This commit is contained in:
Jan Vorlicek 2025-07-30 14:35:00 +02:00 committed by GitHub
commit f6ac207bfc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 45 additions and 35 deletions

View File

@ -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

View File

@ -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();

View File

@ -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
{

View File

@ -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)

View File

@ -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 @@ public:
LIMITED_METHOD_DAC_CONTRACT;
return TT_U2M;
}
};
bool CatchesAllExceptions()
typedef DPTR(class UnhandledExceptionMarkerFrame) PTR_UnhandledExceptionMarkerFrame;
// 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).

View File

@ -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);

View File

@ -10525,12 +10525,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
@ -10540,8 +10536,6 @@ bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
}
EX_END_CATCH
catchFrame.Pop();
return success;
}

View File

@ -7001,7 +7001,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;
@ -7056,7 +7059,8 @@ static void ManagedThreadBase_DispatchOuter(ManagedThreadCallState *pCallState)
}
PAL_FINALLY
{
catchFrame.Pop();
unhandledExceptionMarkerFrame.Pop(pThread);
catchFrame.Pop(pThread);
}
PAL_ENDTRY;
}