Skip to content

Commit

Permalink
Fix handling of corrupting state exceptions (#103048)
Browse files Browse the repository at this point in the history
* Fix handling of corrupting state exceptions

The new EH is not correctly handling corrupting state exceptions.
Instead of failing fast, the exceptions are actually handled like other
exceptions and can be caught by the user code.

This change fixes it. Besides fixing the issue, I had to introduce a way
to trim exception handling code frames from the stack trace reported by
the failfast, otherwise the output would be confusing.

As an additional change, I've noticed that hardware exceptions under
WinDbg don't trigger the WinDbg first chance exception mechanism. I've
recently fixed the same for software exceptions, this adds the same for
hardware ones.

Close #103018

* Remove the WinDbg first chance notification
  • Loading branch information
janvorli authored Jun 5, 2024
1 parent b438888 commit 43a5e4a
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 6 deletions.
30 changes: 24 additions & 6 deletions src/coreclr/vm/eepolicy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ void EEPolicy::HandleExitProcess(ShutdownCompleteAction sca)
//---------------------------------------------------------------------------------------
class CallStackLogger
{
PEXCEPTION_POINTERS m_pExceptionInfo;
// MethodDescs of the stack frames, the TOS is at index 0
CDynArray<MethodDesc*> m_frames;

Expand All @@ -175,6 +176,16 @@ class CallStackLogger
{
WRAPPER_NO_CONTRACT;

if (m_pExceptionInfo != NULL)
{
// Skip managed frames that are not part of the stack that caused the exception
// (they are part of the stack that is unwinding the exception)
if (GetRegdisplaySP(pCF->GetRegisterSet()) < GetSP(m_pExceptionInfo->ContextRecord))
{
return SWA_CONTINUE;
}
}

MethodDesc *pMD = pCF->GetFunction();

if (m_commonStartIndex != -1)
Expand Down Expand Up @@ -231,6 +242,13 @@ class CallStackLogger

public:

CallStackLogger(PEXCEPTION_POINTERS pExceptionInfo)
{
WRAPPER_NO_CONTRACT;

m_pExceptionInfo = pExceptionInfo;
}

// Callback called by the stack walker for each frame on the stack
static StackWalkAction LogCallstackForLogCallback(CrawlFrame *pCF, VOID* pData)
{
Expand Down Expand Up @@ -275,7 +293,7 @@ class CallStackLogger
// Return Value:
// None
//
inline void LogCallstackForLogWorker(Thread* pThread)
inline void LogCallstackForLogWorker(Thread* pThread, PEXCEPTION_POINTERS pExceptionInfo)
{
WRAPPER_NO_CONTRACT;

Expand All @@ -291,7 +309,7 @@ inline void LogCallstackForLogWorker(Thread* pThread)
}
WordAt.Append(W(" "));

CallStackLogger logger;
CallStackLogger logger(pExceptionInfo);

pThread->StackWalkFrames(&CallStackLogger::LogCallstackForLogCallback, &logger, QUICKUNWIND | FUNCTIONSONLY | ALLOW_ASYNC_STACK_WALK);

Expand All @@ -312,7 +330,7 @@ inline void LogCallstackForLogWorker(Thread* pThread)
// Return Value:
// None
//
void LogInfoForFatalError(UINT exitCode, LPCWSTR pszMessage, LPCWSTR errorSource, LPCWSTR argExceptionString)
void LogInfoForFatalError(UINT exitCode, LPCWSTR pszMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, LPCWSTR argExceptionString)
{
WRAPPER_NO_CONTRACT;

Expand Down Expand Up @@ -379,7 +397,7 @@ void LogInfoForFatalError(UINT exitCode, LPCWSTR pszMessage, LPCWSTR errorSource
Thread* pThread = GetThreadNULLOk();
if (pThread && errorSource == NULL)
{
LogCallstackForLogWorker(pThread);
LogCallstackForLogWorker(pThread, pExceptionInfo);

if (argExceptionString != NULL) {
PrintToStdErrW(argExceptionString);
Expand Down Expand Up @@ -407,7 +425,7 @@ void EEPolicy::LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pszMessage
_ASSERTE(pExceptionInfo != NULL);

// Log exception to StdErr
LogInfoForFatalError(exitCode, pszMessage, errorSource, argExceptionString);
LogInfoForFatalError(exitCode, pszMessage, pExceptionInfo, errorSource, argExceptionString);

if(ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context, FailFast))
{
Expand Down Expand Up @@ -579,7 +597,7 @@ void DisplayStackOverflowException()

DWORD LogStackOverflowStackTraceThread(void* arg)
{
LogCallstackForLogWorker((Thread*)arg);
LogCallstackForLogWorker((Thread*)arg, NULL);

return 0;
}
Expand Down
29 changes: 29 additions & 0 deletions src/coreclr/vm/exceptionhandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8155,6 +8155,33 @@ static BOOL CheckExceptionInterception(StackFrameIterator* pStackFrameIterator,
return isIntercepted;
}

void FailFastIfCorruptingStateException(ExInfo *pExInfo)
{
// Failfast if exception indicates corrupted process state
if (IsProcessCorruptedStateException(pExInfo->m_ExceptionCode, pExInfo->GetThrowable()))
{
OBJECTREF oThrowable = NULL;
SString message;

GCPROTECT_BEGIN(oThrowable);
oThrowable = pExInfo->GetThrowable();
if (oThrowable != NULL)
{
EX_TRY
{
GetExceptionMessage(oThrowable, message);
}
EX_CATCH
{
}
EX_END_CATCH(SwallowAllExceptions);
}
GCPROTECT_END();

EEPolicy::HandleFatalError(pExInfo->m_ExceptionCode, 0, (LPCWSTR)message, dac_cast<EXCEPTION_POINTERS*>(&pExInfo->m_ptrs));
}
}

static void NotifyExceptionPassStarted(StackFrameIterator *pThis, Thread *pThread, ExInfo *pExInfo)
{
if (pExInfo->m_passNumber == 1)
Expand Down Expand Up @@ -8295,6 +8322,8 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk
{
GCX_COOP();
UpdatePerformanceMetrics(&pThis->m_crawl, false, ((uint8_t)pExInfo->m_kind & (uint8_t)ExKind::RethrowFlag) == 0);

FailFastIfCorruptingStateException(pExInfo);
}

// Walk the stack until it finds the first managed method
Expand Down

0 comments on commit 43a5e4a

Please sign in to comment.