Skip to content
Merged
2 changes: 1 addition & 1 deletion src/coreclr/vm/amd64/cgenamd64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF
SyncRegDisplayToCurrentContext(pRD);

#ifdef FEATURE_INTERPRETER
if ((m_Next != FRAME_TOP) && (m_Next->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame))
if ((m_Next != FRAME_TOP) && (m_Next != NULL) && (m_Next->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame))
{
// If the next frame is an interpreter frame, we also need to set the first argument register to point to the interpreter frame.
SetFirstArgReg(pRD->pCurrentContext, dac_cast<TADDR>(m_Next));
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/amd64/umthunkstub.S
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//
// METHODDESC_REGISTER: UMEntryThunkData*
//
NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix
NESTED_ENTRY TheUMEntryPrestub, _TEXT, NoHandler
Comment thread
janvorli marked this conversation as resolved.
PUSH_ARGUMENT_REGISTERS
// +8 for alignment
alloc_stack (SIZEOF_MAX_FP_ARG_SPILL + 8)
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/arm64/asmhelpers.S
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ LEAF_END ThePreStubPatch, _TEXT
//
// x12 = UMEntryThunkData*
//
NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix
NESTED_ENTRY TheUMEntryPrestub, _TEXT, NoHandler

// Save arguments and return address
PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -224
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/arm64/stubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF
pRD->pCurrentContextPointers->Fp = (DWORD64 *)&m_pCalleeSavedFP;

#ifdef FEATURE_INTERPRETER
if ((m_Next != FRAME_TOP) && (m_Next->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame))
if ((m_Next != FRAME_TOP) && (m_Next != NULL) && (m_Next->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame))
{
// If the next frame is an interpreter frame, we also need to set the first argument register to point to the interpreter frame.
SetFirstArgReg(pRD->pCurrentContext, dac_cast<TADDR>(m_Next));
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/dllimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6016,6 +6016,7 @@ EXTERN_C void* PInvokeImportWorker(PInvokeMethodDesc* pMD)
}
CONTRACTL_END;

INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME(GetThread()->GetFrame());
INSTALL_MANAGED_EXCEPTION_DISPATCHER;
// this function is called by CLR to native assembly stubs which are called by
// managed code as a result, we need an unwind and continue handler to translate
Expand All @@ -6026,6 +6027,7 @@ EXTERN_C void* PInvokeImportWorker(PInvokeMethodDesc* pMD)

UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME;

return pMD->GetPInvokeTarget();
}
Expand Down
36 changes: 1 addition & 35 deletions src/coreclr/vm/eetwain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1917,41 +1917,7 @@ void InterpreterCodeManager::ResumeAfterCatch(CONTEXT *pContext, size_t targetSS
{
TADDR resumeSP = GetSP(pContext);
TADDR resumeIP = GetIP(pContext);
#ifdef TARGET_WASM
throw ResumeAfterCatchException(resumeSP, resumeIP);
#else
Thread *pThread = GetThread();
InterpreterFrame * pInterpreterFrame = (InterpreterFrame*)pThread->GetFrame();

ClrCaptureContext(pContext);

TADDR targetSP = pInterpreterFrame->GetInterpExecMethodSP();

// We are resuming in interpreter frame. So we need to skip all native, JIT and AOT generated frames until we reach
// the resumeSP
do
{
if (ExecutionManager::IsManagedCode(GetIP(pContext)))
{
// JIT / AOT generated managed code
Thread::VirtualUnwindCallFrame(pContext);
}
else
{
#ifdef TARGET_UNIX
PAL_VirtualUnwind(pContext);
#else
Thread::VirtualUnwindCallFrame(pContext);
#endif
}
}
while (GetSP(pContext) != targetSP);

#if defined(HOST_AMD64) && defined(HOST_WINDOWS)
targetSSP = pInterpreterFrame->GetInterpExecMethodSSP();
#endif
ExecuteFunctionBelowContext((PCODE)ThrowResumeAfterCatchException, pContext, targetSSP, resumeSP, resumeIP);
#endif // TARGET_WASM
ThrowResumeAfterCatchException(resumeSP, resumeIP);
}

#if defined(HOST_AMD64) && defined(HOST_WINDOWS)
Expand Down
46 changes: 9 additions & 37 deletions src/coreclr/vm/excep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2127,10 +2127,10 @@ VOID DECLSPEC_NORETURN __fastcall PropagateExceptionThroughNativeFrames(Object *
}
CONTRACTL_END;

#ifdef TARGET_WASM
// On WASM, the exception needs to keep propagating until it reaches the target frame. On other platforms,
// this is ensured by unwinding stack up to the target frame before propagating the exception. This
// difference is due to the fact that on WASM we don't have native stack unwinding support.
#ifdef TARGET_WASM
struct Param
{
Object *exceptionObj;
Expand Down Expand Up @@ -5610,6 +5610,13 @@ void HandleManagedFault(EXCEPTION_RECORD* pExceptionRecord, CONTEXT* pContext)
}
}

#if defined(HOST_WINDOWS) && defined(HOST_AMD64)
TADDR ssp = GetSSP(pContext);
#else
TADDR ssp = 0;
#endif

INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT(fef.GetExceptionContext(), ssp);
// m_exception is GC-reported via ExInfo chain scanning in ScanStackRoots.
// Do NOT also GCPROTECT it - reporting the same location twice corrupts
// the GC's relocation logic (see clr-code-guide.md §2.1.5).
Expand All @@ -5621,6 +5628,7 @@ void HandleManagedFault(EXCEPTION_RECORD* pExceptionRecord, CONTEXT* pContext)
throwHwEx.InvokeDirect(exceptionCode, &exInfo);

DispatchExSecondPass(&exInfo);
UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT;

UNREACHABLE();
}
Expand Down Expand Up @@ -6687,48 +6695,12 @@ VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFra
}
}

#if defined(HOST_AMD64) && defined(HOST_WINDOWS)
size_t GetSSPForFrameOnCurrentStack(TADDR ip);
#endif // HOST_AMD64 && HOST_WINDOWS

#ifdef FEATURE_INTERPRETER
void ThrowResumeAfterCatchException(TADDR resumeSP, TADDR resumeIP)
{
throw ResumeAfterCatchException(resumeSP, resumeIP);
}

VOID DECLSPEC_NORETURN UnwindAndContinueResumeAfterCatch(TADDR resumeSP, TADDR resumeIP)
{
STATIC_CONTRACT_NOTHROW;
STATIC_CONTRACT_GC_TRIGGERS;
STATIC_CONTRACT_MODE_ANY;

CONTEXT context;
ClrCaptureContext(&context);

// Unwind to the caller of the Ex.RhThrowEx / Ex.RhThrowHwEx
Thread::VirtualUnwindToFirstManagedCallFrame(&context);

#if defined(HOST_AMD64) && defined(HOST_WINDOWS)
size_t targetSSP = GetSSPForFrameOnCurrentStack(GetIP(&context));
#else
size_t targetSSP = 0;
#endif

// Skip all managed frames upto a native frame
while (ExecutionManager::IsManagedCode(GetIP(&context)))
{
Thread::VirtualUnwindCallFrame(&context);
#if defined(HOST_AMD64) && defined(HOST_WINDOWS)
if (targetSSP != 0)
{
targetSSP += sizeof(size_t);
}
#endif
}

ExecuteFunctionBelowContext((PCODE)ThrowResumeAfterCatchException, &context, targetSSP, resumeSP, resumeIP);
}
#endif // FEATURE_INTERPRETER

thread_local DWORD t_dwCurrentExceptionCode;
Expand Down
92 changes: 92 additions & 0 deletions src/coreclr/vm/exceptionhandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,8 +653,20 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord,
#endif
else
{
void *sp = (void*)GetSP(pContextRecord);
PopExplicitFrames(pThread, sp, NULL /* targetCallerSp */, false /* popGCFrames */);
ExInfo::PopExInfos(pThread, sp);
Comment thread
janvorli marked this conversation as resolved.

#if defined(HOST_WINDOWS) && defined(HOST_AMD64)
TADDR ssp = GetSSP(pContextRecord);
#else
TADDR ssp = 0;
#endif

OBJECTREF oref = ExInfo::CreateThrowable(pExceptionRecord, FALSE);
INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT(pContextRecord, ssp);
DispatchManagedException(oref, pContextRecord, pExceptionRecord);
UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT;
}
#endif // !HOST_UNIX

Expand Down Expand Up @@ -1447,6 +1459,7 @@ BOOL HandleHardwareException(PAL_SEHException* ex)
exInfo.TakeExceptionPointersOwnership(ex);
}

INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT(fef.GetExceptionContext(), 0 /* SSP - no SSP support on Unix */);
// m_exception is GC-reported via ExInfo chain scanning in ScanStackRoots.
// Do NOT also GCPROTECT it - reporting the same location twice corrupts
// the GC's relocation logic (see clr-code-guide.md §2.1.5).
Expand All @@ -1458,6 +1471,7 @@ BOOL HandleHardwareException(PAL_SEHException* ex)
throwHwEx.InvokeDirect(exceptionCode, &exInfo);

DispatchExSecondPass(&exInfo);
UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT;

UNREACHABLE();
}
Expand Down Expand Up @@ -1507,6 +1521,83 @@ BOOL HandleHardwareException(PAL_SEHException* ex)

#endif // TARGET_UNIX

#if defined(FEATURE_INTERPRETER) && !defined(HOST_WASM)

// The ssp argument needs to match the pContext (SSP register value at that context)
VOID DECLSPEC_NORETURN RethrowResumeAfterCatchExceptionSkipManagedFrames(const ResumeAfterCatchException& ex, CONTEXT *pContext, TADDR ssp)
{
#if defined(HOST_AMD64) && defined(HOST_WINDOWS)
// Find precise SSP value. We cannot use the instruction pointer from the context here because for PInvoke frames it points to the return address
// of the JIT_PInvokeBegin call that is called before the actual target function.
if (ssp != 0)
{
while (!ExecutionManager::IsManagedCode(*(PCODE*)(ssp - 8)))
{
ssp += 8;
}
}
#endif

while (ExecutionManager::IsManagedCode(GetIP(pContext)))
{
Thread::VirtualUnwindCallFrame(pContext);
#if defined(HOST_AMD64) && defined(HOST_WINDOWS)
if (ssp != 0)
{
ssp += 8;
}
#endif
}

TADDR resumeSP;
TADDR resumeIP;
ex.GetResumeContext(&resumeSP, &resumeIP);
_ASSERTE(resumeSP != 0 && resumeIP != 0);

ExecuteFunctionBelowContext((PCODE)ThrowResumeAfterCatchException, pContext, ssp, resumeSP, resumeIP);
}

// The ssp argument is approximate (it can be the SSP value of several frames below the context extracted from the pFrame)
VOID DECLSPEC_NORETURN RethrowResumeAfterCatchException(const ResumeAfterCatchException& ex, Frame *pFrame, TADDR ssp)
{
// The frame should have been popped already
_ASSERTE(pFrame->PtrNextFrame() == NULL);

EECodeInfo codeInfo(pFrame->GetReturnAddress());

if (!codeInfo.IsValid() || codeInfo.IsInterpretedCode())
{
// Native caller - interpreter stubs or PInvoke called from the interpreted code
throw ex;
}

REGDISPLAY rd = {};
T_CONTEXT context = {};
#if (defined(HOST_WINDOWS) && defined(HOST_AMD64)) || defined(TARGET_ARM64)
constexpr BOOL updateFloats = TRUE;
context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;
RtlCaptureContext(&context);
#else
constexpr BOOL updateFloats = FALSE;
context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
#endif

FillRegDisplay(&rd, &context);
pFrame->UpdateRegDisplay(&rd, updateFloats);

#if defined(HOST_WINDOWS) && defined(HOST_AMD64)
// Initialize FP control/status so that the context can be used for resuming execution
rd.pCurrentContext->FltSave.ControlWord = 0x27F; // Default x87 control word
rd.pCurrentContext->FltSave.MxCsr = 0x1F80; // Default MXCSR value (all exceptions masked)
rd.pCurrentContext->FltSave.MxCsr_Mask = 0x1FFF; // MXCSR mask
rd.pCurrentContext->MxCsr = 0x1F80; // Default MXCSR value (all exceptions masked)
#endif // HOST_WINDOWS && HOST_AMD64

RethrowResumeAfterCatchExceptionSkipManagedFrames(ex, rd.pCurrentContext, ssp);
}

#endif // FEATURE_INTERPRETER && !HOST_WASM

void FirstChanceExceptionNotification()
{
#ifdef TARGET_WINDOWS
Expand Down Expand Up @@ -3000,6 +3091,7 @@ void ExecuteFunctionBelowContext(PCODE functionPtr, CONTEXT *pContext, size_t ta
if (targetSSP != 0)
{
targetSSP -= sizeof(size_t);
_ASSERTE(*(ULONG64*)targetSSP == pContext->Rip);
}
#endif // HOST_WINDOWS
SetSP(pContext, targetSp - 8);
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/vm/exceptionhandling.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ class ResumeAfterCatchException
*pResumeIP = m_resumeIP;
}
};

#ifndef HOST_WASM
VOID DECLSPEC_NORETURN RethrowResumeAfterCatchExceptionSkipManagedFrames(const ResumeAfterCatchException& ex, CONTEXT *pContext, TADDR ssp);
#endif // HOST_WASM

#endif // FEATURE_INTERPRETER

void DECLSPEC_NORETURN ExecuteFunctionBelowContext(PCODE functionPtr, CONTEXT *pContext, size_t targetSSP, size_t arg1 = 0, size_t arg2 = 0);
Expand Down
65 changes: 63 additions & 2 deletions src/coreclr/vm/exceptmacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,69 @@ void UnwindAndContinueRethrowHelperInsideCatch(Frame* pEntryFrame, Exception* pE
VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFrame, Exception* pException, bool nativeRethrow);

#ifdef FEATURE_INTERPRETER
VOID DECLSPEC_NORETURN UnwindAndContinueResumeAfterCatch(TADDR resumeSP, TADDR resumeIP);
#endif // FEATURE_INTERPRETER
class ResumeAfterCatchException;
#endif
Comment thread
janvorli marked this conversation as resolved.

#if defined(FEATURE_INTERPRETER) && !defined(HOST_WASM)
Comment thread
janvorli marked this conversation as resolved.
VOID DECLSPEC_NORETURN RethrowResumeAfterCatchException(const ResumeAfterCatchException& ex, Frame *pFrame, TADDR ssp);

#if defined(HOST_AMD64) && defined(HOST_WINDOWS)
#define READ_SSP() _rdsspq()
#else
#define READ_SSP() 0
#endif

// Install / uninstall handler at a native to managed code boundary.

#define INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT(pContext, ssp) \
CONTEXT *__pResumeAfterCatchContext = pContext; \
TADDR __pResumeAfterCatchSSP = ssp; \
TADDR __resumeSP = 0, __resumeIP = 0; \
try \
{

#define INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME(pFrame) \
Frame *__pResumeAfterCatchFrame = pFrame; \
TADDR __pResumeAfterCatchSSP = READ_SSP(); \
TADDR __resumeSP = 0, __resumeIP = 0; \
try \
{

#define UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT \
} \
catch (const ResumeAfterCatchException& ex) \
{ \
/* We don't rethrow the exception here to work around a Windows bug in shadow stack pointer updating */ \
Comment thread
janvorli marked this conversation as resolved.
/* tracked by (internal) OS issue: https://microsoft.visualstudio.com/OS/_workitems/edit/62622295 */ \
ex.GetResumeContext(&__resumeSP, &__resumeIP); \
} \
if (__resumeSP != 0) \
{ \
ResumeAfterCatchException ex(__resumeSP, __resumeIP); \
RethrowResumeAfterCatchExceptionSkipManagedFrames(ex, __pResumeAfterCatchContext, __pResumeAfterCatchSSP); \
}


#define UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME \
} \
catch (const ResumeAfterCatchException& ex) \
{ \
/* We don't rethrow the exception here to work around a Windows bug in shadow stack pointer updating */ \
/* tracked by (internal) OS issue: https://microsoft.visualstudio.com/OS/_workitems/edit/62622295 */ \
ex.GetResumeContext(&__resumeSP, &__resumeIP); \
} \
if (__resumeSP != 0) \
{ \
ResumeAfterCatchException ex(__resumeSP, __resumeIP); \
RethrowResumeAfterCatchException(ex, __pResumeAfterCatchFrame, __pResumeAfterCatchSSP); \
}

#else // FEATURE_INTERPRETER && !HOST_WASM
#define INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME(pFrame)
#define INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT(pContext, ssp)
#define UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME
#define UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT
#endif // FEATURE_INTERPRETER && !HOST_WASM

#ifdef TARGET_UNIX
VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHardwareException);
Expand Down
Loading
Loading