From 909e4a6636ffe8d52fa1e1e40ee14c778d19ce0d Mon Sep 17 00:00:00 2001 From: Manish Godse <61718172+mangod9@users.noreply.github.com> Date: Fri, 28 Mar 2025 09:37:21 -0700 Subject: [PATCH 1/4] remove the switch to fallback to old EH --- .../debug/daccess/dacdbiimplstackwalk.cpp | 6 +- src/coreclr/debug/ee/debugger.cpp | 15 +- src/coreclr/inc/clrconfigvalues.h | 1 - src/coreclr/inc/dacvars.h | 1 - src/coreclr/vm/clrex.cpp | 10 - src/coreclr/vm/debugdebugger.cpp | 2 +- src/coreclr/vm/excep.cpp | 16 +- src/coreclr/vm/excep.h | 9 +- src/coreclr/vm/exceptionhandling.cpp | 1081 ++--------------- src/coreclr/vm/fcall.cpp | 6 +- src/coreclr/vm/fcall.h | 6 +- src/coreclr/vm/jithelpers.cpp | 99 +- src/coreclr/vm/prestub.cpp | 9 +- src/coreclr/vm/proftoeeinterfaceimpl.cpp | 2 +- src/coreclr/vm/stackwalk.cpp | 111 +- src/coreclr/vm/threadsuspend.cpp | 27 +- src/coreclr/vm/vars.cpp | 1 - src/coreclr/vm/vars.hpp | 1 - 18 files changed, 178 insertions(+), 1225 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp index 90158d237ba5a9..645ecd0baa84d5 100644 --- a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp +++ b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp @@ -262,7 +262,7 @@ BOOL DacDbiInterfaceImpl::UnwindStackWalkFrame(StackWalkHandle pSFIHandle) continue; } #ifdef FEATURE_EH_FUNCLETS - else if (g_isNewExceptionHandlingEnabled && pIter->GetFrameState() == StackFrameIterator::SFITER_FRAMELESS_METHOD) + else if (pIter->GetFrameState() == StackFrameIterator::SFITER_FRAMELESS_METHOD) { // Skip the new exception handling managed code, the debugger clients are not supposed to see them MethodDesc *pMD = pIter->m_crawl.GetFunction(); @@ -462,7 +462,7 @@ ULONG32 DacDbiInterfaceImpl::GetCountOfInternalFrames(VMPTR_Thread vmThread) while (pFrame != FRAME_TOP) { #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled && InlinedCallFrame::FrameHasActiveCall(pFrame)) + if (InlinedCallFrame::FrameHasActiveCall(pFrame)) { // Skip new exception handling helpers InlinedCallFrame *pInlinedCallFrame = dac_cast(pFrame); @@ -515,7 +515,7 @@ void DacDbiInterfaceImpl::EnumerateInternalFrames(VMPTR_Thread while (pFrame != FRAME_TOP) { #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled && InlinedCallFrame::FrameHasActiveCall(pFrame)) + if (InlinedCallFrame::FrameHasActiveCall(pFrame)) { // Skip new exception handling helpers InlinedCallFrame *pInlinedCallFrame = dac_cast(pFrame); diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index 0345218e861b45..fe9cb0f022d364 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -11582,19 +11582,8 @@ HRESULT Debugger::GetAndSendInterceptCommand(DebuggerIPCEvent *event) // Set up the VM side of intercepting. // StackFrame sfInterceptFramePointer; - if (g_isNewExceptionHandlingEnabled) - { - sfInterceptFramePointer = StackFrame::FromRegDisplay(&(csi.m_activeFrame.registers)); - } - else - { -#if defined (TARGET_ARM )|| defined (TARGET_ARM64 ) - // ARM requires the caller stack pointer, not the current stack pointer - sfInterceptFramePointer = CallerStackFrame::FromRegDisplay(&(csi.m_activeFrame.registers)); -#else - sfInterceptFramePointer = StackFrame::FromRegDisplay(&(csi.m_activeFrame.registers)); -#endif - } + sfInterceptFramePointer = StackFrame::FromRegDisplay(&(csi.m_activeFrame.registers)); + if (pExState->GetDebuggerState()->SetDebuggerInterceptInfo(csi.m_activeFrame.pIJM, pThread, csi.m_activeFrame.MethodToken, diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index c772b74fb9b0b7..0e3e115ddfe042 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -259,7 +259,6 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_legacyCorruptedStateExceptionsPolicy, W("le CONFIG_DWORD_INFO(INTERNAL_SuppressLostExceptionTypeAssert, W("SuppressLostExceptionTypeAssert"), 0, "") RETAIL_CONFIG_DWORD_INFO(INTERNAL_UseEntryPointFilter, W("UseEntryPointFilter"), 0, "") RETAIL_CONFIG_DWORD_INFO(INTERNAL_Corhost_Swallow_Uncaught_Exceptions, W("Corhost_Swallow_Uncaught_Exceptions"), 0, "") -RETAIL_CONFIG_DWORD_INFO(EXTERNAL_LegacyExceptionHandling, W("LegacyExceptionHandling"), 0, "Enable legacy exception handling."); CONFIG_DWORD_INFO(INTERNAL_LogStackOverflowExit, W("LogStackOverflowExit"), 0, "Temporary flag to log stack overflow exit process") /// diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index b43cb3fd5eff51..2c5a21fd80c1c7 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -120,7 +120,6 @@ DEFINE_DACVAR(DWORD, dac__g_TlsIndex, g_TlsIndex) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pEHClass, ::g_pEHClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pExceptionServicesInternalCallsClass, ::g_pExceptionServicesInternalCallsClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pStackFrameIteratorClass, ::g_pStackFrameIteratorClass) -DEFINE_DACVAR(BOOL, dac__g_isNewExceptionHandlingEnabled, ::g_isNewExceptionHandlingEnabled) #endif DEFINE_DACVAR(PTR_SString, SString__s_Empty, SString::s_Empty) diff --git a/src/coreclr/vm/clrex.cpp b/src/coreclr/vm/clrex.cpp index 947f5eeb992f17..711cceaf184096 100644 --- a/src/coreclr/vm/clrex.cpp +++ b/src/coreclr/vm/clrex.cpp @@ -844,16 +844,6 @@ void CLRException::HandlerState::SetupCatch(INDEBUG_COMMA(_In_z_ const char * sz } } } - -#ifdef FEATURE_EH_FUNCLETS - if (!DidCatchCxx() && !g_isNewExceptionHandlingEnabled) - { - // this must be done after the second pass has run, it does not - // reference anything on the stack, so it is safe to run in an - // SEH __except clause as well as a C++ catch clause. - ExceptionTracker::PopTrackers(this); - } -#endif // FEATURE_EH_FUNCLETS } #ifdef LOGGING diff --git a/src/coreclr/vm/debugdebugger.cpp b/src/coreclr/vm/debugdebugger.cpp index a77dd524d6eaf5..32986a13b5f81e 100644 --- a/src/coreclr/vm/debugdebugger.cpp +++ b/src/coreclr/vm/debugdebugger.cpp @@ -957,7 +957,7 @@ void DebugStackTrace::GetStackFramesFromException(OBJECTREF * e, #if defined(DACCESS_COMPILE) && defined(TARGET_AMD64) // Compensate for a bug in the old EH that for a frame that faulted // has the ip pointing to an address before the faulting instruction - if (g_isNewExceptionHandlingEnabled && (i == 0) && ((cur.flags & STEF_IP_ADJUSTED) == 0)) + if ((i == 0) && ((cur.flags & STEF_IP_ADJUSTED) == 0)) { ip -= 1; } diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index 48d67b68fc0940..8d546f6c6f0684 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -6542,10 +6542,7 @@ VEH_ACTION WINAPI CLRVectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo // Not an Out-of-memory situation, so no need for a forbid fault region here // #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled) - { - EEPolicy::HandleStackOverflow(); - } + EEPolicy::HandleStackOverflow(); #endif // FEATURE_EH_FUNCLETS return VEH_CONTINUE_SEARCH; } @@ -7240,14 +7237,7 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) // // HandleManagedFault may never return, so we cannot use a forbid fault region around it. // - if (g_isNewExceptionHandlingEnabled) - { - HandleManagedFaultNew(pExceptionInfo->ExceptionRecord, pExceptionInfo->ContextRecord); - } - else - { - HandleManagedFault(pExceptionInfo->ExceptionRecord, pExceptionInfo->ContextRecord); - } + HandleManagedFaultNew(pExceptionInfo->ExceptionRecord, pExceptionInfo->ContextRecord); return EXCEPTION_CONTINUE_EXECUTION; } #endif // FEATURE_EH_FUNCLETS @@ -7457,7 +7447,7 @@ VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFra Exception::Delete(pException); #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled && !nativeRethrow) + if (!nativeRethrow) { Thread *pThread = GetThread(); ThreadExceptionState* pExState = pThread->GetExceptionState(); diff --git a/src/coreclr/vm/excep.h b/src/coreclr/vm/excep.h index ba37657a520a79..7fc3f29b46e97f 100644 --- a/src/coreclr/vm/excep.h +++ b/src/coreclr/vm/excep.h @@ -756,10 +756,6 @@ LONG WatsonLastChance( bool DebugIsEECxxException(EXCEPTION_RECORD* pExceptionRecord); -#ifndef FEATURE_EH_FUNCLETS -#define g_isNewExceptionHandlingEnabled false -#endif - inline void CopyOSContext(T_CONTEXT* pDest, T_CONTEXT* pSrc) { SIZE_T cbReadOnlyPost = 0; @@ -769,10 +765,7 @@ inline void CopyOSContext(T_CONTEXT* pDest, T_CONTEXT* pSrc) memcpyNoGCRefs(pDest, pSrc, sizeof(T_CONTEXT) - cbReadOnlyPost); #ifdef TARGET_AMD64 - if (g_isNewExceptionHandlingEnabled) - { - pDest->ContextFlags = (pDest->ContextFlags & ~(CONTEXT_XSTATE | CONTEXT_FLOATING_POINT)) | CONTEXT_AMD64; - } + pDest->ContextFlags = (pDest->ContextFlags & ~(CONTEXT_XSTATE | CONTEXT_FLOATING_POINT)) | CONTEXT_AMD64; #endif // TARGET_AMD64 } diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 673d3f8fe50c97..628e4254954c00 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -234,8 +234,6 @@ void InitializeExceptionHandling() g_theTrackerAllocator.Init(); - g_isNewExceptionHandlingEnabled = Configuration::GetKnobBooleanValue(W("System.Runtime.LegacyExceptionHandling"), CLRConfig::EXTERNAL_LegacyExceptionHandling ) == 0; - #ifdef TARGET_UNIX // Register handler of hardware exceptions like null reference in PAL PAL_SetHardwareExceptionHandler(HandleHardwareException, IsSafeToHandleHardwareException); @@ -1000,403 +998,7 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord, STATIC_CONTRACT_GC_TRIGGERS; STATIC_CONTRACT_THROWS; - if (g_isNewExceptionHandlingEnabled) - { - return ProcessCLRExceptionNew(pExceptionRecord, pEstablisherFrame, pContextRecord, pDispatcherContext); - } - - // We must preserve this so that GCStress=4 eh processing doesnt kill last error. - DWORD dwLastError = GetLastError(); - - EXCEPTION_DISPOSITION returnDisposition = ExceptionContinueSearch; - - STRESS_LOG5(LF_EH, LL_INFO10, "Processing exception at establisher=%p, ip=%p disp->cxr: %p, sp: %p, cxr @ exception: %p\n", - pEstablisherFrame, pDispatcherContext->ControlPc, - pDispatcherContext->ContextRecord, - GetSP(pDispatcherContext->ContextRecord), pContextRecord); - AMD64_ONLY(STRESS_LOG3(LF_EH, LL_INFO10, " rbx=%p, rsi=%p, rdi=%p\n", pContextRecord->Rbx, pContextRecord->Rsi, pContextRecord->Rdi)); - - // sample flags early on because we may change pExceptionRecord below - // if we are seeing a STATUS_UNWIND_CONSOLIDATE - DWORD dwExceptionFlags = pExceptionRecord->ExceptionFlags; - Thread* pThread = GetThread(); - - // Stack Overflow is handled specially by the CLR EH mechanism. In fact - // there are cases where we aren't in managed code, but aren't quite in - // known unmanaged code yet either... - // - // These "boundary code" cases include: - // - in JIT helper methods which don't have a frame - // - in JIT helper methods before/during frame setup - // - in FCALL before/during frame setup - // - // In those cases on x86 we take special care to start our unwind looking - // for a handler which is below the last explicit frame which has been - // established on the stack as it can't reliably crawl the stack frames - // above that. - // NOTE: see code in the CLRVectoredExceptionHandler() routine. - // - // From the perspective of the EH subsystem, we can handle unwind correctly - // even without erecting a transition frame on WIN64. However, since the GC - // uses the stackwalker to update object references, and since the stackwalker - // relies on transition frame, we still cannot let an exception be handled - // by an unprotected managed frame. - // - // This code below checks to see if a SO has occurred outside of managed code. - // If it has, and if we don't have a transition frame higher up the stack, then - // we don't handle the SO. - if (!(dwExceptionFlags & EXCEPTION_UNWINDING)) - { - if (pExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) - { - // We don't need to unwind the frame chain here because we have backstop - // personality routines at the U2M boundary to handle do that. They are - // the personality routines of CallDescrWorker() and UMThunkStubCommon(). - // - // See VSW 471619 for more information. - - // We should be in cooperative mode if we are going to handle the SO. - // We track SO state for the thread. - EEPolicy::HandleStackOverflow(); - InterlockedAnd((LONG*)&pThread->m_fPreemptiveGCDisabled, 0); - return ExceptionContinueSearch; - } - } - else - { - DWORD exceptionCode = pExceptionRecord->ExceptionCode; - - if ((NTSTATUS)exceptionCode == STATUS_UNWIND) - // If exceptionCode is STATUS_UNWIND, RtlUnwind is called with a NULL ExceptionRecord, - // therefore OS uses a faked ExceptionRecord with STATUS_UNWIND code. Then we need to - // look at our saved exception code. - exceptionCode = GetCurrentExceptionCode(); - - if (exceptionCode == STATUS_STACK_OVERFLOW) - { - return ExceptionContinueSearch; - } - } - - StackFrame sf((UINT_PTR)pEstablisherFrame); - - - { - GCX_COOP(); - // Update the current establisher frame - if (dwExceptionFlags & EXCEPTION_UNWINDING) - { - ExceptionTracker *pCurrentTracker = (ExceptionTracker*)pThread->GetExceptionState()->GetCurrentExceptionTracker(); - if (pCurrentTracker != NULL) - { - pCurrentTracker->SetCurrentEstablisherFrame(sf); - } - } - -#ifdef _DEBUG - Thread::ObjectRefFlush(pThread); -#endif // _DEBUG - } - - - // - // begin Early Processing - // - { - EH_LOG((LL_INFO100, "..................................................................................\n")); - EH_LOG((LL_INFO100, "ProcessCLRException enter, sp = 0x%p, ControlPc = 0x%p\n", pEstablisherFrame, pDispatcherContext->ControlPc)); - DebugLogExceptionRecord(pExceptionRecord); - - if (STATUS_UNWIND_CONSOLIDATE == pExceptionRecord->ExceptionCode) - { - EH_LOG((LL_INFO100, "STATUS_UNWIND_CONSOLIDATE, retrieving stored exception record\n")); - _ASSERTE(pExceptionRecord->NumberParameters >= 7); - pExceptionRecord = (EXCEPTION_RECORD*)pExceptionRecord->ExceptionInformation[6]; - DebugLogExceptionRecord(pExceptionRecord); - } - - CONSISTENCY_CHECK_MSG(!DebugIsEECxxException(pExceptionRecord), "EE C++ Exception leaked into managed code!!\n"); - } - // - // end Early Processing (tm) -- we're now into really processing an exception for managed code - // - - if (!(dwExceptionFlags & EXCEPTION_UNWINDING)) - { - // If the exception is a breakpoint, but outside of the runtime or managed code, - // let it go. It is not ours, so someone else will handle it, or we'll see - // it again as an unhandled exception. - if ((pExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) || - (pExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP)) - { - // It is a breakpoint; is it from the runtime or managed code? - PCODE ip = GetIP(pContextRecord); // IP of the fault. - - BOOL fExternalException; - - fExternalException = (!ExecutionManager::IsManagedCode(ip) && - !IsIPInModule(GetClrModuleBase(), ip)); - - if (fExternalException) - { - // The breakpoint was not ours. Someone else can handle it. (Or if not, we'll get it again as - // an unhandled exception.) - returnDisposition = ExceptionContinueSearch; - goto lExit; - } - } - } - - { - BOOL bAsynchronousThreadStop = IsThreadHijackedForThreadStop(pThread, pExceptionRecord); - - // we already fixed the context in HijackHandler, so let's - // just clear the thread state. - pThread->ResetThrowControlForThread(); - - ExceptionTracker::StackTraceState STState; - - ExceptionTracker* pTracker = ExceptionTracker::GetOrCreateTracker( - pDispatcherContext->ControlPc, - sf, - pExceptionRecord, - pContextRecord, - bAsynchronousThreadStop, - !(dwExceptionFlags & EXCEPTION_UNWINDING), - &STState); - - if (!(dwExceptionFlags & EXCEPTION_UNWINDING)) - { - // Switch to COOP mode - GCX_COOP(); - - // Failfast if exception indicates corrupted process state - if (IsProcessCorruptedStateException(pExceptionRecord->ExceptionCode, pTracker->GetThrowable())) - { - OBJECTREF oThrowable = NULL; - SString message; - - GCPROTECT_BEGIN(oThrowable); - oThrowable = pTracker->GetThrowable(); - if (oThrowable != NULL) - { - EX_TRY - { - GetExceptionMessage(oThrowable, message); - } - EX_CATCH - { - } - EX_END_CATCH(SwallowAllExceptions); - } - GCPROTECT_END(); - - EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(pExceptionRecord->ExceptionCode, (LPCWSTR)message); - } - } - -#ifndef TARGET_UNIX // Watson is on Windows only - // Setup bucketing details for nested exceptions (rethrow and non-rethrow) only if we are in the first pass - if (!(dwExceptionFlags & EXCEPTION_UNWINDING)) - { - ExceptionTracker *pPrevEHTracker = (ExceptionTracker*)pTracker->GetPreviousExceptionTracker(); - if (pPrevEHTracker != NULL) - { - SetStateForWatsonBucketing((STState == ExceptionTracker::STS_FirstRethrowFrame), pPrevEHTracker->GetThrowableAsHandle()); - } - } -#endif //!TARGET_UNIX - - CLRUnwindStatus status; - - // Refer to comment in ProcessOSExceptionNotification about ICF and codegen difference. - InlinedCallFrame *pICFSetAsLimitFrame = NULL; - - status = pTracker->ProcessOSExceptionNotification( - pExceptionRecord, - pContextRecord, - pDispatcherContext, - dwExceptionFlags, - sf, - pThread, - STState, - (PVOID)pICFSetAsLimitFrame); - - if (FirstPassComplete == status) - { - EH_LOG((LL_INFO100, "first pass finished, found handler, TargetFrameSp = %p\n", - pDispatcherContext->EstablisherFrame)); - - SetLastError(dwLastError); - -#ifndef TARGET_UNIX - // - // At this point (the end of the 1st pass) we don't know where - // we are going to resume to. So, we pass in an address, which - // lies in NULL pointer partition of the memory, as the target IP. - // - // Once we reach the target frame in the second pass unwind, we call - // the catch funclet that caused us to resume execution and it - // tells us where we are resuming to. At that point, we patch - // the context record with the resume IP and RtlUnwind finishes - // by restoring our context at the right spot. - // - // If we are unable to set the resume PC for some reason, then - // the OS will try to resume at the NULL partition address and the - // attempt will fail due to AV, resulting in failfast, helping us - // isolate problems in patching the IP. - - ClrUnwindEx(pExceptionRecord, - (UINT_PTR)pThread, - INVALID_RESUME_ADDRESS, - pDispatcherContext->EstablisherFrame); - - UNREACHABLE(); - // - // doesn't return - // -#else - // On Unix, we will return ExceptionStackUnwind back to the custom - // exception dispatch system. When it sees this disposition, it will - // know that we want to handle the exception and will commence unwind - // via the custom unwinder. - return ExceptionStackUnwind; - -#endif // TARGET_UNIX - } - else if (SecondPassComplete == status) - { - bool fAborting = false; - UINT_PTR uResumePC = (UINT_PTR)-1; - UINT_PTR uOriginalSP = GetSP(pContextRecord); - - Frame* pLimitFrame = pTracker->GetLimitFrame(); - - pDispatcherContext->ContextRecord = pContextRecord; - - // We may be in COOP mode at this point - the indefinite switch was done - // in ExceptionTracker::ProcessManagedCallFrame. - // - // However, if a finally was invoked non-exceptionally and raised an exception - // that was caught in its parent method, unwind will result in invoking any applicable termination - // handlers in the finally funclet and thus, also switching the mode to COOP indefinitely. - // - // Since the catch block to be executed will lie in the parent method, - // we will skip frames till we reach the parent and in the process, switch back to PREEMP mode - // as control goes back to the OS. - // - // Upon reaching the target of unwind, we wont call ExceptionTracker::ProcessManagedCallFrame (since any - // handlers in finally or surrounding it will be invoked when we unwind finally funclet). Thus, - // we may not be in COOP mode. - // - // Since CallCatchHandler expects to be in COOP mode, perform the switch here. - GCX_COOP_NO_DTOR(); - uResumePC = pTracker->CallCatchHandler(pContextRecord, &fAborting); - - { - // - // GC must NOT occur after the handler has returned until - // we resume at the new address because the stackwalker - // EnumGcRefs would try and report things as live from the - // try body, that were probably reported dead from the - // handler body. - // - // GC must NOT occur once the frames have been popped because - // the values in the unwound CONTEXT are not GC-protected. - // - GCX_FORBID(); - - CONSISTENCY_CHECK((UINT_PTR)-1 != uResumePC); - - // Ensure we are not resuming to the invalid target IP we had set at the end of - // first pass - _ASSERTE_MSG(INVALID_RESUME_ADDRESS != uResumePC, "CallCatchHandler returned invalid resume PC!"); - - // - // CallCatchHandler freed the tracker. - // - INDEBUG(pTracker = (ExceptionTracker*)POISONC); - - // Note that we should only fail to fix up for SO. - bool fFixedUp = FixNonvolatileRegisters(uOriginalSP, pThread, pContextRecord, fAborting); - _ASSERTE(fFixedUp || (pExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)); - - - CONSISTENCY_CHECK(pLimitFrame > dac_cast(GetSP(pContextRecord))); - if (pICFSetAsLimitFrame != NULL) - { - _ASSERTE(pICFSetAsLimitFrame == pLimitFrame); - - // Mark the ICF as inactive (by setting the return address as NULL). - // It will be marked as active at the next PInvoke callsite. - // - // This ensures that any stackwalk post the catch handler but before - // the next pinvoke callsite does not see the frame as active. - pICFSetAsLimitFrame->Reset(); - } - - pThread->SetFrame(pLimitFrame); - - FixContext(pContextRecord); - - SetIP(pContextRecord, (PCODE)uResumePC); - } - -#ifdef STACK_GUARDS_DEBUG - // We are transitioning back to managed code, so ensure that we are in - // SO-tolerant mode before we do so. - RestoreSOToleranceState(); -#endif - -#ifdef TARGET_AMD64 - // OSes older than Win8 have a bug where RtlUnwindEx passes meaningless ContextFlags to the personality routine in - // some cases. - pContextRecord->ContextFlags |= CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT; -#endif - - ExceptionTracker::ResumeExecution(pContextRecord); - UNREACHABLE(); - } - } - -lExit: ; - - EH_LOG((LL_INFO100, "returning %s\n", DebugGetExceptionDispositionName(returnDisposition))); - CONSISTENCY_CHECK( !((dwExceptionFlags & EXCEPTION_TARGET_UNWIND) && (ExceptionContinueSearch == returnDisposition))); - - if ((ExceptionContinueSearch == returnDisposition)) - { - if (dwExceptionFlags & EXCEPTION_UNWINDING) - { - EECodeInfo codeInfo(pDispatcherContext->ControlPc); - if (codeInfo.IsValid()) - { - bool invalidRevPInvoke; -#ifdef USE_GC_INFO_DECODER - GcInfoDecoder gcInfoDecoder(codeInfo.GetGCInfoToken(), DECODE_REVERSE_PINVOKE_VAR); - invalidRevPInvoke = gcInfoDecoder.GetReversePInvokeFrameStackSlot() != NO_REVERSE_PINVOKE_FRAME; -#else // USE_GC_INFO_DECODER - hdrInfo gcHdrInfo; - DecodeGCHdrInfo(codeInfo.GetGCInfoToken(), 0, &gcHdrInfo); - invalidRevPInvoke = gcHdrInfo.revPInvokeOffset != INVALID_REV_PINVOKE_OFFSET; -#endif // USE_GC_INFO_DECODER - - if (invalidRevPInvoke) - { - // Exception is being propagated from a method marked UnmanagedCallersOnlyAttribute into its native caller. - // The explicit frame chain needs to be unwound at this boundary. - bool fIsSO = pExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW; - CleanUpForSecondPass(pThread, fIsSO, pEstablisherFrame, pEstablisherFrame); - } - } - } - - GCX_PREEMP_NO_DTOR(); - } - - SetLastError(dwLastError); - - return returnDisposition; + return ProcessCLRExceptionNew(pExceptionRecord, pEstablisherFrame, pContextRecord, pDispatcherContext); } // When we hit a native exception such as an AV in managed code, we put up a FaultingExceptionFrame which saves all the @@ -3612,59 +3214,6 @@ void ExceptionTracker::PopTrackers( } } -// -// during the second pass, an exception might escape out to -// unmanaged code where it is swallowed (or potentially rethrown). -// The current tracker is abandoned in this case, and if a rethrow -// does happen in unmanaged code, this is unfortunately treated as -// a brand new exception. This is unavoidable because if two -// exceptions escape out to unmanaged code in this manner, a subsequent -// rethrow cannot be disambiguated as corresponding to the nested vs. -// the original exception. -void ExceptionTracker::PopTrackerIfEscaping( - void* pStackPointer - ) -{ - CONTRACTL - { - MODE_ANY; - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - - _ASSERTE(!g_isNewExceptionHandlingEnabled); - Thread* pThread = GetThread(); - ThreadExceptionState* pExState = pThread->GetExceptionState(); - ExceptionTracker* pTracker = (ExceptionTracker*)pExState->m_pCurrentTracker; - CONSISTENCY_CHECK((NULL == pTracker) || pTracker->IsValid()); - - // If we are resuming in managed code (albeit further up the stack) we will still need this - // tracker. Otherwise we are either propagating into unmanaged code -- with the rethrow - // issues mentioned above -- or we are going unhandled. - // - // Note that we don't distinguish unmanaged code in the EE vs. unmanaged code outside the - // EE. We could use the types of the Frames above us to make this distinction. Without - // this, the technique of EX_TRY/EX_CATCH/EX_RETHROW inside the EE will lose its tracker - // and have to rely on LastThrownObject in the rethrow. Along the same lines, unhandled - // exceptions only have access to LastThrownObject. - // - // There may not be a current tracker if, for instance, UMThunk has dispatched into managed - // code via CallDescr. In that case, CallDescr may pop the tracker, leaving UMThunk with - // nothing to do. - - if (pTracker && pTracker->m_sfResumeStackFrame.IsNull()) - { - StackFrame sf((UINT_PTR)pStackPointer); - StackFrame sfTopMostStackFrameFromFirstPass = pTracker->GetTopmostStackFrameFromFirstPass(); - - // Refer to the comment around ExceptionTracker::HasFrameBeenUnwoundByAnyActiveException - // for details on the usage of this COOP switch. - GCX_COOP(); - ExceptionTracker::PopTrackers(sf, true); - } -} - // // static void ExceptionTracker::PopTrackers( @@ -3682,117 +3231,7 @@ void ExceptionTracker::PopTrackers( } CONTRACTL_END; - if (g_isNewExceptionHandlingEnabled) - { - return; - } - - Thread* pThread = GetThreadNULLOk(); - ExceptionTracker* pTracker = (pThread ? (ExceptionTracker*)pThread->GetExceptionState()->m_pCurrentTracker : NULL); - - // NOTE: - // - // This method is a no-op when there is no managed Thread object. We detect such a case and short circuit out in ExceptionTrackers::PopTrackers. - // If this ever changes, then please revisit that method and fix it up appropriately. - - // If this tracker does not have valid stack ranges and it is in the first pass, - // then we came here likely when the tracker was being setup - // and an exception took place. - // - // In such a case, we will not pop off the tracker - if (pTracker && pTracker->m_ScannedStackRange.IsEmpty() && pTracker->IsInFirstPass()) - { - // skip any others with empty ranges... - do - { - pTracker = (ExceptionTracker*)pTracker->m_pPrevNestedInfo; - } - while (pTracker && pTracker->m_ScannedStackRange.IsEmpty()); - - // pTracker is now the first non-empty one, make sure it doesn't need popping - // if it does, then someone let an exception propagate out of the exception dispatch code - - _ASSERTE(!pTracker || (pTracker->m_ScannedStackRange.GetUpperBound() > sfResumeFrame)); - return; - } - -#if defined(DEBUGGING_SUPPORTED) - DWORD_PTR dwInterceptStackFrame = 0; - - // This method may be called on an unmanaged thread, in which case no interception can be done. - if (pTracker) - { - ThreadExceptionState* pExState = pThread->GetExceptionState(); - - // If the exception is intercepted, then pop trackers according to the stack frame at which - // the exception is intercepted. We must retrieve the frame pointer before we start popping trackers. - if (pExState->GetFlags()->DebuggerInterceptInfo()) - { - pExState->GetDebuggerState()->GetDebuggerInterceptInfo(NULL, NULL, (PBYTE*)&dwInterceptStackFrame, - NULL, NULL); - } - } -#endif // DEBUGGING_SUPPORTED - - while (pTracker) - { -#ifndef TARGET_UNIX - // When we are about to pop off a tracker, it should - // have a stack range setup. - // It is not true on PAL where the scanned stack range needs to - // be reset after unwinding a sequence of native frames. - _ASSERTE(!pTracker->m_ScannedStackRange.IsEmpty()); -#endif // TARGET_UNIX - - ExceptionTracker* pPrev = (ExceptionTracker*)pTracker->m_pPrevNestedInfo; - - // - // with new tracker collapsing code, we will only ever pop one of these at a time - // at the end of the 2nd pass. However, CLRException::HandlerState::SetupCatch - // still uses this function and we still need to revisit how it interacts with - // ExceptionTrackers - // - - if ((fPopWhenEqual && (pTracker->m_ScannedStackRange.GetUpperBound() == sfResumeFrame)) || - (pTracker->m_ScannedStackRange.GetUpperBound() < sfResumeFrame)) - { -#if defined(DEBUGGING_SUPPORTED) - if (g_pDebugInterface != NULL) - { - if (pTracker->m_ScannedStackRange.GetUpperBound().SP < dwInterceptStackFrame) - { - g_pDebugInterface->DeleteInterceptContext(pTracker->m_DebuggerExState.GetDebuggerInterceptContext()); - } - else - { - _ASSERTE(dwInterceptStackFrame == 0 || - ( dwInterceptStackFrame == sfResumeFrame.SP && - dwInterceptStackFrame == pTracker->m_ScannedStackRange.GetUpperBound().SP )); - } - } -#endif // DEBUGGING_SUPPORTED - - ExceptionTracker* pTrackerToFree = pTracker; - EH_LOG((LL_INFO100, "Unlinking ExceptionTracker object 0x%p, thread = 0x%p\n", pTrackerToFree, pTrackerToFree->m_pThread)); - CONSISTENCY_CHECK(pTracker->IsValid()); - pTracker = pPrev; - - // free managed tracker resources causing notification -- do this before unlinking the tracker - // this is necessary so that we know an exception is still in flight while we give the notification - FreeTrackerMemory(pTrackerToFree, memManaged); - - // unlink the tracker from the thread - pThread->GetExceptionState()->m_pCurrentTracker = pTracker; - CONSISTENCY_CHECK((NULL == pTracker) || pTracker->IsValid()); - - // free unmanaged tracker resources - FreeTrackerMemory(pTrackerToFree, memUnmanaged); - } - else - { - break; - } - } + return; } // @@ -4334,38 +3773,22 @@ EXCEPTION_DISPOSITION ClrDebuggerDoUnwindAndIntercept(X86_FIRST_ARG(EXCEPTION_RE (PBYTE*)&uInterceptStackFrame, NULL, NULL); - if (g_isNewExceptionHandlingEnabled) - { - GCX_COOP(); - ExInfo* pExInfo = (ExInfo*)pExState->GetCurrentExceptionTracker(); - _ASSERTE(pExInfo != NULL); + GCX_COOP(); - PREPARE_NONVIRTUAL_CALLSITE(METHOD__EH__UNWIND_AND_INTERCEPT); - DECLARE_ARGHOLDER_ARRAY(args, 2); - args[ARGNUM_0] = PTR_TO_ARGHOLDER(pExInfo); - args[ARGNUM_1] = PTR_TO_ARGHOLDER(uInterceptStackFrame); - pThread->IncPreventAbort(); + ExInfo* pExInfo = (ExInfo*)pExState->GetCurrentExceptionTracker(); + _ASSERTE(pExInfo != NULL); - //Ex.RhUnwindAndIntercept(throwable, &exInfo) - CRITICAL_CALLSITE; - CALL_MANAGED_METHOD_NORET(args) + PREPARE_NONVIRTUAL_CALLSITE(METHOD__EH__UNWIND_AND_INTERCEPT); + DECLARE_ARGHOLDER_ARRAY(args, 2); + args[ARGNUM_0] = PTR_TO_ARGHOLDER(pExInfo); + args[ARGNUM_1] = PTR_TO_ARGHOLDER(uInterceptStackFrame); + pThread->IncPreventAbort(); + + //Ex.RhUnwindAndIntercept(throwable, &exInfo) + CRITICAL_CALLSITE; + CALL_MANAGED_METHOD_NORET(args) - UNREACHABLE(); - } - else - { -#ifdef TARGET_UNIX - CONTEXT *pContext = pThread->GetExceptionState()->GetContextRecord(); - PAL_SEHException ex(pThread->GetExceptionState()->GetExceptionRecord(), pContext, /* onStack */ false); - ex.TargetIp = INVALID_RESUME_ADDRESS; - ex.TargetFrameSp = uInterceptStackFrame; - ex.ReturnValue = (UINT_PTR)pThread; - UnwindManagedExceptionPass2(ex, pContext); -#else // TARGET_UNIX - ClrUnwindEx(pExceptionRecord, (UINT_PTR)pThread, INVALID_RESUME_ADDRESS, uInterceptStackFrame); -#endif // TARGET_UNIX - } UNREACHABLE(); } #endif // DEBUGGER_EXCEPTION_INTERCEPTION_SUPPORTED @@ -4998,85 +4421,13 @@ VOID DECLSPEC_NORETURN UnwindManagedExceptionPass1(PAL_SEHException& ex, CONTEXT VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHardwareException) { - if (g_isNewExceptionHandlingEnabled) + if (!isHardwareException) { - if (!isHardwareException) - { - RtlCaptureContext(ex.GetContextRecord()); - } - GCX_COOP(); - OBJECTREF throwable = ExceptionTracker::CreateThrowable(ex.GetExceptionRecord(), FALSE); - DispatchManagedException(throwable, ex.GetContextRecord()); + RtlCaptureContext(ex.GetContextRecord()); } - - do - { - try - { - // Unwind the context to the first managed frame - CONTEXT frameContext; - - // If the exception is hardware exceptions, we use the exception's context record directly - if (isHardwareException) - { - frameContext = *ex.GetContextRecord(); - } - else - { - RtlCaptureContext(&frameContext); - UINT_PTR currentSP = GetSP(&frameContext); - - if (Thread::VirtualUnwindToFirstManagedCallFrame(&frameContext) == 0) - { - // There are no managed frames on the stack, so the exception was not handled - LONG disposition = InternalUnhandledExceptionFilter_Worker(&ex.ExceptionPointers); - _ASSERTE(disposition == EXCEPTION_CONTINUE_SEARCH); - CrashDumpAndTerminateProcess(1); - UNREACHABLE(); - } - - UINT_PTR firstManagedFrameSP = GetSP(&frameContext); - - // Check if there is any exception holder in the skipped frames. If there is one, we need to unwind them - // using the C++ handling. This is a special case when the UNINSTALL_MANAGED_EXCEPTION_DISPATCHER was - // not at the managed to native boundary. - if (NativeExceptionHolderBase::FindNextHolder(nullptr, (void*)currentSP, (void*)firstManagedFrameSP) != nullptr) - { - break; - } - } - - if (ex.IsFirstPass()) - { - UnwindManagedExceptionPass1(ex, &frameContext); - } - else - { - // This is a continuation of pass 2 after native frames unwinding. - UnwindManagedExceptionPass2(ex, &frameContext); - } - UNREACHABLE(); - } - catch (PAL_SEHException& ex2) - { - isHardwareException = false; - ex = std::move(ex2); - } - - } - while (true); - - // Ensure that the corruption severity is set for exceptions that didn't pass through managed frames - // yet and so there is no exception tracker. - if (ex.IsFirstPass()) - { - // Get the thread and the thread exception state - they must exist at this point - Thread *pCurThread = GetThread(); - ThreadExceptionState * pCurTES = pCurThread->GetExceptionState(); - _ASSERTE(pCurTES != NULL); - } - - throw std::move(ex); + GCX_COOP(); + OBJECTREF throwable = ExceptionTracker::CreateThrowable(ex.GetExceptionRecord(), FALSE); + DispatchManagedException(throwable, ex.GetContextRecord()); } #if defined(TARGET_AMD64) || defined(TARGET_X86) @@ -5545,43 +4896,37 @@ BOOL HandleHardwareException(PAL_SEHException* ex) fef.InitAndLink(ex->GetContextRecord()); } - if (g_isNewExceptionHandlingEnabled) - { - Thread *pThread = GetThread(); + Thread *pThread = GetThread(); - ExInfo exInfo(pThread, ex->GetExceptionRecord(), ex->GetContextRecord(), ExKind::HardwareFault); + ExInfo exInfo(pThread, ex->GetExceptionRecord(), ex->GetContextRecord(), ExKind::HardwareFault); - DWORD exceptionCode = ex->GetExceptionRecord()->ExceptionCode; - if (exceptionCode == STATUS_ACCESS_VIOLATION) + DWORD exceptionCode = ex->GetExceptionRecord()->ExceptionCode; + if (exceptionCode == STATUS_ACCESS_VIOLATION) + { + if (ex->GetExceptionRecord()->ExceptionInformation[1] < NULL_AREA_SIZE) { - if (ex->GetExceptionRecord()->ExceptionInformation[1] < NULL_AREA_SIZE) - { - exceptionCode = 0; //STATUS_REDHAWK_NULL_REFERENCE; - } + exceptionCode = 0; //STATUS_REDHAWK_NULL_REFERENCE; } + } - if (!ex->RecordsOnStack) - { - exInfo.TakeExceptionPointersOwnership(ex); - } + if (!ex->RecordsOnStack) + { + exInfo.TakeExceptionPointersOwnership(ex); + } - GCPROTECT_BEGIN(exInfo.m_exception); - PREPARE_NONVIRTUAL_CALLSITE(METHOD__EH__RH_THROWHW_EX); - DECLARE_ARGHOLDER_ARRAY(args, 2); - args[ARGNUM_0] = DWORD_TO_ARGHOLDER(exceptionCode); - args[ARGNUM_1] = PTR_TO_ARGHOLDER(&exInfo); + GCPROTECT_BEGIN(exInfo.m_exception); + PREPARE_NONVIRTUAL_CALLSITE(METHOD__EH__RH_THROWHW_EX); + DECLARE_ARGHOLDER_ARRAY(args, 2); + args[ARGNUM_0] = DWORD_TO_ARGHOLDER(exceptionCode); + args[ARGNUM_1] = PTR_TO_ARGHOLDER(&exInfo); - pThread->IncPreventAbort(); + pThread->IncPreventAbort(); - //Ex.RhThrowHwEx(exceptionCode, &exInfo) - CALL_MANAGED_METHOD_NORET(args) + //Ex.RhThrowHwEx(exceptionCode, &exInfo) + CALL_MANAGED_METHOD_NORET(args) + + GCPROTECT_END(); - GCPROTECT_END(); - } - else - { - DispatchManagedException(*ex, true /* isHardwareException */); - } UNREACHABLE(); } else @@ -6201,14 +5546,7 @@ void CleanUpForSecondPass(Thread* pThread, bool fIsSO, LPVOID MemoryStackFpForFr // (stack grows up). if (!fIsSO) { - if (g_isNewExceptionHandlingEnabled) - { - ExInfo::PopExInfos(pThread, MemoryStackFp); - } - else - { - ExceptionTracker::PopTrackerIfEscaping(MemoryStackFp); - } + ExInfo::PopExInfos(pThread, MemoryStackFp); } } @@ -6369,17 +5707,8 @@ CallDescrWorkerUnwindFrameChainHandler(IN PEXCEPTION_RECORD pExceptionReco } EXCEPTION_DISPOSITION retVal; - if (!g_isNewExceptionHandlingEnabled) - { - retVal = ProcessCLRException(pExceptionRecord, - pEstablisherFrame, - pContextRecord, - pDispatcherContext); - } - else - { - retVal = ExceptionContinueSearch; - } + + retVal = ExceptionContinueSearch; if (retVal == ExceptionContinueSearch) { @@ -6530,7 +5859,7 @@ void ExceptionTrackerBase::StackRange::ExtendUpperBound(StackFrame sf) { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsConsistent()); - CONSISTENCY_CHECK(g_isNewExceptionHandlingEnabled ? (sf >= m_sfHighBound) : (sf > m_sfHighBound)); + CONSISTENCY_CHECK((sf >= m_sfHighBound)); m_sfHighBound = sf; } @@ -6539,7 +5868,7 @@ void ExceptionTrackerBase::StackRange::ExtendLowerBound(StackFrame sf) { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsConsistent()); - CONSISTENCY_CHECK(g_isNewExceptionHandlingEnabled ? (sf <= m_sfLowBound) : (sf < m_sfLowBound)); + CONSISTENCY_CHECK((sf <= m_sfLowBound)); m_sfLowBound = sf; } @@ -6697,24 +6026,8 @@ bool ExceptionTracker::IsInStackRegionUnwoundBySpecifiedException(CrawlFrame * p // Remember that sfLowerBound and sfUpperBound are in the "OS format". // Refer to the comment for CallerStackFrame for more information. - if (g_isNewExceptionHandlingEnabled) - { - // The new exception handling sets the ranges always to the SP of the unwound frame - return (sfLowerBound < csfToCheck) && (csfToCheck <= sfUpperBound); - } - -#ifndef STACK_RANGE_BOUNDS_ARE_CALLER_SP - if ((sfLowerBound < csfToCheck) && (csfToCheck <= sfUpperBound)) -#else // !STACK_RANGE_BOUNDS_ARE_CALLER_SP - if ((sfLowerBound <= csfToCheck) && (csfToCheck < sfUpperBound)) -#endif // STACK_RANGE_BOUNDS_ARE_CALLER_SP - { - return true; - } - else - { - return false; - } + // The new exception handling sets the ranges always to the SP of the unwound frame + return (sfLowerBound < csfToCheck) && (csfToCheck <= sfUpperBound); } // Returns a bool indicating if the specified CrawlFrame has been unwound by the active exception. @@ -6754,229 +6067,29 @@ bool ExceptionTracker::HasFrameBeenUnwoundByAnyActiveException(CrawlFrame * pCF) Thread * pTargetThread = pCF->pThread; bool fHasFrameBeenUnwound = false; - if (g_isNewExceptionHandlingEnabled) { + CallerStackFrame csfToCheck; + if (pCF->IsFrameless()) { - CallerStackFrame csfToCheck; - if (pCF->IsFrameless()) - { - csfToCheck = CallerStackFrame::FromRegDisplay(pCF->GetRegisterSet()); - } - else - { - csfToCheck = CallerStackFrame((UINT_PTR)pCF->GetFrame()); - } - STRESS_LOG4(LF_EH|LF_GCROOTS, LL_INFO100, "CrawlFrame (%p): Frameless: %s %s: %p\n", - pCF, pCF->IsFrameless() ? "Yes" : "No", pCF->IsFrameless() ? "CallerSP" : "Address", csfToCheck.SP); + csfToCheck = CallerStackFrame::FromRegDisplay(pCF->GetRegisterSet()); } - - PTR_ExInfo pTopExInfo = (PTR_ExInfo)pTargetThread->GetExceptionState()->GetCurrentExceptionTracker(); - for (PTR_ExInfo pCurrentExInfo = pTopExInfo; pCurrentExInfo != NULL; pCurrentExInfo = dac_cast(pCurrentExInfo->m_pPrevNestedInfo)) + else { - STRESS_LOG2(LF_EH|LF_GCROOTS, LL_INFO100, "Checking lower bound %p, upper bound %p\n", (void*)pCurrentExInfo->m_ScannedStackRange.GetLowerBound().SP, (void*)pCurrentExInfo->m_ScannedStackRange.GetUpperBound().SP); - if (ExceptionTracker::IsInStackRegionUnwoundBySpecifiedException(pCF, (PTR_ExceptionTrackerBase)pCurrentExInfo)) - { - fHasFrameBeenUnwound = true; - break; - } + csfToCheck = CallerStackFrame((UINT_PTR)pCF->GetFrame()); } - - if (fHasFrameBeenUnwound) - STRESS_LOG0(LF_EH|LF_GCROOTS, LL_INFO100, "Has already been unwound\n"); - - return fHasFrameBeenUnwound; + STRESS_LOG4(LF_EH|LF_GCROOTS, LL_INFO100, "CrawlFrame (%p): Frameless: %s %s: %p\n", + pCF, pCF->IsFrameless() ? "Yes" : "No", pCF->IsFrameless() ? "CallerSP" : "Address", csfToCheck.SP); } - PTR_ExceptionTracker pTopTracker = (PTR_ExceptionTracker)pTargetThread->GetExceptionState()->GetCurrentExceptionTracker(); - PTR_ExceptionTracker pCurrentTracker = pTopTracker; - - while (pCurrentTracker != NULL) + PTR_ExInfo pTopExInfo = (PTR_ExInfo)pTargetThread->GetExceptionState()->GetCurrentExceptionTracker(); + for (PTR_ExInfo pCurrentExInfo = pTopExInfo; pCurrentExInfo != NULL; pCurrentExInfo = dac_cast(pCurrentExInfo->m_pPrevNestedInfo)) { - bool fSkipCurrentTracker = false; - - // The tracker must be in the second pass, and its stack range must not be empty. - if (pCurrentTracker->IsInFirstPass() || - pCurrentTracker->m_ScannedStackRange.IsEmpty()) - { - fSkipCurrentTracker = true; - } - - if (!fSkipCurrentTracker) + STRESS_LOG2(LF_EH|LF_GCROOTS, LL_INFO100, "Checking lower bound %p, upper bound %p\n", (void*)pCurrentExInfo->m_ScannedStackRange.GetLowerBound().SP, (void*)pCurrentExInfo->m_ScannedStackRange.GetUpperBound().SP); + if (ExceptionTracker::IsInStackRegionUnwoundBySpecifiedException(pCF, (PTR_ExceptionTrackerBase)pCurrentExInfo)) { - CallerStackFrame csfToCheck; - bool fFrameless = false; - if (pCF->IsFrameless()) - { - csfToCheck = CallerStackFrame::FromRegDisplay(pCF->GetRegisterSet()); - fFrameless = true; - } - else - { - csfToCheck = CallerStackFrame((UINT_PTR)pCF->GetFrame()); - } - - STRESS_LOG4(LF_EH|LF_GCROOTS, LL_INFO100, "CrawlFrame (%p): Frameless: %s %s: %p\n", - pCF, fFrameless ? "Yes" : "No", fFrameless ? "CallerSP" : "Address", csfToCheck.SP); - - StackFrame sfLowerBound = pCurrentTracker->m_ScannedStackRange.GetLowerBound(); - StackFrame sfUpperBound = pCurrentTracker->m_ScannedStackRange.GetUpperBound(); - StackFrame sfCurrentEstablisherFrame = pCurrentTracker->GetCurrentEstablisherFrame(); - StackFrame sfLastUnwoundEstablisherFrame = pCurrentTracker->GetLastUnwoundEstablisherFrame(); - - STRESS_LOG4(LF_EH|LF_GCROOTS, LL_INFO100, "LowerBound/UpperBound/CurrentEstablisherFrame/LastUnwoundManagedFrame: %p/%p/%p/%p\n", - sfLowerBound.SP, sfUpperBound.SP, sfCurrentEstablisherFrame.SP, sfLastUnwoundEstablisherFrame.SP); - - // Refer to the detailed comment in ExceptionTracker::IsInStackRegionUnwoundBySpecifiedException on the nature - // of this check. - // -#ifndef STACK_RANGE_BOUNDS_ARE_CALLER_SP - if ((sfLowerBound < csfToCheck) && (csfToCheck <= sfUpperBound)) -#else // !STACK_RANGE_BOUNDS_ARE_CALLER_SP - if ((sfLowerBound <= csfToCheck) && (csfToCheck < sfUpperBound)) -#endif // STACK_RANGE_BOUNDS_ARE_CALLER_SP - { - fHasFrameBeenUnwound = true; - break; - } - - // - // The frame in question was not found to be covered by the scanned stack range of the exception tracker. - // If the frame is managed, then it is possible that it forms the upper bound of the scanned stack range. - // - // The scanned stack range is updated by our personality routine once ExceptionTracker::ProcessOSExceptionNotification is invoked. - // However, it is possible that we have unwound a frame and returned back to the OS (in preemptive mode) and: - // - // 1) Either our personality routine has been invoked for the subsequent upstack managed frame but it has not yet got a chance to update - // the scanned stack range, OR - // 2) We have simply returned to the kernel exception dispatch and yet to be invoked for a subsequent frame. - // - // In such a window, if we have been asked to check if the frame forming the upper bound of the scanned stack range has been unwound, or not, - // then do the needful validations. - // - // This is applicable to managed frames only. - if (fFrameless) - { -#ifndef STACK_RANGE_BOUNDS_ARE_CALLER_SP - // On X64, if the SP of the managed frame indicates that the frame is forming the upper bound, - // then: - // - // For case (1) above, sfCurrentEstablisherFrame will be the same as the callerSP of the managed frame. - // For case (2) above, sfLastUnwoundEstablisherFrame would be the same as the managed frame's SP (or upper bound) - // - // For these scenarios, the frame is considered unwound. - - // For most cases which satisfy above condition GetRegdisplaySP(pCF->GetRegisterSet()) will be equal to sfUpperBound.SP. - // However, frames where Sp is modified after prolog ( eg. localloc) this might not be the case. For those scenarios, - // we need to check if sfUpperBound.SP is in between GetRegdisplaySP(pCF->GetRegisterSet()) & callerSp. - if (GetRegdisplaySP(pCF->GetRegisterSet()) <= sfUpperBound.SP && sfUpperBound < csfToCheck) - { - if (csfToCheck == sfCurrentEstablisherFrame) - { - fHasFrameBeenUnwound = true; - break; - } - else if (sfUpperBound == sfLastUnwoundEstablisherFrame) - { - fHasFrameBeenUnwound = true; - break; - } - } -#else // !STACK_RANGE_BOUNDS_ARE_CALLER_SP - // On ARM, if the callerSP of the managed frame is the same as upper bound, then: - // - // For case (1), sfCurrentEstablisherFrame will be above the callerSP of the managed frame (since EstablisherFrame is the caller SP for a given frame on ARM) - // For case (2), upper bound will be the same as LastUnwoundEstablisherFrame. - // - // For these scenarios, the frame is considered unwound. - if (sfUpperBound == csfToCheck) - { - if (csfToCheck < sfCurrentEstablisherFrame) - { - fHasFrameBeenUnwound = true; - break; - } - else if (sfLastUnwoundEstablisherFrame == sfUpperBound) - { - fHasFrameBeenUnwound = true; - break; - } - } -#endif // STACK_RANGE_BOUNDS_ARE_CALLER_SP - } - - // The frame in question does not appear in the current tracker's scanned stack range (of managed frames). - // If the frame is an explicit frame, then check if it equal to (or greater) than the initial explicit frame - // of the tracker. We can do this equality comparison because explicit frames are stack allocated. - // - // Do keep in mind that InitialExplicitFrame is only set in the 2nd (unwind) pass, which works - // fine for the purpose of this method since it operates on exception trackers in the second pass only. - if (!fFrameless) - { - PTR_Frame pInitialExplicitFrame = pCurrentTracker->GetInitialExplicitFrame(); - PTR_Frame pLimitFrame = pCurrentTracker->GetLimitFrame(); - -#if !defined(DACCESS_COMPILE) - STRESS_LOG2(LF_EH|LF_GCROOTS, LL_INFO100, "InitialExplicitFrame: %p, LimitFrame: %p\n", pInitialExplicitFrame, pLimitFrame); -#endif // !defined(DACCESS_COMPILE) - - // Ideally, we would like to perform a comparison check to determine if the - // frame has been unwound. This, however, is based upon the premise that - // each explicit frame that is added to the frame chain is at a lower - // address than this predecessor. - // - // This works for frames across function calls but if we have multiple - // explicit frames in the same function, then the compiler is free to - // assign an address it deems fit. Thus, its totally possible for a - // frame at the head of the frame chain to be at a higher address than - // its predecessor. This has been observed to be true with VC++ compiler - // in the CLR ret build. - // - // To address this, we loop starting from the InitialExplicitFrame until we reach - // the LimitFrame. Since all frames starting from the InitialExplicitFrame, and prior - // to the LimitFrame, have been unwound, we break out of the loop if we find - // the frame we are looking for, setting a flag indicating that the frame in question - // was unwound. - - /*if ((sfInitialExplicitFrame <= csfToCheck) && (csfToCheck < sfLimitFrame)) - { - // The explicit frame falls in the range of explicit frames unwound by this tracker. - fHasFrameBeenUnwound = true; - break; - }*/ - - // The pInitialExplicitFrame can be NULL on Unix right after we've unwound a sequence - // of native frames in the second pass of exception unwinding, since the pInitialExplicitFrame - // is cleared to make sure that it doesn't point to a frame that was destroyed during the - // native frames unwinding. At that point, the csfToCheck could not have been unwound, - // so we don't need to do any check. - if (pInitialExplicitFrame != NULL) - { - PTR_Frame pFrameToCheck = (PTR_Frame)csfToCheck.SP; - PTR_Frame pCurrentFrame = pInitialExplicitFrame; - - { - while((pCurrentFrame != FRAME_TOP) && (pCurrentFrame != pLimitFrame)) - { - if (pCurrentFrame == pFrameToCheck) - { - fHasFrameBeenUnwound = true; - break; - } - - pCurrentFrame = pCurrentFrame->PtrNextFrame(); - } - } - - if (fHasFrameBeenUnwound == true) - { - break; - } - } - } + fHasFrameBeenUnwound = true; + break; } - - // Move to the next (previous) tracker - pCurrentTracker = (PTR_ExceptionTracker)pCurrentTracker->GetPreviousExceptionTracker(); } if (fHasFrameBeenUnwound) @@ -7253,80 +6366,22 @@ StackFrame ExceptionTracker::FindParentStackFrameHelper(CrawlFrame* pCF, } } - if (g_isNewExceptionHandlingEnabled) + for (PTR_ExInfo pCurrentExInfo = (PTR_ExInfo)pThread->GetExceptionState()->GetCurrentExceptionTracker(); + pCurrentExInfo != NULL; + pCurrentExInfo = (PTR_ExInfo)pCurrentExInfo->m_pPrevNestedInfo) { - for (PTR_ExInfo pCurrentExInfo = (PTR_ExInfo)pThread->GetExceptionState()->GetCurrentExceptionTracker(); - pCurrentExInfo != NULL; - pCurrentExInfo = (PTR_ExInfo)pCurrentExInfo->m_pPrevNestedInfo) - { - // Check if the ExInfo has just been created. - if (pCurrentExInfo->m_ScannedStackRange.IsEmpty()) - { - continue; - } - - CallerStackFrame csfFunclet = pCurrentExInfo->m_csfEHClause; - if (csfCurrent == csfFunclet) - { - sfResult = (StackFrame)pCurrentExInfo->m_csfEnclosingClause; - break; - } - } - - goto lExit; - } - - for (pCurrentTracker = (PTR_ExceptionTracker)pThread->GetExceptionState()->m_pCurrentTracker; - pCurrentTracker != NULL; - pCurrentTracker = (PTR_ExceptionTracker)pCurrentTracker->m_pPrevNestedInfo) - { - // Check if the tracker has just been created. - if (pCurrentTracker->m_ScannedStackRange.IsEmpty()) + // Check if the ExInfo has just been created. + if (pCurrentExInfo->m_ScannedStackRange.IsEmpty()) { continue; } - // Since the current frame is a non-filter funclet, determine if its caller is the same one - // as was saved against the exception tracker before the funclet was invoked in ExceptionTracker::CallHandler. - CallerStackFrame csfFunclet = pCurrentTracker->m_EHClauseInfo.GetCallerStackFrameForEHClause(); + CallerStackFrame csfFunclet = pCurrentExInfo->m_csfEHClause; if (csfCurrent == csfFunclet) { - // The EnclosingClauseCallerSP is initialized in ExceptionTracker::ProcessManagedCallFrame, just before - // invoking the funclets. Basically, we are using the SP of the caller of the frame containing the funclet - // to determine if we have reached the frame containing the funclet. - EnclosingClauseInfo srcEnclosingClause = (fForGCReporting) ? pCurrentTracker->m_EnclosingClauseInfoForGCReporting - : pCurrentTracker->m_EnclosingClauseInfo; - sfResult = (StackFrame)(CallerStackFrame(srcEnclosingClause.GetEnclosingClauseCallerSP())); - - // Check whether the tracker has called any funclet yet. - if (sfResult.IsNull()) - { - continue; - } - - // Set the relevant information. - if (pfRealParent != NULL) - { - *pfRealParent = !srcEnclosingClause.EnclosingClauseIsFunclet(); - } - if (pParentOffset != NULL) - { - *pParentOffset = srcEnclosingClause.GetEnclosingClauseOffset(); - } - + sfResult = (StackFrame)pCurrentExInfo->m_csfEnclosingClause; break; } - // Check if this tracker was collapsed with another tracker and if caller of funclet clause for collapsed exception tracker matches. - else if (fForGCReporting && !(pCurrentTracker->m_csfEHClauseOfCollapsedTracker.IsNull()) && csfCurrent == pCurrentTracker->m_csfEHClauseOfCollapsedTracker) - { - EnclosingClauseInfo srcEnclosingClause = pCurrentTracker->m_EnclosingClauseInfoOfCollapsedTracker; - sfResult = (StackFrame)(CallerStackFrame(srcEnclosingClause.GetEnclosingClauseCallerSP())); - - _ASSERTE(!sfResult.IsNull()); - - break; - - } } lExit: ; diff --git a/src/coreclr/vm/fcall.cpp b/src/coreclr/vm/fcall.cpp index 8dc242e934db0e..a3aa1d37368c58 100644 --- a/src/coreclr/vm/fcall.cpp +++ b/src/coreclr/vm/fcall.cpp @@ -42,10 +42,8 @@ NOINLINE LPVOID __FCThrow(LPVOID __me, RuntimeExceptionKind reKind, UINT resID, !"Don't throw kExecutionEngineException from here. Go to EEPolicy directly, or throw something better."); #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled) - { - DispatchManagedException(reKind); - } + DispatchManagedException(reKind); + #endif // FEATURE_EH_FUNCLETS if (resID == 0) diff --git a/src/coreclr/vm/fcall.h b/src/coreclr/vm/fcall.h index f51bf44c9d7aec..79e88dc399e5ca 100644 --- a/src/coreclr/vm/fcall.h +++ b/src/coreclr/vm/fcall.h @@ -567,9 +567,8 @@ LPVOID __FCThrow(LPVOID me, enum RuntimeExceptionKind reKind, UINT resID, LPCWST HELPER_METHOD_FRAME_BEGIN_EX_BODY(ret, helperFrame, gcpoll, allowGC) \ /* TODO TURN THIS ON!!! */ \ /* gcpoll; */ \ - if (g_isNewExceptionHandlingEnabled) __helperframe.Push(); \ + __helperframe.Push(); \ INSTALL_MANAGED_EXCEPTION_DISPATCHER; \ - if (!g_isNewExceptionHandlingEnabled) __helperframe.Push(); \ MAKE_CURRENT_THREAD_AVAILABLE_EX(__helperframe.GetThread()); \ INSTALL_UNWIND_AND_CONTINUE_HANDLER_FOR_HMF(&__helperframe); @@ -602,9 +601,8 @@ LPVOID __FCThrow(LPVOID me, enum RuntimeExceptionKind reKind, UINT resID, LPCWST #define HELPER_METHOD_FRAME_END_EX(gcpoll,allowGC) \ UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; \ - if (!g_isNewExceptionHandlingEnabled) __helperframe.Pop(); \ UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; \ - if (g_isNewExceptionHandlingEnabled) __helperframe.Pop(); \ + __helperframe.Pop(); \ HELPER_METHOD_FRAME_END_EX_BODY(gcpoll,allowGC); #define HELPER_METHOD_FRAME_END_EX_NOTHROW(gcpoll,allowGC) \ diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 58773f88bb04aa..17f6172aecbf26 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1522,46 +1522,44 @@ HCIMPL1(void, IL_Throw, Object* obj) OBJECTREF oref = ObjectToOBJECTREF(obj); #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled) - { - Thread *pThread = GetThread(); - SoftwareExceptionFrame exceptionFrame; - RtlCaptureContext(exceptionFrame.GetContext()); - exceptionFrame.InitAndLink(pThread); + Thread *pThread = GetThread(); - FC_CAN_TRIGGER_GC(); + SoftwareExceptionFrame exceptionFrame; + RtlCaptureContext(exceptionFrame.GetContext()); + exceptionFrame.InitAndLink(pThread); - if (oref == 0) - DispatchManagedException(kNullReferenceException); - else - if (!IsException(oref->GetMethodTable())) - { - GCPROTECT_BEGIN(oref); + FC_CAN_TRIGGER_GC(); + + if (oref == 0) + DispatchManagedException(kNullReferenceException); + else + if (!IsException(oref->GetMethodTable())) + { + GCPROTECT_BEGIN(oref); + + WrapNonCompliantException(&oref); - WrapNonCompliantException(&oref); + GCPROTECT_END(); + } + else + { // We know that the object derives from System.Exception - GCPROTECT_END(); + // If the flag indicating ForeignExceptionRaise has been set, + // then do not clear the "_stackTrace" field of the exception object. + if (pThread->GetExceptionState()->IsRaisingForeignException()) + { + ((EXCEPTIONREF)oref)->SetStackTraceString(NULL); } else - { // We know that the object derives from System.Exception - - // If the flag indicating ForeignExceptionRaise has been set, - // then do not clear the "_stackTrace" field of the exception object. - if (pThread->GetExceptionState()->IsRaisingForeignException()) - { - ((EXCEPTIONREF)oref)->SetStackTraceString(NULL); - } - else - { - ((EXCEPTIONREF)oref)->ClearStackTracePreservingRemoteStackTrace(); - } + { + ((EXCEPTIONREF)oref)->ClearStackTracePreservingRemoteStackTrace(); } - - DispatchManagedException(oref, exceptionFrame.GetContext()); - FC_CAN_TRIGGER_GC_END(); - UNREACHABLE(); } + + DispatchManagedException(oref, exceptionFrame.GetContext()); + FC_CAN_TRIGGER_GC_END(); + UNREACHABLE(); #endif // FEATURE_EH_FUNCLETS HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_EXCEPTION); // Set up a frame @@ -1612,36 +1610,33 @@ HCIMPL0(void, IL_Rethrow) FC_GC_POLL_NOT_NEEDED(); // throws always open up for GC #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled) - { - Thread *pThread = GetThread(); + Thread *pThread = GetThread(); - SoftwareExceptionFrame exceptionFrame; - RtlCaptureContext(exceptionFrame.GetContext()); - exceptionFrame.InitAndLink(pThread); + SoftwareExceptionFrame exceptionFrame; + RtlCaptureContext(exceptionFrame.GetContext()); + exceptionFrame.InitAndLink(pThread); - ExInfo *pActiveExInfo = (ExInfo*)pThread->GetExceptionState()->GetCurrentExceptionTracker(); + ExInfo *pActiveExInfo = (ExInfo*)pThread->GetExceptionState()->GetCurrentExceptionTracker(); - ExInfo exInfo(pThread, pActiveExInfo->m_ptrs.ExceptionRecord, exceptionFrame.GetContext(), ExKind::None); + ExInfo exInfo(pThread, pActiveExInfo->m_ptrs.ExceptionRecord, exceptionFrame.GetContext(), ExKind::None); - FC_CAN_TRIGGER_GC(); + FC_CAN_TRIGGER_GC(); - GCPROTECT_BEGIN(exInfo.m_exception); - PREPARE_NONVIRTUAL_CALLSITE(METHOD__EH__RH_RETHROW); - DECLARE_ARGHOLDER_ARRAY(args, 2); + GCPROTECT_BEGIN(exInfo.m_exception); + PREPARE_NONVIRTUAL_CALLSITE(METHOD__EH__RH_RETHROW); + DECLARE_ARGHOLDER_ARRAY(args, 2); - args[ARGNUM_0] = PTR_TO_ARGHOLDER(pActiveExInfo); - args[ARGNUM_1] = PTR_TO_ARGHOLDER(&exInfo); + args[ARGNUM_0] = PTR_TO_ARGHOLDER(pActiveExInfo); + args[ARGNUM_1] = PTR_TO_ARGHOLDER(&exInfo); - pThread->IncPreventAbort(); + pThread->IncPreventAbort(); - //Ex.RhRethrow(ref ExInfo activeExInfo, ref ExInfo exInfo) - CALL_MANAGED_METHOD_NORET(args) - GCPROTECT_END(); + //Ex.RhRethrow(ref ExInfo activeExInfo, ref ExInfo exInfo) + CALL_MANAGED_METHOD_NORET(args) + GCPROTECT_END(); - FC_CAN_TRIGGER_GC_END(); - UNREACHABLE(); - } + FC_CAN_TRIGGER_GC_END(); + UNREACHABLE(); #endif HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_EXCEPTION); // Set up a frame diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 6277c7f26fb305..2792c289ebd780 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -2713,12 +2713,9 @@ extern "C" PCODE STDCALL PreStubWorker(TransitionBlock* pTransitionBlock, Method } EX_CATCH { - if (g_isNewExceptionHandlingEnabled) - { - OBJECTHANDLE ohThrowable = CURRENT_THREAD->LastThrownObjectHandle(); - _ASSERTE(ohThrowable); - StackTraceInfo::AppendElement(ohThrowable, 0, (UINT_PTR)pTransitionBlock, pMD, NULL); - } + OBJECTHANDLE ohThrowable = CURRENT_THREAD->LastThrownObjectHandle(); + _ASSERTE(ohThrowable); + StackTraceInfo::AppendElement(ohThrowable, 0, (UINT_PTR)pTransitionBlock, pMD, NULL); EX_RETHROW; } EX_END_CATCH(SwallowAllExceptions) diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp index 4889972ad18913..6e5ae608e26968 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp +++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp @@ -8085,7 +8085,7 @@ StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_D } #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled && !pCf->IsFrameless() && InlinedCallFrame::FrameHasActiveCall(pCf->GetFrame())) + if (!pCf->IsFrameless() && InlinedCallFrame::FrameHasActiveCall(pCf->GetFrame())) { // Skip new exception handling helpers InlinedCallFrame *pInlinedCallFrame = dac_cast(pCf->GetFrame()); diff --git a/src/coreclr/vm/stackwalk.cpp b/src/coreclr/vm/stackwalk.cpp index 8445fe5110686a..1a264c3214b1c2 100644 --- a/src/coreclr/vm/stackwalk.cpp +++ b/src/coreclr/vm/stackwalk.cpp @@ -1081,10 +1081,8 @@ BOOL StackFrameIterator::Init(Thread * pThread, #endif // ELIMINATE_FEF #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled) - { - m_pNextExInfo = (PTR_ExInfo)pThread->GetExceptionState()->GetCurrentExceptionTracker(); - } + + m_pNextExInfo = (PTR_ExInfo)pThread->GetExceptionState()->GetCurrentExceptionTracker(); #endif // FEATURE_EH_FUNCLETS // @@ -1555,14 +1553,8 @@ StackWalkAction StackFrameIterator::Filter(void) #if defined(FEATURE_EH_FUNCLETS) ExceptionTracker* pTracker = NULL; ExInfo* pExInfo = NULL; - if (g_isNewExceptionHandlingEnabled) - { - pExInfo = (PTR_ExInfo)m_crawl.pThread->GetExceptionState()->GetCurrentExceptionTracker(); - } - else - { - pTracker = (PTR_ExceptionTracker)m_crawl.pThread->GetExceptionState()->GetCurrentExceptionTracker(); - } + + pExInfo = (PTR_ExInfo)m_crawl.pThread->GetExceptionState()->GetCurrentExceptionTracker(); fRecheckCurrentFrame = false; fSkipFuncletCallback = true; @@ -1795,15 +1787,12 @@ StackWalkAction StackFrameIterator::Filter(void) m_sfParent = m_sfIntermediaryFuncletParent; fSkipFuncletCallback = false; - if (g_isNewExceptionHandlingEnabled) + if (!ExecutionManager::IsManagedCode(GetIP(m_crawl.GetRegisterSet()->pCallerContext))) { - if (!ExecutionManager::IsManagedCode(GetIP(m_crawl.GetRegisterSet()->pCallerContext))) - { - // Initiate force reporting of references in the new managed exception handling code frames. - // These frames are still alive when we are in a finally funclet. - m_forceReportingWhileSkipping = ForceGCReportingStage::LookForManagedFrame; - STRESS_LOG0(LF_GCROOTS, LL_INFO100, "STACKWALK: Setting m_forceReportingWhileSkipping = ForceGCReportingStage::LookForManagedFrame while processing filter funclet\n"); - } + // Initiate force reporting of references in the new managed exception handling code frames. + // These frames are still alive when we are in a finally funclet. + m_forceReportingWhileSkipping = ForceGCReportingStage::LookForManagedFrame; + STRESS_LOG0(LF_GCROOTS, LL_INFO100, "STACKWALK: Setting m_forceReportingWhileSkipping = ForceGCReportingStage::LookForManagedFrame while processing filter funclet\n"); } } } @@ -1844,27 +1833,24 @@ StackWalkAction StackFrameIterator::Filter(void) // can use it. m_sfParent = m_sfFuncletParent; - if (g_isNewExceptionHandlingEnabled) + if (!m_fFoundFirstFunclet && (pExInfo > (void*)GetRegdisplaySP(m_crawl.GetRegisterSet())) && ((void*)m_sfParent.SP > pExInfo)) { - if (!m_fFoundFirstFunclet && (pExInfo > (void*)GetRegdisplaySP(m_crawl.GetRegisterSet())) && ((void*)m_sfParent.SP > pExInfo)) - { - // For the first funclet we encounter below the topmost ExInfo that has a parent above that ExInfo - // (so it is an exceptionally called funclet for the exception represented by the ExInfo), - // we instruct the GC scanning of the frame - // to save information on the funclet so that we can use it to report references in the parent frame if - // no such funclet is found in future GC scans for the same exception. - _ASSERTE(pExInfo != NULL); - m_crawl.fShouldSaveFuncletInfo = true; - m_fFoundFirstFunclet = true; - } + // For the first funclet we encounter below the topmost ExInfo that has a parent above that ExInfo + // (so it is an exceptionally called funclet for the exception represented by the ExInfo), + // we instruct the GC scanning of the frame + // to save information on the funclet so that we can use it to report references in the parent frame if + // no such funclet is found in future GC scans for the same exception. + _ASSERTE(pExInfo != NULL); + m_crawl.fShouldSaveFuncletInfo = true; + m_fFoundFirstFunclet = true; + } - if (!fFrameWasUnwound && !ExecutionManager::IsManagedCode(GetIP(m_crawl.GetRegisterSet()->pCallerContext))) - { - // Initiate force reporting of references in the new managed exception handling code frames. - // These frames are still alive when we are in a finally funclet. - m_forceReportingWhileSkipping = ForceGCReportingStage::LookForManagedFrame; - STRESS_LOG0(LF_GCROOTS, LL_INFO100, "STACKWALK: Setting m_forceReportingWhileSkipping = ForceGCReportingStage::LookForManagedFrame\n"); - } + if (!fFrameWasUnwound && !ExecutionManager::IsManagedCode(GetIP(m_crawl.GetRegisterSet()->pCallerContext))) + { + // Initiate force reporting of references in the new managed exception handling code frames. + // These frames are still alive when we are in a finally funclet. + m_forceReportingWhileSkipping = ForceGCReportingStage::LookForManagedFrame; + STRESS_LOG0(LF_GCROOTS, LL_INFO100, "STACKWALK: Setting m_forceReportingWhileSkipping = ForceGCReportingStage::LookForManagedFrame\n"); } // For non-filter funclets, we will make the callback for the funclet @@ -2029,11 +2015,8 @@ StackWalkAction StackFrameIterator::Filter(void) // check if the parent frame of the funclet is also handling an exception. if it is, then we will need to // report roots for it since the catch handler may use references inside it. - if (g_isNewExceptionHandlingEnabled) - { - STRESS_LOG2(LF_GCROOTS, LL_INFO100, - "STACKWALK: Reached parent of funclet which didn't report GC roots, since funclet is already unwound, pExInfo->m_sfCallerOfActualHandlerFrame=%p, m_sfFuncletParent=%p\n", (void*)pExInfo->m_sfCallerOfActualHandlerFrame.SP, (void*)m_sfFuncletParent.SP); - } + STRESS_LOG2(LF_GCROOTS, LL_INFO100, + "STACKWALK: Reached parent of funclet which didn't report GC roots, since funclet is already unwound, pExInfo->m_sfCallerOfActualHandlerFrame=%p, m_sfFuncletParent=%p\n", (void*)pExInfo->m_sfCallerOfActualHandlerFrame.SP, (void*)m_sfFuncletParent.SP); _ASSERT(pExInfo != NULL || pTracker != NULL); if ((pExInfo && pExInfo->m_sfCallerOfActualHandlerFrame == m_sfFuncletParent) || @@ -2053,28 +2036,13 @@ StackWalkAction StackFrameIterator::Filter(void) // address of catch funclet to report live GC references. m_crawl.fShouldParentFrameUseUnwindTargetPCforGCReporting = true; - if (g_isNewExceptionHandlingEnabled) - { - m_crawl.ehClauseForCatch = pExInfo->m_ClauseForCatch; - STRESS_LOG2(LF_GCROOTS, LL_INFO100, - "STACKWALK: Parent of funclet which didn't report GC roots is handling an exception" - "(EH handler range [%x, %x) ), so we need to specially report roots to ensure variables alive" - " in its handler stay live.\n", - m_crawl.ehClauseForCatch.HandlerStartPC, - m_crawl.ehClauseForCatch.HandlerEndPC); - } - else - { - // Store catch clause info. Helps retrieve IP of resume address. - m_crawl.ehClauseForCatch = pTracker->GetEHClauseForCatch(); - - STRESS_LOG3(LF_GCROOTS, LL_INFO100, - "STACKWALK: Parent of funclet which didn't report GC roots is handling an exception at 0x%p" - "(EH handler range [%x, %x) ), so we need to specially report roots to ensure variables alive" - " in its handler stay live.\n", - pTracker->GetCatchToCallPC(), m_crawl.ehClauseForCatch.HandlerStartPC, - m_crawl.ehClauseForCatch.HandlerEndPC); - } + m_crawl.ehClauseForCatch = pExInfo->m_ClauseForCatch; + STRESS_LOG2(LF_GCROOTS, LL_INFO100, + "STACKWALK: Parent of funclet which didn't report GC roots is handling an exception" + "(EH handler range [%x, %x) ), so we need to specially report roots to ensure variables alive" + " in its handler stay live.\n", + m_crawl.ehClauseForCatch.HandlerStartPC, + m_crawl.ehClauseForCatch.HandlerEndPC); } else if (!m_crawl.IsFunclet()) { @@ -2095,16 +2063,7 @@ StackWalkAction StackFrameIterator::Filter(void) "STACKWALK: Reached parent of funclet which didn't report GC roots is not a funclet, resetting m_fDidFuncletReportGCReferences to true\n"); } - if (g_isNewExceptionHandlingEnabled) - { - _ASSERTE(!ExceptionTracker::HasFrameBeenUnwoundByAnyActiveException(&m_crawl)); - } - else - { - STRESS_LOG4(LF_GCROOTS, LL_INFO100, - "Funclet didn't report references: handling frame: %p, m_sfFuncletParent = %p, is funclet: %d, skip reporting %d\n", - pTracker->GetEstablisherOfActualHandlingFrame().SP, m_sfFuncletParent.SP, m_crawl.IsFunclet(), shouldSkipReporting); - } + _ASSERTE(!ExceptionTracker::HasFrameBeenUnwoundByAnyActiveException(&m_crawl)); } m_crawl.fShouldParentToFuncletSkipReportingGCReferences = shouldSkipReporting; diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index db41b16dfd3b26..274e374f1ec650 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -959,7 +959,7 @@ BOOL Thread::ReadyForAsyncException() } #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled && IsAbortPrevented()) + if (IsAbortPrevented()) { return FALSE; } @@ -2309,11 +2309,7 @@ void Thread::HandleThreadAbort () } #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled) - { DispatchManagedException(exceptObj); - } - else #endif // FEATURE_EH_FUNCLETS { RaiseTheExceptionInternalOnly(exceptObj, FALSE); @@ -3785,20 +3781,17 @@ ThrowControlForThread( STRESS_LOG0(LF_SYNC, LL_INFO100, "ThrowControlForThread Aborting\n"); #ifdef FEATURE_EH_FUNCLETS - if (g_isNewExceptionHandlingEnabled) - { - GCX_COOP(); - EXCEPTION_RECORD exceptionRecord = {0}; - exceptionRecord.NumberParameters = MarkAsThrownByUs(exceptionRecord.ExceptionInformation); - exceptionRecord.ExceptionCode = EXCEPTION_COMPLUS; - exceptionRecord.ExceptionFlags = 0; + GCX_COOP(); - OBJECTREF throwable = ExceptionTracker::CreateThrowable(&exceptionRecord, TRUE); - pfef->GetExceptionContext()->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; - DispatchManagedException(throwable, pfef->GetExceptionContext()); - } - else + EXCEPTION_RECORD exceptionRecord = {0}; + exceptionRecord.NumberParameters = MarkAsThrownByUs(exceptionRecord.ExceptionInformation); + exceptionRecord.ExceptionCode = EXCEPTION_COMPLUS; + exceptionRecord.ExceptionFlags = 0; + + OBJECTREF throwable = ExceptionTracker::CreateThrowable(&exceptionRecord, TRUE); + pfef->GetExceptionContext()->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; + DispatchManagedException(throwable, pfef->GetExceptionContext()); #endif // FEATURE_EH_FUNCLETS { // Here we raise an exception. diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index f925258656e226..68a0d9299a62bd 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -99,7 +99,6 @@ MethodTable* g_pCastHelpers; GPTR_IMPL(MethodTable, g_pEHClass); GPTR_IMPL(MethodTable, g_pExceptionServicesInternalCallsClass); GPTR_IMPL(MethodTable, g_pStackFrameIteratorClass); -GVAL_IMPL(bool, g_isNewExceptionHandlingEnabled); #endif GVAL_IMPL_INIT(PTR_WSTR, g_EntryAssemblyPath, NULL); diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index b4a9786403492c..73572da40a49a3 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -361,7 +361,6 @@ GVAL_DECL(DWORD, g_TlsIndex); GPTR_DECL(MethodTable, g_pEHClass); GPTR_DECL(MethodTable, g_pExceptionServicesInternalCallsClass); GPTR_DECL(MethodTable, g_pStackFrameIteratorClass); -GVAL_DECL(bool, g_isNewExceptionHandlingEnabled); #endif // Full path to the managed entry assembly - stored for ease of identifying the entry asssembly for diagnostics From b495c994643c31d3757f956cb4f5d2811e7dd051 Mon Sep 17 00:00:00 2001 From: Manish Godse <61718172+mangod9@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:17:06 -0700 Subject: [PATCH 2/4] more cleanup --- .../vm/amd64/ExternalMethodFixupThunk.asm | 1 - .../vm/amd64/GenericCLRToCOMCallStubs.asm | 4 +-- src/coreclr/vm/amd64/ThePreStubAMD64.asm | 3 +- src/coreclr/vm/excep.cpp | 32 ++----------------- src/coreclr/vm/exceptionhandling.cpp | 23 ++----------- 5 files changed, 6 insertions(+), 57 deletions(-) diff --git a/src/coreclr/vm/amd64/ExternalMethodFixupThunk.asm b/src/coreclr/vm/amd64/ExternalMethodFixupThunk.asm index 58aa0b9fe3fbc1..8fba12d4c6e6c1 100644 --- a/src/coreclr/vm/amd64/ExternalMethodFixupThunk.asm +++ b/src/coreclr/vm/amd64/ExternalMethodFixupThunk.asm @@ -5,7 +5,6 @@ include include AsmConstants.inc extern ExternalMethodFixupWorker:proc - extern ProcessCLRException:proc ifdef FEATURE_READYTORUN extern DynamicHelperWorker:proc diff --git a/src/coreclr/vm/amd64/GenericCLRToCOMCallStubs.asm b/src/coreclr/vm/amd64/GenericCLRToCOMCallStubs.asm index 67d749d8e6c686..ae49ccdd78145e 100644 --- a/src/coreclr/vm/amd64/GenericCLRToCOMCallStubs.asm +++ b/src/coreclr/vm/amd64/GenericCLRToCOMCallStubs.asm @@ -8,10 +8,8 @@ include asmconstants.inc extern CLRToCOMWorker:proc -extern ProcessCLRException:proc - -NESTED_ENTRY GenericCLRToCOMCallStub, _TEXT, ProcessCLRException +NESTED_ENTRY GenericCLRToCOMCallStub, _TEXT PROLOG_WITH_TRANSITION_BLOCK 8 diff --git a/src/coreclr/vm/amd64/ThePreStubAMD64.asm b/src/coreclr/vm/amd64/ThePreStubAMD64.asm index 2be63172dcfc50..da90bbb9c0a3dc 100644 --- a/src/coreclr/vm/amd64/ThePreStubAMD64.asm +++ b/src/coreclr/vm/amd64/ThePreStubAMD64.asm @@ -5,9 +5,8 @@ include include AsmConstants.inc extern PreStubWorker:proc - extern ProcessCLRException:proc -NESTED_ENTRY ThePreStub, _TEXT, ProcessCLRException +NESTED_ENTRY ThePreStub, _TEXT PROLOG_WITH_TRANSITION_BLOCK diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index 8d546f6c6f0684..98e362f74874ec 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -6245,7 +6245,7 @@ static LONG HandleManagedFaultFilter(EXCEPTION_POINTERS* ep, LPVOID pv) return EXCEPTION_CONTINUE_SEARCH; } -void HandleManagedFaultNew(EXCEPTION_RECORD* pExceptionRecord, CONTEXT* pContext) +void HandleManagedFault(EXCEPTION_RECORD* pExceptionRecord, CONTEXT* pContext) { WRAPPER_NO_CONTRACT; @@ -6280,34 +6280,6 @@ void HandleManagedFaultNew(EXCEPTION_RECORD* pExceptionRecord, CONTEXT* pContext GCPROTECT_END(); } -void HandleManagedFault(EXCEPTION_RECORD* pExceptionRecord, CONTEXT* pContext) -{ - WRAPPER_NO_CONTRACT; - - // Ok. Now we have a brand new fault in jitted code. - FaultingExceptionFrame fef; - FaultingExceptionFrame *frame = &fef; - frame->InitAndLink(pContext); - - HandleManagedFaultFilterParam param; - param.fFilterExecuted = FALSE; - param.pOriginalExceptionRecord = pExceptionRecord; - - PAL_TRY(HandleManagedFaultFilterParam *, pParam, ¶m) - { - GetThread()->SetThreadStateNC(Thread::TSNC_DebuggerIsManagedException); - - EXCEPTION_RECORD *pRecord = pParam->pOriginalExceptionRecord; - - RaiseException(pRecord->ExceptionCode, 0, - pRecord->NumberParameters, pRecord->ExceptionInformation); - } - PAL_EXCEPT_FILTER(HandleManagedFaultFilter) - { - } - PAL_ENDTRY -} - #endif // USE_FEF && !TARGET_UNIX // @@ -7237,7 +7209,7 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) // // HandleManagedFault may never return, so we cannot use a forbid fault region around it. // - HandleManagedFaultNew(pExceptionInfo->ExceptionRecord, pExceptionInfo->ContextRecord); + HandleManagedFault(pExceptionInfo->ExceptionRecord, pExceptionInfo->ContextRecord); return EXCEPTION_CONTINUE_EXECUTION; } #endif // FEATURE_EH_FUNCLETS diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 628e4254954c00..c17ce4b348f364 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -914,7 +914,7 @@ static void PopExplicitFrames(Thread *pThread, void *targetSp, void *targetCalle } EXTERN_C EXCEPTION_DISPOSITION -ProcessCLRExceptionNew(IN PEXCEPTION_RECORD pExceptionRecord, +ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord, IN PVOID pEstablisherFrame, IN OUT PCONTEXT pContextRecord, IN OUT PDISPATCHER_CONTEXT pDispatcherContext @@ -934,8 +934,7 @@ ProcessCLRExceptionNew(IN PEXCEPTION_RECORD pExceptionRecord, // There is nothing to do for those with the new exception handling. // Also skip all frames when processing unhandled exceptions. That allows them to reach the host app // level and let 3rd party the chance to handle them. - if (!ExecutionManager::IsManagedCode((PCODE)pDispatcherContext->ControlPc) || - pThread->HasThreadStateNC(Thread::TSNC_ProcessedUnhandledException)) + if (pThread->HasThreadStateNC(Thread::TSNC_ProcessedUnhandledException)) { return ExceptionContinueSearch; } @@ -983,24 +982,6 @@ ProcessCLRExceptionNew(IN PEXCEPTION_RECORD pExceptionRecord, UNREACHABLE(); } -EXTERN_C EXCEPTION_DISPOSITION -ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord, - IN PVOID pEstablisherFrame, - IN OUT PCONTEXT pContextRecord, - IN OUT PDISPATCHER_CONTEXT pDispatcherContext - ) -{ - // - // This method doesn't always return, so it will leave its - // state on the thread if using dynamic contracts. - // - STATIC_CONTRACT_MODE_ANY; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_THROWS; - - return ProcessCLRExceptionNew(pExceptionRecord, pEstablisherFrame, pContextRecord, pDispatcherContext); -} - // When we hit a native exception such as an AV in managed code, we put up a FaultingExceptionFrame which saves all the // non-volatile registers. The GC may update these registers if they contain object references. However, the CONTEXT // with which we are going to resume execution doesn't have these updated values. Thus, we need to fix up the non-volatile From 9070d8ad699a3425d1ea9eb07203fec126026dcd Mon Sep 17 00:00:00 2001 From: Manish Godse <61718172+mangod9@users.noreply.github.com> Date: Mon, 31 Mar 2025 08:50:35 -0700 Subject: [PATCH 3/4] fix build break after merge. --- src/coreclr/vm/jithelpers.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index e049882cb7ff49..d66be6010f666b 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1538,10 +1538,6 @@ HCIMPL1(void, IL_Throw, Object* obj) #endif exceptionFrame.InitAndLink(pThread); - SoftwareExceptionFrame exceptionFrame; - RtlCaptureContext(exceptionFrame.GetContext()); - exceptionFrame.InitAndLink(pThread); - FC_CAN_TRIGGER_GC(); if (oref == 0) From b5dee282da5449b36b923369f68efcd5b3df9663 Mon Sep 17 00:00:00 2001 From: Manish Godse <61718172+mangod9@users.noreply.github.com> Date: Mon, 31 Mar 2025 13:48:14 -0700 Subject: [PATCH 4/4] CR feedback --- src/coreclr/vm/threadsuspend.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index d8282438ca93b4..03cfcbbdc748ec 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -2309,11 +2309,10 @@ void Thread::HandleThreadAbort () } #ifdef FEATURE_EH_FUNCLETS - DispatchManagedException(exceptObj); + DispatchManagedException(exceptObj); +#else // FEATURE_EH_FUNCLETS + RaiseTheExceptionInternalOnly(exceptObj, FALSE); #endif // FEATURE_EH_FUNCLETS - { - RaiseTheExceptionInternalOnly(exceptObj, FALSE); - } } ::SetLastError(lastError); @@ -3792,13 +3791,12 @@ ThrowControlForThread( OBJECTREF throwable = ExceptionTracker::CreateThrowable(&exceptionRecord, TRUE); pfef->GetExceptionContext()->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; DispatchManagedException(throwable, pfef->GetExceptionContext()); -#endif // FEATURE_EH_FUNCLETS - { - // Here we raise an exception. - INSTALL_MANAGED_EXCEPTION_DISPATCHER - RaiseComPlusException(); - UNINSTALL_MANAGED_EXCEPTION_DISPATCHER - } +#else // FEATURE_EH_FUNCLETS + // Here we raise an exception. + INSTALL_MANAGED_EXCEPTION_DISPATCHER + RaiseComPlusException(); + UNINSTALL_MANAGED_EXCEPTION_DISPATCHER +#endif // FEATURE_EH_FUNCLETS } #if defined(FEATURE_HIJACK) && !defined(TARGET_UNIX)