Skip to content

GCRoot: Report GCFrame and in-flight exception objects#129145

Open
leculver wants to merge 4 commits into
dotnet:mainfrom
leculver:cdac-exinfo-stack-roots
Open

GCRoot: Report GCFrame and in-flight exception objects#129145
leculver wants to merge 4 commits into
dotnet:mainfrom
leculver:cdac-exinfo-stack-roots

Conversation

@leculver

@leculver leculver commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Threads' GCFrame objects were not being reported correctly as GCRoots. Similarly, an in-flight exception was also not being reported, though it typically has other roots it's just good to fix the gap.

This is my first real cdac change, so detailed feedback and nitpicks are very appreciated.

…nces

WalkStackReferences (GetStackReferences) reports the per-thread GC roots that
the GC scans in gcenv.ee.cpp ScanStackRoots. Alongside the frame references it
now also reports:

- The thread's GCFrame (GCPROTECT) chain: each GCFrame keeps a set of object
  references alive across a runtime operation. New data descriptors expose the
  chain -- Thread.GCFrame (m_pGCFrame) plus a GCFrame type
  (Next/ObjRefs/NumObjRefs/GCFlags) in vm/frames.h, vm/threads.h,
  datadescriptor.inc, and the managed Data/GCFrame.cs + DataType. The managed
  Thread.GCFrame field is optional, so a target that does not describe it is
  skipped. Interior promotion is applied when GCFlags != 0, matching
  GCFrame::GcScanRoots.

- The thread's exception-tracking (ExInfo) chain: the current in-flight
  exception plus any superseded/nested ones, via the existing
  IException.GetNestedExceptionInfo contract.

Adds two dump-based StackReferenceDumpTests with dedicated debuggees.
NestedException builds a superseded exception chain and verifies the nested
exception (reachable only through the ExInfo chain) is reported. GCProtect
crashes inside an AppDomain.AssemblyResolve handler the runtime invokes while
holding a GCPROTECT frame, and verifies a GCFrame-protected object is reported.
Both use Full dumps and pass against a locally built runtime.
@leculver leculver self-assigned this Jun 8, 2026
Copilot AI review requested due to automatic review settings June 8, 2026 23:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends cDAC stack reference enumeration to also report two additional GC root sources that were previously missed: (1) objects protected by the thread’s GCFrame (GCPROTECT) chain and (2) in-flight exception objects held on the thread’s ExInfo chain. It also adds new dump debuggees and dump tests to validate these root sources show up in IStackWalk.WalkStackReferences.

Changes:

  • Add cDAC data contract support for GCFrame and expose the thread’s m_pGCFrame chain via the Thread contract.
  • Extend StackWalk_1.WalkStackReferences to report GCFrame roots and ExInfo (exception tracker) roots.
  • Add two new dump debuggees and corresponding dump tests covering GCFrame roots and nested in-flight exceptions.
Show a summary per file
File Description
src/native/managed/cdac/tests/DumpTests/StackReferenceDumpTests.cs Adds new dump-based tests for ExInfo and GCFrame root reporting; GCFrame test needs to avoid potential false positives.
src/native/managed/cdac/tests/DumpTests/Debuggees/NestedException/Program.cs New debuggee that crashes while nested exceptions are still in flight.
src/native/managed/cdac/tests/DumpTests/Debuggees/NestedException/NestedException.csproj Registers the NestedException debuggee and requests Full dumps.
src/native/managed/cdac/tests/DumpTests/Debuggees/GCProtect/Program.cs New debuggee that FailFasts inside an AssemblyResolve handler under a native GCPROTECT scope.
src/native/managed/cdac/tests/DumpTests/Debuggees/GCProtect/GCProtect.csproj Registers the GCProtect debuggee and requests Full dumps.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/DataType.cs Adds GCFrame to the public DataType enum (new public surface).
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/Thread.cs Adds an optional GCFrame pointer field to the managed Thread data contract.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/GCFrame.cs New managed data contract type describing the native GCFrame layout.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/StackWalk_1.cs Reports GCFrame-protected roots and ExInfo-tracked exception roots as stack references.
src/coreclr/vm/threads.h Exposes Thread::m_pGCFrame offset via cdac_data<Thread>.
src/coreclr/vm/frames.h Adds cdac_data<GCFrame> describing the native GCFrame layout.
src/coreclr/vm/datadescriptor/datadescriptor.inc Adds Thread.GCFrame field and a new GCFrame CDAC type descriptor.

Copilot's findings

  • Files reviewed: 12/12 changed files
  • Comments generated: 4

Comment thread src/native/managed/cdac/tests/DumpTests/StackReferenceDumpTests.cs Outdated
…ng, match GCFrame roots by Source

- ReportGCFrameRoots: forward the full GCFrame.GCFlags bitmask to the
  promote func via (GcScanFlags) cast, mirroring GCFrame::GcScanRoots,
  instead of remapping any nonzero value to GC_CALL_INTERIOR.
- ReportGCFrameRoots/ReportExceptionTrackerRoots: wrap each helper body
  in try/catch so a bad read yields partial results instead of failing
  the whole WalkStackReferences walk, matching the per-frame loop.
- GCProtect_GCFrameRootsAreReported: identify GCFrame roots by matching
  StackReferenceData.Source against the thread's actual GCFrame chain
  node addresses, instead of the SP-null heuristic that also matches
  ExInfo-sourced roots.
Copilot AI review requested due to automatic review settings June 9, 2026 00:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 12/12 changed files
  • Comments generated: 5

Comment thread src/coreclr/vm/datadescriptor/datadescriptor.inc
Comment thread src/native/managed/cdac/tests/DumpTests/StackReferenceDumpTests.cs Outdated
leculver added 2 commits June 8, 2026 21:09
- Report GCFrame/ExInfo roots with a non-zero StackPointer (the on-stack
  node address) instead of 0, matching native DacStackReferenceWalker
  which gives frame-sourced roots a real SP that SOSDacImpl forwards.
- Move DataType.GCFrame from the exception-type group into the Frame
  group where it belongs (GCFrame is a Frame subtype). DataType lookups
  are name-keyed, so ordering is not load-bearing.
- Document Thread.GCFrame and the GCFrame type descriptors, plus the new
  GCFrame/ExInfo root reporting, in the Thread and StackWalk contract docs.
- Guard the test's MethodTable read with try/catch (a reported GCFrame
  root may be an interior pointer), mirroring GCRoots_RefsPointToValidObjects.
Bring the in-process cdacstress oracle into parity with GetStackReferences.
WalkStackReferences now reports the GCFrame (GCPROTECT) chain and the in-flight
ExInfo chain, but CollectRuntimeStackRefs skipped GCFrame outright and never
collected ExInfo, so any thread holding a live GCPROTECT frame or an in-flight
exception produced a spurious cDAC/runtime count mismatch. Mirror ScanStackRoots
on the runtime side so the two sets line up.

Also correct the StackWalk data-contract doc: WalkStackReferences mirrors the
GC's own ScanStackRoots (a superset of DacStackReferenceWalker, which covers
only the per-frame roots), and add the Exception contract dependency.
Copilot AI review requested due to automatic review settings June 9, 2026 01:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 15/15 changed files
  • Comments generated: 2

Comment thread docs/design/datacontracts/Thread.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants