if (pExceptionInfo && pExceptionInfo->ContextRecord)
{
GCX_COOP();
+ CONTEXT *pExceptionContext = pExceptionInfo->ContextRecord;
+
#if defined(TARGET_X86) && defined(TARGET_WINDOWS)
// For Windows x86, we don't have a reliable method to unwind to the first managed call frame,
// so we handle at least the cases when the stack overflow happens in JIT helpers
AdjustContextForJITHelpers(pExceptionInfo->ExceptionRecord, pExceptionInfo->ContextRecord);
#else
- Thread::VirtualUnwindToFirstManagedCallFrame(pExceptionInfo->ContextRecord);
+ // There are three possible kinds of locations where the stack overflow can happen:
+ // 1. In managed code
+ // 2. In native code with no explicit frame above the topmost managed frame
+ // 3. In native code with a explicit frame(s) above the topmost managed frame
+ // The FaultingExceptionFrame's context needs to point to the topmost managed code frame except for the case 3.
+ // In that case, it needs to point to the actual frame where the stack overflow happened, otherwise the stack
+ // walker would skip the explicit frame(s) and misbehave.
+ Thread *pThread = GetThreadNULLOk();
+ if (pThread)
+ {
+ // Use the context in the FaultingExceptionFrame as a temporary store for unwinding to the first managed frame
+ CopyOSContext((&fef)->GetExceptionContext(), pExceptionInfo->ContextRecord);
+ Thread::VirtualUnwindToFirstManagedCallFrame((&fef)->GetExceptionContext());
+ if (GetSP((&fef)->GetExceptionContext()) > (TADDR)pThread->GetFrame())
+ {
+ // If the unwind has crossed any explicit frame, use the original exception context.
+ pExceptionContext = pExceptionInfo->ContextRecord;
+ }
+ else
+ {
+ // Otherwise use the first managed frame context.
+ pExceptionContext = (&fef)->GetExceptionContext();
+ }
+ }
#endif
- fef.InitAndLink(pExceptionInfo->ContextRecord);
+ fef.InitAndLink(pExceptionContext);
}
static volatile LONG g_stackOverflowCallStackLogged = 0;