diff --git a/src/coreclr/vm/FrameTypes.h b/src/coreclr/vm/FrameTypes.h index 83a4e0aa6de455..ad59f50e0082dd 100644 --- a/src/coreclr/vm/FrameTypes.h +++ b/src/coreclr/vm/FrameTypes.h @@ -37,6 +37,7 @@ FRAME_TYPE_NAME(DebuggerClassInitMarkFrame) FRAME_TYPE_NAME(DebuggerExitFrame) FRAME_TYPE_NAME(DebuggerU2MCatchHandlerFrame) FRAME_TYPE_NAME(ExceptionFilterFrame) +FRAME_TYPE_NAME(UnhandledExceptionMarkerFrame) #ifdef FEATURE_INTERPRETER FRAME_TYPE_NAME(InterpreterFrame) #endif // FEATURE_INTERPRETER diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp index 028534a932b8a9..59d182af36ba10 100644 --- a/src/coreclr/vm/corhost.cpp +++ b/src/coreclr/vm/corhost.cpp @@ -295,6 +295,8 @@ HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId, AppDomain *pCurDomain = SystemDomain::GetCurrentDomain(); + UnhandledExceptionMarkerFrame unhandledExceptionMarkerFrame; + Thread *pThread = GetThreadNULLOk(); if (pThread == NULL) { @@ -305,6 +307,11 @@ HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId, } } + { + GCX_COOP(); + unhandledExceptionMarkerFrame.Push(pThread); + } + INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; INSTALL_UNWIND_AND_CONTINUE_HANDLER; @@ -327,7 +334,6 @@ HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId, { GCX_COOP(); - PTRARRAYREF arguments = NULL; GCPROTECT_BEGIN(arguments); @@ -359,6 +365,11 @@ HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId, UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; + { + GCX_COOP(); + unhandledExceptionMarkerFrame.Pop(pThread); + } + #ifdef LOG_EXECUTABLE_ALLOCATOR_STATISTICS ExecutableAllocator::DumpHolderUsage(); ExecutionManager::DumpExecutionManagerUsage(); diff --git a/src/coreclr/vm/dispatchinfo.cpp b/src/coreclr/vm/dispatchinfo.cpp index 6967b196927371..cfc754049d19aa 100644 --- a/src/coreclr/vm/dispatchinfo.cpp +++ b/src/coreclr/vm/dispatchinfo.cpp @@ -2168,7 +2168,7 @@ HRESULT DispatchInfo::InvokeMember(SimpleComCallWrapper *pSimpleWrap, DISPID id, // The sole purpose of having this frame is to tell the debugger that we have a catch handler here // which may swallow managed exceptions. The debugger needs this in order to send a // CatchHandlerFound (CHF) notification. - DebuggerU2MCatchHandlerFrame catchFrame(true /* catchesAllExceptions */); + DebuggerU2MCatchHandlerFrame catchFrame; EX_TRY { diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index d450d953c92f6a..5453d022e5be29 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -4013,16 +4013,17 @@ extern "C" CLR_BOOL QCALLTYPE SfiNext(StackFrameIterator* pThis, uint* uExCollid // Check if there are any further managed frames on the stack or a catch for all exceptions in native code (marked by // DebuggerU2MCatchHandlerFrame with CatchesAllExceptions() returning true). // If not, the exception is unhandled. - bool isNotHandledByRuntime = - (pFrame == FRAME_TOP) || - (IsTopmostDebuggerU2MCatchHandlerFrame(pFrame) && !((DebuggerU2MCatchHandlerFrame*)pFrame)->CatchesAllExceptions()) + bool reportUnhandledException = + ((pFrame != FRAME_TOP) && + (pFrame->GetFrameIdentifier() == FrameIdentifier::UnhandledExceptionMarkerFrame) && + IsExceptionFromManagedCode(pTopExInfo->m_ptrs.ExceptionRecord)) #ifdef HOST_UNIX // Don't allow propagating exceptions from managed to non-runtime native code || isPropagatingToExternalNativeCode #endif ; - if (isNotHandledByRuntime && IsExceptionFromManagedCode(pTopExInfo->m_ptrs.ExceptionRecord)) + if (reportUnhandledException) { EH_LOG((LL_INFO100, "SfiNext (pass %d): no more managed frames on the stack, the exception is unhandled", pTopExInfo->m_passNumber)); if (pTopExInfo->m_passNumber == 1) diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index 072613619c5fc9..09fc2ccc71c5d6 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -100,6 +100,9 @@ // +-DebuggerU2MCatchHandlerFrame - marker frame to indicate that native code is going to catch and // | swallow a managed exception // | +// +- UnhandledExceptionMarkerFrame - When exception handling passes through this frame, +// | the exception is reported as unhandled. +// | #ifdef DEBUGGING_SUPPORTED // +-FuncEvalFrame - frame for debugger function evaluation #endif // DEBUGGING_SUPPORTED @@ -2077,15 +2080,13 @@ class DebuggerU2MCatchHandlerFrame : public Frame { public: #ifndef DACCESS_COMPILE - DebuggerU2MCatchHandlerFrame(bool catchesAllExceptions) : Frame(FrameIdentifier::DebuggerU2MCatchHandlerFrame), - m_catchesAllExceptions(catchesAllExceptions) + DebuggerU2MCatchHandlerFrame() : Frame(FrameIdentifier::DebuggerU2MCatchHandlerFrame) { WRAPPER_NO_CONTRACT; Frame::Push(); } - DebuggerU2MCatchHandlerFrame(Thread * pThread, bool catchesAllExceptions) : Frame(FrameIdentifier::DebuggerU2MCatchHandlerFrame), - m_catchesAllExceptions(catchesAllExceptions) + DebuggerU2MCatchHandlerFrame(Thread * pThread) : Frame(FrameIdentifier::DebuggerU2MCatchHandlerFrame) { WRAPPER_NO_CONTRACT; Frame::Push(pThread); @@ -2097,16 +2098,19 @@ class DebuggerU2MCatchHandlerFrame : public Frame LIMITED_METHOD_DAC_CONTRACT; return TT_U2M; } +}; + +typedef DPTR(class UnhandledExceptionMarkerFrame) PTR_UnhandledExceptionMarkerFrame; - bool CatchesAllExceptions() +// When exception handling passes through this frame, the exception is reported as unhandled. +class UnhandledExceptionMarkerFrame : public Frame +{ +public: +#ifndef DACCESS_COMPILE + UnhandledExceptionMarkerFrame() : Frame(FrameIdentifier::UnhandledExceptionMarkerFrame) { - LIMITED_METHOD_DAC_CONTRACT; - return m_catchesAllExceptions; } - -private: - // The catch handled marked by the DebuggerU2MCatchHandlerFrame catches all exceptions. - bool m_catchesAllExceptions; +#endif }; // Frame for the Reverse PInvoke (i.e. UnmanagedCallersOnlyAttribute). diff --git a/src/coreclr/vm/interoplibinterface_comwrappers.cpp b/src/coreclr/vm/interoplibinterface_comwrappers.cpp index 7b984171ff6715..5500c6b64c8247 100644 --- a/src/coreclr/vm/interoplibinterface_comwrappers.cpp +++ b/src/coreclr/vm/interoplibinterface_comwrappers.cpp @@ -355,18 +355,15 @@ namespace InteropLibImports return TryInvokeICustomQueryInterfaceResult::FailedToInvoke; } - // Switch to Cooperative mode since object references - // are being manipulated and the catchFrame needs that so that it can push - // itself to the explicit frame stack. - GCX_COOP(); - // Indicate to the debugger and exception handling that managed exceptions are being caught - // here. - DebuggerU2MCatchHandlerFrame catchFrame(true /* catchesAllExceptions */); - HRESULT hr; auto result = TryInvokeICustomQueryInterfaceResult::FailedToInvoke; EX_TRY_THREAD(CURRENT_THREAD) { + // Switch to Cooperative mode since object references + // are being manipulated and the catchFrame needs that so that it can push + // itself to the explicit frame stack. + GCX_COOP(); + struct { OBJECTREF objRef; @@ -384,8 +381,6 @@ namespace InteropLibImports } EX_CATCH_HRESULT(hr); - catchFrame.Pop(); - // Assert valid value. _ASSERTE(TryInvokeICustomQueryInterfaceResult::Min <= result && result <= TryInvokeICustomQueryInterfaceResult::Max); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 1a9556a77228e7..164f43f4bf0e02 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10512,12 +10512,8 @@ bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param) bool success = true; - GCX_COOP(); - DebuggerU2MCatchHandlerFrame catchFrame(true /* catchesAllExceptions */); - EX_TRY { - GCX_PREEMP(); function(param); } EX_CATCH @@ -10527,8 +10523,6 @@ bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param) } EX_END_CATCH - catchFrame.Pop(); - return success; } diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index 1469ffe0e64453..9cc5f1877371cb 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -7069,7 +7069,10 @@ static void ManagedThreadBase_DispatchOuter(ManagedThreadCallState *pCallState) // The sole purpose of having this frame is to tell the debugger that we have a catch handler here // which may swallow managed exceptions. The debugger needs this in order to send a // CatchHandlerFound (CHF) notification. - DebuggerU2MCatchHandlerFrame catchFrame(false /* catchesAllExceptions */); + DebuggerU2MCatchHandlerFrame catchFrame(pThread); + + UnhandledExceptionMarkerFrame unhandledExceptionMarkerFrame; + unhandledExceptionMarkerFrame.Push(pThread); TryParam param(pCallState); param.pFrame = &catchFrame; @@ -7124,7 +7127,8 @@ static void ManagedThreadBase_DispatchOuter(ManagedThreadCallState *pCallState) } PAL_FINALLY { - catchFrame.Pop(); + unhandledExceptionMarkerFrame.Pop(pThread); + catchFrame.Pop(pThread); } PAL_ENDTRY; }