Skip to content

Commit

Permalink
Fix missing frame on inner exception stack trace in release build (#1…
Browse files Browse the repository at this point in the history
…05482)

There is a problem in release builds of the runtime that was discovered
by SOS tests. When an exception is thrown from reflection code, the
inner exception was missing the frame(s) from the reflection called code
on the stack trace and had them in the `_remoteStackTraceString` instead.
So getting the exception stack trace as string still worked correctly.
In checked or debug builds, it was working as expected.

It turned out that the issue was caused by the fact that when an
exception is rethrown as native one when exception unwinding reaches
native frames, it used `RealCOMPlusThrow` method. The catch was that while
in debug / checked builds it was using this method with Object*
argument, in release builds, the `OBJECTREF` and Object* are the same
thing, so the `RealCOMPlusThrow` with the explicit Object* was not
compiled and we were using the one with the OBJECTREF argument.
Unfortunately, that one has a different semantics - to save the current
stack trace into the `_remoteStackTraceString` and then building it from
scratch.

The fix was to rename the RealCOMPlusThrow version with the Object*
argument to a different name so that it can be built for release,
checked and debug builds and used for the specific purpose of
propagating managed exception through the native frames.
  • Loading branch information
janvorli authored Jul 26, 2024
1 parent ebf5da7 commit 360569f
Show file tree
Hide file tree
Showing 3 changed files with 3 additions and 5 deletions.
4 changes: 1 addition & 3 deletions src/coreclr/vm/excep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2509,8 +2509,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable)
RealCOMPlusThrow(throwable, FALSE);
}

#ifdef USE_CHECKED_OBJECTREFS
VOID DECLSPEC_NORETURN RealCOMPlusThrow(Object *exceptionObj)
VOID DECLSPEC_NORETURN PropagateExceptionThroughNativeFrames(Object *exceptionObj)
{
CONTRACTL
{
Expand All @@ -2523,7 +2522,6 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrow(Object *exceptionObj)
OBJECTREF throwable = ObjectToOBJECTREF(exceptionObj);
RealCOMPlusThrowWorker(throwable, FALSE);
}
#endif // USE_CHECKED_OBJECTREFS

// this function finds the managed callback to get a resource
// string from the then current local domain and calls it
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/excep.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowNonLocalized(RuntimeExceptionKind reKind,
//==========================================================================

VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable);
VOID DECLSPEC_NORETURN RealCOMPlusThrow(Object *exceptionObj);
VOID DECLSPEC_NORETURN PropagateExceptionThroughNativeFrames(Object *exceptionObj);

//==========================================================================
// Throw an undecorated runtime exception.
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/exceptionhandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7872,7 +7872,7 @@ extern "C" void * QCALLTYPE CallCatchFunclet(QCall::ObjectHandleOnStack exceptio
#elif defined(HOST_RISCV) || defined(HOST_LOONGARCH64)
pvRegDisplay->pCurrentContext->Ra = GetIP(pvRegDisplay->pCurrentContext);
#endif
SetIP(pvRegDisplay->pCurrentContext, (PCODE)(void (*)(Object*))RealCOMPlusThrow);
SetIP(pvRegDisplay->pCurrentContext, (PCODE)(void (*)(Object*))PropagateExceptionThroughNativeFrames);
#if defined(HOST_AMD64)
SetSP(pvRegDisplay->pCurrentContext, targetSp - 8);
#elif defined(HOST_X86)
Expand Down

0 comments on commit 360569f

Please sign in to comment.