diff --git a/src/coreclr/vm/amd64/cgenamd64.cpp b/src/coreclr/vm/amd64/cgenamd64.cpp index 70ebf04fa7fc1c..e8380e10983f34 100644 --- a/src/coreclr/vm/amd64/cgenamd64.cpp +++ b/src/coreclr/vm/amd64/cgenamd64.cpp @@ -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(m_Next)); diff --git a/src/coreclr/vm/amd64/umthunkstub.S b/src/coreclr/vm/amd64/umthunkstub.S index 8855d710570993..c0f5112be65b82 100644 --- a/src/coreclr/vm/amd64/umthunkstub.S +++ b/src/coreclr/vm/amd64/umthunkstub.S @@ -8,7 +8,7 @@ // // METHODDESC_REGISTER: UMEntryThunkData* // -NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix +NESTED_ENTRY TheUMEntryPrestub, _TEXT, NoHandler PUSH_ARGUMENT_REGISTERS // +8 for alignment alloc_stack (SIZEOF_MAX_FP_ARG_SPILL + 8) diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index 880849df5c4564..3ce76b008fd4e3 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -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 diff --git a/src/coreclr/vm/arm64/stubs.cpp b/src/coreclr/vm/arm64/stubs.cpp index ba9a29ff4bcde5..9ee0c4b42377d4 100644 --- a/src/coreclr/vm/arm64/stubs.cpp +++ b/src/coreclr/vm/arm64/stubs.cpp @@ -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(m_Next)); diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 830cc01e966fa1..99b56382bdf81e 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -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 @@ -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(); } diff --git a/src/coreclr/vm/eetwain.cpp b/src/coreclr/vm/eetwain.cpp index db4bdd840d94e4..3abcf070a6a349 100644 --- a/src/coreclr/vm/eetwain.cpp +++ b/src/coreclr/vm/eetwain.cpp @@ -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) diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index f3084898048f9c..279cb3e85871a8 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -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; @@ -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). @@ -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(); } @@ -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; diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index f6d79b4e79062b..90f3d4a5e5edb9 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -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); + +#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 @@ -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). @@ -1458,6 +1471,7 @@ BOOL HandleHardwareException(PAL_SEHException* ex) throwHwEx.InvokeDirect(exceptionCode, &exInfo); DispatchExSecondPass(&exInfo); + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT; UNREACHABLE(); } @@ -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 @@ -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); diff --git a/src/coreclr/vm/exceptionhandling.h b/src/coreclr/vm/exceptionhandling.h index f060df53dd53d4..1c8d72f03785ce 100644 --- a/src/coreclr/vm/exceptionhandling.h +++ b/src/coreclr/vm/exceptionhandling.h @@ -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); diff --git a/src/coreclr/vm/exceptmacros.h b/src/coreclr/vm/exceptmacros.h index c72b673c898ad5..7fea6c62f1ecc9 100644 --- a/src/coreclr/vm/exceptmacros.h +++ b/src/coreclr/vm/exceptmacros.h @@ -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 + +#if defined(FEATURE_INTERPRETER) && !defined(HOST_WASM) +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 */ \ + /* 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); diff --git a/src/coreclr/vm/frames.cpp b/src/coreclr/vm/frames.cpp index 53ddec159d3714..c69962bdb05509 100644 --- a/src/coreclr/vm/frames.cpp +++ b/src/coreclr/vm/frames.cpp @@ -687,7 +687,7 @@ void InlinedCallFrame::UpdateFloatingPointRegisters_Impl(const PREGDISPLAY pRD, if (IsInInterpreter()) { InterpreterFrame *pInterpreterFrame = (InterpreterFrame *)m_Next; - pInterpreterFrame->UpdateFloatingPointRegisters(pRD, pInterpreterFrame->GetInterpExecMethodSP()); + pInterpreterFrame->UpdateFloatingPointRegisters(pRD, 0 /* unused for interpreter frame*/); pInterpreterFrame->SetContextToInterpMethodContextFrame(pRD->pCurrentContext); return; } @@ -713,7 +713,7 @@ void InlinedCallFrame::UpdateFloatingPointRegisters_Impl(const PREGDISPLAY pRD, BOOL InlinedCallFrame::IsInInterpreter() { PTR_InterpreterFrame pInterpreterFrame = NULL; - if ((m_Next != FRAME_TOP) && (m_Next->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame)) + if ((m_Next != FRAME_TOP) && (m_Next != NULL) && (m_Next->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame)) { PTR_InterpreterFrame pInterpreterFrame = (PTR_InterpreterFrame)m_Next; // The interpreter frame is in the interpreter when its top method context frame matches the m_pCallSiteSP diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index f3661289e2e352..a88cf0b0387f3d 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -2427,20 +2427,6 @@ class InterpreterFrame : public FramedMethodFrame } #endif // HOST_AMD64 && HOST_WINDOWS -#ifndef TARGET_WASM - void SetInterpExecMethodSP(TADDR sp) - { - LIMITED_METHOD_CONTRACT; - m_SP = sp; - } - - TADDR GetInterpExecMethodSP() - { - LIMITED_METHOD_CONTRACT; - return m_SP; - } -#endif // TARGET_WASM - void SetIsFaulting(bool isFaulting) { LIMITED_METHOD_CONTRACT; @@ -2485,9 +2471,6 @@ class InterpreterFrame : public FramedMethodFrame // Saved SSP of the InterpExecMethod for resuming after catch into interpreter frames. TADDR m_SSP; #endif // HOST_AMD64 && HOST_WINDOWS -#ifndef TARGET_WASM - TADDR m_SP; -#endif // TARGET_WASM PTR_Object m_continuation; friend struct cdac_data; diff --git a/src/coreclr/vm/gchelpers.cpp b/src/coreclr/vm/gchelpers.cpp index c9e3020948fe3e..ba24ad29f6c5bd 100644 --- a/src/coreclr/vm/gchelpers.cpp +++ b/src/coreclr/vm/gchelpers.cpp @@ -180,6 +180,7 @@ EXTERN_C void RhExceptionHandling_FailedAllocation_Helper(MethodTable* pMT, bool pFrame->Push(CURRENT_THREAD); + INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME(&frame); INSTALL_MANAGED_EXCEPTION_DISPATCHER; INSTALL_UNWIND_AND_CONTINUE_HANDLER; @@ -191,6 +192,7 @@ EXTERN_C void RhExceptionHandling_FailedAllocation_Helper(MethodTable* pMT, bool UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME; pFrame->Pop(CURRENT_THREAD); } diff --git a/src/coreclr/vm/i386/umthunkstub.S b/src/coreclr/vm/i386/umthunkstub.S index 6dc63a7702530b..8130537c465aff 100644 --- a/src/coreclr/vm/i386/umthunkstub.S +++ b/src/coreclr/vm/i386/umthunkstub.S @@ -8,7 +8,7 @@ // // eax = UMEntryThunkData* // -NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix +NESTED_ENTRY TheUMEntryPrestub, _TEXT, NoHandler #define STK_ALIGN_PADDING 8 sub esp, STK_ALIGN_PADDING push eax // UMEntryThunkData* diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 4ef4ad40c9617f..accba2e4dcd272 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -194,14 +194,6 @@ static size_t CreateDispatchTokenForMethod(MethodDesc* pMD) } } -#ifdef TARGET_WASM -// Unused on WASM -#define SAVE_THE_LOWEST_SP do {} while (0) -#else -// Save the lowest SP in the current method so that we can identify it by that during stackwalk -#define SAVE_THE_LOWEST_SP pInterpreterFrame->SetInterpExecMethodSP((TADDR)GetCurrentSP()) -#endif // !TARGET_WASM - // Call invoker helpers provided by platform. void InvokeManagedMethod(ManagedMethodParam *pParam); void InvokeUnmanagedMethod(MethodDesc *targetMethod, int8_t *pArgs, int8_t *pRet, PCODE callTarget); @@ -1333,6 +1325,9 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr } CONTRACTL_END; + TADDR resumeSP = 0; + TADDR resumeIP = 0; + #if defined(HOST_AMD64) && defined(HOST_WINDOWS) pInterpreterFrame->SetInterpExecMethodSSP((TADDR)_rdsspq()); #endif // HOST_AMD64 && HOST_WINDOWS @@ -1382,8 +1377,6 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr MethodDesc* targetMethod; uint32_t opcode; - SAVE_THE_LOWEST_SP; - MAIN_LOOP: try { @@ -3342,7 +3335,6 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr pChildFrame = (InterpMethodContextFrame*)alloca(sizeof(InterpMethodContextFrame)); pChildFrame->pNext = NULL; pFrame->pNext = pChildFrame; - SAVE_THE_LOWEST_SP; } pChildFrame->ReInit(pFrame, targetIp, returnValueAddress, LOCAL_VAR_ADDR(callArgsOffset, int8_t)); pFrame = pChildFrame; @@ -3443,7 +3435,6 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr pChildFrame = (InterpMethodContextFrame*)alloca(sizeof(InterpMethodContextFrame)); pChildFrame->pNext = NULL; pFrame->pNext = pChildFrame; - SAVE_THE_LOWEST_SP; } pChildFrame->ReInit(pFrame, targetIp, returnValueAddress, callArgsAddress); pFrame = pChildFrame; @@ -4277,7 +4268,6 @@ do \ pChildFrame = (InterpMethodContextFrame*)alloca(sizeof(InterpMethodContextFrame)); pChildFrame->pNext = NULL; pFrame->pNext = pChildFrame; - SAVE_THE_LOWEST_SP; } // Set the frame to the same values as the caller frame. pChildFrame->ReInit(pFrame, pFrame->startIp, pFrame->pRetVal, pFrame->pStack); @@ -4637,8 +4627,7 @@ do \ } catch (const ResumeAfterCatchException& ex) { - TADDR resumeSP; - TADDR resumeIP; + GCX_COOP_NO_DTOR(); ex.GetResumeContext(&resumeSP, &resumeIP); _ASSERTE(resumeSP != 0 && resumeIP != 0); @@ -4652,7 +4641,9 @@ do \ // sequences of interpreted frames without any AOTed/JITted frames in between. In such case, the topmost native frame // the ResumeAfterCatchException is thrown from may not be the one that corresponds to the target interpreted frame. // Thus, we need to rethrow it to let it propagate further. - throw; + // 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 + goto RETHROW_RESUME_AFTER_CATCH; } pThreadContext->frameDataAllocator.PopInfo(pFrame); pFrame->ip = 0; @@ -4704,6 +4695,11 @@ do \ } pThreadContext->pStackPointer = pFrame->pStack; + return; + +RETHROW_RESUME_AFTER_CATCH: + // Rethrow the exception to let it propagate to the correct resume frame + ThrowResumeAfterCatchException(resumeSP, resumeIP); } #endif // FEATURE_INTERPRETER diff --git a/src/coreclr/vm/interpexec.h b/src/coreclr/vm/interpexec.h index 1192ddadf0cdbe..0fca7879b73189 100644 --- a/src/coreclr/vm/interpexec.h +++ b/src/coreclr/vm/interpexec.h @@ -119,7 +119,6 @@ extern "C" void ExecuteInterpretedMethodFromUnmanaged(MethodDesc* pMD, int8_t* a CallStubHeader *CreateNativeToInterpreterCallStub(InterpMethod* pInterpMethod); // Arguments are bundled in a struct to force register passing on ARM32. -// This ensures the current SP value saved by the SAVE_THE_LOWEST_SP into the InterpreterFrame precisely matches the SP that stack walking reports for the InterpExecMethod. // Passing arguments on stack on ARM32 would result in reporting SP after the arguments were pushed, which is different. struct ManagedMethodParam { diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index a71a92fc5519e4..95bcbefb4dbfea 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -802,7 +802,9 @@ EXTERN_C HCIMPL2(void, IL_Throw_Impl, Object* obj, TransitionBlock* transitionB DispatchManagedException(kNullReferenceException); NormalizeThrownObject(&oref); + INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT(exceptionFrame.GetContext(), READ_SSP()); DispatchManagedException(oref, exceptionFrame.GetContext()); + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT; FC_CAN_TRIGGER_GC_END(); UNREACHABLE(); @@ -830,7 +832,9 @@ EXTERN_C HCIMPL1(void, IL_Rethrow_Impl, TransitionBlock* transitionBlock) FC_CAN_TRIGGER_GC(); + INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT(exceptionFrame.GetContext(), READ_SSP()); DispatchRethrownManagedException(exceptionFrame.GetContext()); + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT; FC_CAN_TRIGGER_GC_END(); UNREACHABLE(); @@ -862,7 +866,9 @@ EXTERN_C HCIMPL2(void, IL_ThrowExact_Impl, Object* obj, TransitionBlock* transi FC_CAN_TRIGGER_GC(); + INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT(exceptionFrame.GetContext(), READ_SSP()); DispatchManagedException(oref, exceptionFrame.GetContext(), NULL, ExKind::RethrowFlag); + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT; FC_CAN_TRIGGER_GC_END(); UNREACHABLE(); diff --git a/src/coreclr/vm/loongarch64/asmhelpers.S b/src/coreclr/vm/loongarch64/asmhelpers.S index 8b4b4736a629c1..c4dce79a61fbde 100644 --- a/src/coreclr/vm/loongarch64/asmhelpers.S +++ b/src/coreclr/vm/loongarch64/asmhelpers.S @@ -435,7 +435,7 @@ NESTED_END StubDispatchFixupStub, _TEXT // // $t2 = UMEntryThunkData* // -NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix +NESTED_ENTRY TheUMEntryPrestub, _TEXT, NoHandler // Save arguments and return address // $fp,$ra diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index d4220ae0185414..086c8bc50ab6d9 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -1876,6 +1876,7 @@ extern "C" PCODE STDCALL PreStubWorker(TransitionBlock* pTransitionBlock, Method { bool propagateExceptionToNativeCode = IsCallDescrWorkerInternalReturnAddress(pTransitionBlock->m_ReturnAddress); + INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME(&frame); INSTALL_MANAGED_EXCEPTION_DISPATCHER_EX; INSTALL_UNWIND_AND_CONTINUE_HANDLER_EX; @@ -1930,12 +1931,16 @@ extern "C" PCODE STDCALL PreStubWorker(TransitionBlock* pTransitionBlock, Method UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_EX(propagateExceptionToNativeCode); UNINSTALL_MANAGED_EXCEPTION_DISPATCHER_EX(propagateExceptionToNativeCode); + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME; } EX_CATCH { OBJECTHANDLE ohThrowable = CURRENT_THREAD->LastThrownObjectHandle(); - _ASSERTE(ohThrowable); - StackTraceInfo::AppendElement(ObjectFromHandle(ohThrowable), 0, (UINT_PTR)pTransitionBlock, pMD, NULL); + // ohThrowable can be NULL when we've caught the ResumeAfterCatchException + if (ohThrowable != NULL) + { + StackTraceInfo::AppendElement(ObjectFromHandle(ohThrowable), 0, (UINT_PTR)pTransitionBlock, pMD, NULL); + } EX_RETHROW; } EX_END_CATCH @@ -2038,23 +2043,25 @@ extern "C" void* STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBl frames.interpMethodContextFrame.pStack = sp; frames.interpMethodContextFrame.pRetVal = (retBuff != NULL) ? (int8_t*)retBuff : sp; + INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME(&frames.interpreterFrame); InterpExecMethod(&frames.interpreterFrame, &frames.interpMethodContextFrame, threadContext); + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME; ArgumentRegisters *pArgumentRegisters = (ArgumentRegisters*)(((uint8_t*)pTransitionBlock) + TransitionBlock::GetOffsetOfArgumentRegisters()); - #if defined(TARGET_AMD64) +#if defined(TARGET_AMD64) pArgumentRegisters->RCX = (INT_PTR)*frames.interpreterFrame.GetContinuationPtr(); - #elif defined(TARGET_ARM64) +#elif defined(TARGET_ARM64) pArgumentRegisters->x[2] = (INT64)*frames.interpreterFrame.GetContinuationPtr(); - #elif defined(TARGET_ARM) +#elif defined(TARGET_ARM) pArgumentRegisters->r[2] = (INT64)*frames.interpreterFrame.GetContinuationPtr(); - #elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) +#elif defined(TARGET_RISCV64) || defined(TARGET_LOONGARCH64) pArgumentRegisters->a[2] = (INT64)*frames.interpreterFrame.GetContinuationPtr(); - #elif defined(TARGET_WASM) +#elif defined(TARGET_WASM) // We do not yet have an ABI for WebAssembly native code to handle here. - #else +#else #error Unsupported architecture - #endif +#endif frames.interpreterFrame.Pop(); diff --git a/src/coreclr/vm/qcall.h b/src/coreclr/vm/qcall.h index 079f93780d40df..a64bf4a2d7836c 100644 --- a/src/coreclr/vm/qcall.h +++ b/src/coreclr/vm/qcall.h @@ -110,12 +110,14 @@ #endif // !TARGET_UNIX #define BEGIN_QCALL \ + INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME(GetThread()->GetFrame()) \ INSTALL_MANAGED_EXCEPTION_DISPATCHER \ INSTALL_UNWIND_AND_CONTINUE_HANDLER #define END_QCALL \ UNINSTALL_UNWIND_AND_CONTINUE_HANDLER \ - UNINSTALL_MANAGED_EXCEPTION_DISPATCHER + UNINSTALL_MANAGED_EXCEPTION_DISPATCHER \ + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME #define QCALL_CHECK \ THROWS; \ diff --git a/src/coreclr/vm/riscv64/asmhelpers.S b/src/coreclr/vm/riscv64/asmhelpers.S index c180a1e2e4a2c5..32614d1d2b74dc 100644 --- a/src/coreclr/vm/riscv64/asmhelpers.S +++ b/src/coreclr/vm/riscv64/asmhelpers.S @@ -315,7 +315,7 @@ C_FUNC(ThePreStubPatchLabel): ret LEAF_END ThePreStubPatch, _TEXT -NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix +NESTED_ENTRY TheUMEntryPrestub, _TEXT, NoHandler // Save arguments and return address PROLOG_SAVE_REG_PAIR_INDEXED fp, ra, 0xa0 //PROLOG_SAVE_REG gp, 16 diff --git a/src/coreclr/vm/virtualcallstub.cpp b/src/coreclr/vm/virtualcallstub.cpp index e4e616315e9e3f..5fac2f4750a58f 100644 --- a/src/coreclr/vm/virtualcallstub.cpp +++ b/src/coreclr/vm/virtualcallstub.cpp @@ -1621,11 +1621,13 @@ PCODE VSD_ResolveWorker(TransitionBlock * pTransitionBlock, if (pObj == NULL) { pSDFrame->SetForNullReferenceException(); pSDFrame->Push(CURRENT_THREAD); + INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME(pSDFrame); INSTALL_MANAGED_EXCEPTION_DISPATCHER_EX; INSTALL_UNWIND_AND_CONTINUE_HANDLER_EX; COMPlusThrow(kNullReferenceException); UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_EX(propagateExceptionToNativeCode); UNINSTALL_MANAGED_EXCEPTION_DISPATCHER_EX(propagateExceptionToNativeCode); + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME; _ASSERTE(!"Throw returned"); } @@ -1661,6 +1663,7 @@ PCODE VSD_ResolveWorker(TransitionBlock * pTransitionBlock, pSDFrame->SetRepresentativeSlot(pRepresentativeMT, representativeToken.GetSlotNumber()); pSDFrame->Push(CURRENT_THREAD); + INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME(pSDFrame); INSTALL_MANAGED_EXCEPTION_DISPATCHER_EX; INSTALL_UNWIND_AND_CONTINUE_HANDLER_EX; @@ -1700,6 +1703,8 @@ PCODE VSD_ResolveWorker(TransitionBlock * pTransitionBlock, UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_EX(propagateExceptionToNativeCode); UNINSTALL_MANAGED_EXCEPTION_DISPATCHER_EX(propagateExceptionToNativeCode); + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME; + pSDFrame->Pop(CURRENT_THREAD); return target; @@ -1747,6 +1752,7 @@ PCODE VSD_ResolveWorkerForInterfaceLookupSlot(TransitionBlock * pTransitionBlock pSDFrame->Push(CURRENT_THREAD); + INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME(pSDFrame); INSTALL_MANAGED_EXCEPTION_DISPATCHER_EX; INSTALL_UNWIND_AND_CONTINUE_HANDLER_EX; @@ -1785,6 +1791,8 @@ PCODE VSD_ResolveWorkerForInterfaceLookupSlot(TransitionBlock * pTransitionBlock UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_EX(propagateExceptionToNativeCode); UNINSTALL_MANAGED_EXCEPTION_DISPATCHER_EX(propagateExceptionToNativeCode); + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME; + pSDFrame->Pop(CURRENT_THREAD); return target; diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp index 848d708f27bf0c..fe0ffe3d05c561 100644 --- a/src/coreclr/vm/wasm/helpers.cpp +++ b/src/coreclr/vm/wasm/helpers.cpp @@ -462,7 +462,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(m_Next));