diff --git a/src/coreclr/inc/volatile.h b/src/coreclr/inc/volatile.h index 1c97750496d74d..5c322e9125a9f6 100644 --- a/src/coreclr/inc/volatile.h +++ b/src/coreclr/inc/volatile.h @@ -59,6 +59,8 @@ #include "staticcontract.h" +#include + // // This code is extremely compiler- and CPU-specific, and will need to be altered to // support new compilers and/or CPUs. Here we enforce that we can only compile using @@ -325,6 +327,18 @@ void VolatileLoadBarrier() #endif } +// +// Compiler reordering barrier. Prevents the compiler from moving memory accesses across this +// point. It emits no instructions and provides no CPU or cross-thread ordering; use it only to +// order accesses with respect to asynchronous interruption on the SAME thread, such as a signal +// or hardware-exception handler. +// +inline +void CompilerBarrier() +{ + std::atomic_signal_fence(std::memory_order_acq_rel); +} + // // Volatile implements accesses with our volatile semantics over a variable of type T. // Wherever you would have used a "volatile Foo" or, equivalently, "Foo volatile", use Volatile diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 714f41bfa7a742..4107328b658064 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -3360,7 +3360,11 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr if (!pChildFrame) { pChildFrame = (InterpMethodContextFrame*)alloca(sizeof(InterpMethodContextFrame)); + // We make sure that a new frame can't be seen with invalid ip/next when a stack + // overflow is triggered at a location outside of our control. + pChildFrame->ip = NULL; pChildFrame->pNext = NULL; + CompilerBarrier(); pFrame->pNext = pChildFrame; } pChildFrame->ReInit(pFrame, targetIp, returnValueAddress, LOCAL_VAR_ADDR(callArgsOffset, int8_t)); @@ -3463,7 +3467,11 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr if (!pChildFrame) { pChildFrame = (InterpMethodContextFrame*)alloca(sizeof(InterpMethodContextFrame)); + // We make sure that a new frame can't be seen with invalid ip/next when a stack + // overflow is triggered at a location outside of our control. + pChildFrame->ip = NULL; pChildFrame->pNext = NULL; + CompilerBarrier(); pFrame->pNext = pChildFrame; } pChildFrame->ReInit(pFrame, targetIp, returnValueAddress, callArgsAddress); @@ -4296,7 +4304,11 @@ do \ if (!pChildFrame) { pChildFrame = (InterpMethodContextFrame*)alloca(sizeof(InterpMethodContextFrame)); + // We make sure that a new frame can't be seen with invalid ip/next when a stack + // overflow is triggered at a location outside of our control. + pChildFrame->ip = NULL; pChildFrame->pNext = NULL; + CompilerBarrier(); pFrame->pNext = pChildFrame; } // Set the frame to the same values as the caller frame.