Remove unneeded DebuggerU2MCatchHandleFrames - #132082
Open
jkoritzinsky wants to merge 2 commits into
Open
Conversation
Now that we call into managed code from unmanaged with UCO methods with try-catch blocks around the body, the DebuggerU2MCatchHandleFrames that represent "there's a catch-all in manually managed runtime code" no longer provide benefit. This PR removes the unneeded frames. It also cleans up a bit of the usage in ComWrappers so we aren't rethrowing an exception just to immediately catch it and extract the HResult to a local (that we don't even return out anywhere).
jkoritzinsky
marked this pull request as ready for review
August 10, 2026 16:24
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
|
Tagging subscribers to this area: @agocke |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR removes several uses of DebuggerU2MCatchHandlerFrame (and related “catch-all” metadata) across CoreCLR unmanaged-to-managed transition points, and simplifies some COM/dispatch interop paths that previously used dedicated debugger/EH wrapper scaffolding.
Changes:
- Simplifies
DebuggerU2MCatchHandlerFrameby removing the “catches all exceptions” flag and updating call sites accordingly. - Removes
DebuggerU2MCatchHandlerFrameusage from JIT interface error-trap and COMIDispatchinvocation paths, including deleting theInvokeMemberDebuggerWrapperhelper. - Refactors
ComWrappersinterop invocation to avoid throw/rethrow patterns by using direct UCO invocation with an exception out-parameter.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/coreclr/vm/threads.cpp | Updates DebuggerU2MCatchHandlerFrame construction to new signature while preserving push/pop lifetime. |
| src/coreclr/vm/jitinterface.cpp | Removes debugger catch-handler frame from CEEInfo::runWithErrorTrap. |
| src/coreclr/vm/interoplibinterface_comwrappers.cpp | Switches CallICustomQueryInterface invocation to InvokeDirect_Ret with an exception out-param. |
| src/coreclr/vm/frames.h | Removes catchesAllExceptions state from DebuggerU2MCatchHandlerFrame and updates constructors. |
| src/coreclr/vm/exceptionhandling.cpp | Simplifies the “unhandled by runtime” check involving topmost DebuggerU2MCatchHandlerFrame. |
| src/coreclr/vm/dispatchinfo.h | Removes the InvokeMemberDebuggerWrapper declaration. |
| src/coreclr/vm/dispatchinfo.cpp | Removes InvokeMemberDebuggerWrapper implementation and calls InvokeMemberWorker directly. |
Suppressed comments (1)
src/coreclr/vm/frames.h:1836
- The "Notes" section a few lines above still says this frame is only used in
DispatchInfo::InvokeMember, but that usage was removed and the frame is still used elsewhere (e.g.,ManagedThreadBase_DispatchOuterinthreads.cpp). Please update/remove that note so it remains accurate.
static constexpr size_t NumObjRefs = offsetof(GCFrame, m_numObjRefs);
static constexpr size_t GCFlags = offsetof(GCFrame, m_gcFlags);
};
//-----------------------------------------------------------------------------
Comment on lines
340
to
344
| struct | ||
| { | ||
| OBJECTREF objRef; | ||
| EXCEPTIONREF exceptionRef; | ||
| } gc; |
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (2)
src/coreclr/vm/interoplibinterface_comwrappers.cpp:346
gc.exceptionRefis GC-protected but never initialized beforeGCPROTECT_BEGIN(gc). Leaving anEXCEPTIONREFuninitialized can make the GC treat arbitrary stack data as an object reference, leading to memory corruption or crashes.
struct
{
OBJECTREF objRef;
EXCEPTIONREF exceptionRef;
} gc;
gc.objRef = NULL;
src/coreclr/vm/frames.h:2017
- The class comment’s note says this frame is only used by
DispatchInfo.InvokeMember, but this PR removes that usage and the remaining usage is inManagedThreadBase_DispatchOuter(threads.cpp). Please update the note to avoid misleading future readers.
DebuggerU2MCatchHandlerFrame() : Frame(FrameIdentifier::DebuggerU2MCatchHandlerFrame)
{
WRAPPER_NO_CONTRACT;
Frame::Push();
}
This was referenced Aug 10, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Now that we call into managed code from unmanaged with UCO methods with try-catch blocks around the body, the DebuggerU2MCatchHandleFrames that represent "there's a catch-all in manually managed runtime code" no longer provide benefit.
This PR removes the unneeded frames. It also cleans up a bit of the usage in ComWrappers so we aren't rethrowing an exception just to immediately catch it and extract the HResult to a local (that we don't even return out anywhere).