Skip to content

Commit a142e77

Browse files
authored
Fix VS debugger issues with funceval and secondary threads (#102470)
* Fix VS debugger issues with funceval and secondary threads The VS team has recently reported two issues with the new exception handling in Visual Studio debugger. The first issue was that an unhandled exception on a secondary managed thread wasn't showing any stack trace when the exception occured and the debugger has broken in. The other issue was that when an exception occured during a funceval invoked from the immediate window, the debugger would not highlight the source line where the exception occured and it would not display a dialog with the exception details. Both problems were caused by the same underlying problem. In both cases, the "catch handler found" notification was to be sent at a point when the managed stack frames were already gone - in native code in catch / filter. In the funceval case, there was even a check that prevented sending the notification at all when there was no exception info present. The fix is to move the notification to the point where the managed stack frames are still present - when we detect in the EH code that there is no managed frame left and either the DebuggerU2MCatchHandler frame or FuncEvalFrame is the explicit frame we've encountered as the next one to process. The FuncEvalFrame case is a bit more involved, as we always push ProtectValueClassFrame after the FuncEvalFrame, so we need to skip that one in the check. The debugger actually needs to get a pointer to the FuncEvalFrame in the notification to do the right thing. Close #102178 and #101729 * Fix too strong assert The ProtectValueClassFrame can also occur without FuncEvalFrame in the reflection invocation.
1 parent e8b89a3 commit a142e77

File tree

2 files changed

+22
-2
lines changed

2 files changed

+22
-2
lines changed

src/coreclr/vm/excep.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7901,10 +7901,10 @@ LONG NotifyOfCHFFilterWrapper(
79017901
(pThread->GetExceptionState()->GetContextRecord() == NULL) ||
79027902
(GetSP(pThread->GetExceptionState()->GetContextRecord()) != GetSP(pExceptionInfo->ContextRecord) ) )
79037903
{
7904-
LOG((LF_EH, LL_INFO1000, "NotifyOfCHFFilterWrapper: not sending notices. pThread: %0x8", pThread));
7904+
LOG((LF_EH, LL_INFO1000, "NotifyOfCHFFilterWrapper: not sending notices. pThread: %p", pThread));
79057905
if (pThread)
79067906
{
7907-
LOG((LF_EH, LL_INFO1000, ", Thread SP: %0x8, Exception SP: %08x",
7907+
LOG((LF_EH, LL_INFO1000, ", Thread SP: %p, Exception SP: %p",
79087908
pThread->GetExceptionState()->GetContextRecord() ? GetSP(pThread->GetExceptionState()->GetContextRecord()) : NULL,
79097909
pExceptionInfo->ContextRecord ? GetSP(pExceptionInfo->ContextRecord) : NULL ));
79107910
}

src/coreclr/vm/exceptionhandling.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8217,6 +8217,26 @@ static void NotifyExceptionPassStarted(StackFrameIterator *pThis, Thread *pThrea
82178217
pExInfo->m_ExceptionFlags.SetUnwindHasStarted();
82188218
EEToDebuggerExceptionInterfaceWrapper::ManagedExceptionUnwindBegin(pThread);
82198219
}
8220+
else
8221+
{
8222+
// The debugger explicitly checks that the notification refers to a FuncEvalFrame in case an exception becomes unhandled in a func eval.
8223+
// We need to do the notification here before we start propagating the exception through native frames, since that will remove
8224+
// all managed frames from the stack and the debugger would not see the failure location.
8225+
if (pThis->GetFrameState() == StackFrameIterator::SFITER_FRAME_FUNCTION)
8226+
{
8227+
Frame* pFrame = pThis->m_crawl.GetFrame();
8228+
// If the frame is ProtectValueClassFrame, move to the next one as we want to report the FuncEvalFrame
8229+
if (pFrame->GetVTablePtr() == ProtectValueClassFrame::GetMethodFrameVPtr())
8230+
{
8231+
pFrame = pFrame->PtrNextFrame();
8232+
_ASSERTE(pFrame != FRAME_TOP);
8233+
}
8234+
if ((pFrame->GetVTablePtr() == FuncEvalFrame::GetMethodFrameVPtr()) || (pFrame->GetVTablePtr() == DebuggerU2MCatchHandlerFrame::GetMethodFrameVPtr()))
8235+
{
8236+
EEToDebuggerExceptionInterfaceWrapper::NotifyOfCHFFilter((EXCEPTION_POINTERS *)&pExInfo->m_ptrs, pFrame);
8237+
}
8238+
}
8239+
}
82208240
}
82218241
}
82228242

0 commit comments

Comments
 (0)