Skip to content

[cDAC] Add GC stress verification infrastructure and stack walk fixes#126176

Draft
max-charlamb wants to merge 65 commits intodotnet:mainfrom
max-charlamb:cdac-stackreferences-4
Draft

[cDAC] Add GC stress verification infrastructure and stack walk fixes#126176
max-charlamb wants to merge 65 commits intodotnet:mainfrom
max-charlamb:cdac-stackreferences-4

Conversation

@max-charlamb
Copy link
Member

Add cDAC stress verification (DOTNET_CdacStress) with three-way cDAC/DAC/RT comparison. Fix SkipCurrentFrameInCheck regression, SW_SKIPPED_FRAME context restoration, FilterContext reading, and dead code removal. See commit messages for details.

Max Charlamb and others added 30 commits March 12, 2026 14:00
… support

Squash of cdac-stackreferences branch changes onto main:
- Implement stack reference enumeration (EnumerateStackRefs)
- Add GC scanning support (GcScanner, GcScanContext, BitStreamReader)
- Add exception handling for stack walks (ExceptionHandling)
- Add IsFunclet/IsFilterFunclet to execution manager
- Add EH clause retrieval for ReadyToRun
- Add data types: EEILExceptionClause, CorCompileExceptionClause,
  CorCompileExceptionLookupEntry, LastReportedFuncletInfo
- Update datadescriptor.inc with new type layouts
- Update SOSDacImpl with improved stack walk support

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Port the native GcInfoDecoder::EnumerateLiveSlots to managed code:
- Add FindSafePoint for partially-interruptible safe point lookup
- Handle partially-interruptible path (1-bit-per-slot and RLE encoded)
- Handle indirect live state table with pointer offset indirection
- Handle fully-interruptible path with chunk-based lifetime transitions
  (couldBeLive bitvectors, final state bits, transition offsets)
- Report untracked slots (always live unless suppressed by flags)
- Add InterruptibleRanges/SlotTable decode points for lazy decoding
- Save safe point and live state bit offsets during body decode
- Add POINTER_SIZE_ENCBASE, LIVESTATE_RLE_*, NUM_NORM_CODE_OFFSETS_*
  constants to IGCInfoTraits (same across all platforms)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix IsFrameless: use StackWalkState.SW_FRAMELESS check
- Fix EnumGcRefs call: pass CodeManagerFlags parameter (was missing)
- Add public access modifier to GetMethodRegionInfo in ExecutionManager_1/2
- Fix redundant equality (== false) in ExecutionManagerCore
- Suppress unused parameter/variable analyzer errors in GcScanner stub

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Wire GcScanner to use IGCInfoDecoder.EnumerateLiveSlots
- Add LiveSlotCallback delegate and EnumerateLiveSlots to IGCInfoDecoder
- Add interface implementation in GcInfoDecoder that wraps the generic method
- Translate register slots to values via IPlatformAgnosticContext
- Translate stack slots using SP/FP base + offset addressing
- Add StackBaseRegister accessor to GcInfoDecoder
- Report live slots to GcScanContext.GCEnumCallback with proper flags
- Add GcScanFlags.None value

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add StackReferenceData public data class in Abstractions
- Change IStackWalk.WalkStackReferences to return IReadOnlyList<StackReferenceData>
- Update StackWalk_1.WalkStackReferences to convert and return results
- Add ISOSStackRefEnum, ISOSStackRefErrorEnum COM interfaces with GUIDs
- Add SOSStackRefData, SOSStackRefError structs, SOSStackSourceType enum
- Add SOSStackRefEnum class implementing ISOSStackRefEnum (follows SOSHandleEnum pattern)
- Wire up SOSDacImpl.GetStackReferences: find thread by OS ID, walk stack
  references, convert to SOSStackRefData[], return via COM enumerator
- Remove Console.WriteLine debug output from WalkStackReferences

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add three test classes for stack reference enumeration:
- StackReferenceDumpTests: Basic tests using StackWalk debuggee
  (WalkStackReferences returns without throwing, refs have valid source info)
- GCRootsStackReferenceDumpTests: Tests using GCRoots debuggee which keeps
  objects alive on stack via GC.KeepAlive (finds refs, refs point to valid objects)
- PInvokeFrameStackReferenceDumpTests: Tests using PInvokeStub debuggee which
  has InlinedCallFrame on the stack (non-frameless Frame path)

The PInvokeStub tests exercise the Frame::GcScanRoots path which is not yet
implemented (empty else block in WalkStackReferences).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add native C++ changes needed for the data descriptor entries:
- Add friend cdac_data<ExInfo> to ExceptionFlags for m_flags access
- Add LastReportedFuncletInfo struct and field to ExInfo
- Add cdac_data<PatchpointInfo> specialization for LocalCount
- Use cdac_data<ExInfo>::ExceptionFlagsValue for ExceptionFlags offset

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add ScanFrameRoots method that dispatches based on frame type name.
Most frame types use the base Frame::GcScanRoots_Impl which is a no-op.

Key findings documented in the code:
- GCFrame is NOT part of the Frame chain and the DAC does not scan it
- Stub frames (StubDispatch, External, CallCounting, Dynamic, CLRToCOM)
  call PromoteCallerStack to report method arguments — not yet implemented
- InlinedCallFrame, SoftwareExceptionFrame, etc. use the base no-op

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ation

- Fix GcScanSlotLocation register for stack slots: was hardcoded to 0,
  now correctly maps GC_SP_REL→RSP(4), GC_FRAMEREG_REL→stackBaseRegister
- Update GetStackReferences debug block to use set-based comparison
  (match by Address) instead of index-based, since ref ordering may differ
- Validate Object, SourceType, Source, and Flags for each matched ref

Known issue: Some refs have different computed addresses between cDAC and
legacy DAC due to stack slot address computation differences. Needs further
investigation of SP/FP handling during stack walk context management.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix two bugs in the GCInfoDecoder slot table decoder that caused wrong
slots to be reported as live:

1. When previous slot had non-zero flags, subsequent slots use a FULL
   offset (STACK_SLOT_ENCBASE) not a delta. The managed code incorrectly
   used STACK_SLOT_DELTA_ENCBASE for this case.

2. When previous slot had zero flags, subsequent slots use an unsigned
   delta (DecodeVarLengthUnsigned) with no +1 adjustment. The managed
   code incorrectly used DecodeVarLengthSigned with +1.

Both bugs affected tracked and untracked stack slot sections.

Verified with DOTNET_ENABLE_CDAC=1 and cdb against three debuggee dumps:
all refs now match the legacy DAC exactly (count, Address, Object,
Source, SourceType, Flags, Register, Offset for every ref).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix two bugs found via deep comparison with native GCInfoDecoder:

1. ARM64GCInfoTraits.DenormalizeStackBaseRegister used 0x29 (41 decimal)
   instead of 29 decimal. ARM64's frame pointer is X29, so the native
   XORs with 29. This would produce wrong addresses for all ARM64
   stack-base-relative GC slots.

2. When ExecutionAborted and instruction offset is not in any
   interruptible range, the native code jumps to ExitSuccess (skips
   all reporting). The managed code incorrectly jumped to
   ReportUntracked, which would over-report untracked slots for
   aborted frames.

Also documented the missing scratch register/slot filtering as a
known gap (TODO in ReportSlot). The native ReportSlotToGC checks
IsScratchRegister/IsScratchStackSlot for non-leaf frames; the cDAC
currently reports all slots unconditionally.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Match native safe point skip: always skip numSafePoints * numTracked
  bits in the else branch, matching the native behavior. The indirect
  table case (numBitsPerOffset != 0) combined with interruptible ranges
  is unreachable in practice.
- Add TODO for FindSafePoint binary search optimization (perf only,
  no correctness impact).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add scratch register filtering to match native ReportSlotToGC behavior:

- Add IsScratchRegister to IGCInfoTraits with per-platform implementations:
  - AMD64: preserved = rbx, rbp, rsi, rdi, r12-r15 (Windows ABI)
  - ARM64: preserved = x19-x28; scratch = x0-x17, x29-x30
  - ARM: preserved = r4-r11; scratch = r0-r3, r12, r14
  - Interpreter: no scratch registers
- Add scratch filtering in ReportSlot: skip scratch registers for
  non-leaf frames (when ActiveStackFrame is not set)
- Add ReportFPBasedSlotsOnly filtering: skip register slots and
  non-FP-relative stack slots when flag is set
- Add IsScratchStackSlot check: skip SP-relative slots in the
  outgoing/scratch area for non-leaf frames
- Set ActiveStackFrame flag for the first frameless frame in
  WalkStackReferences (matching native GetCodeManagerFlags behavior)

Verified with DOTNET_ENABLE_CDAC=1 against three debuggee dumps:
all refs match the legacy DAC exactly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix 5 issues from PR dotnet#125075 review:

1. datadescriptor.inc: Fix EHInfo type annotation from /*uint16*/ to
   /*pointer*/ — phdrJitEHInfo is PTR_EE_ILEXCEPTION, not uint16.

2. StackWalk.md: Update GetMethodDescPtr(IStackDataFrameHandle) docs
   to describe InlinedCallFrame special case for interop MethodDesc
   reporting at SW_SKIPPED_FRAME positions.

3. BitStreamReader: Replace static host-dependent BitsPerSize
   (IntPtr.Size * 8) with instance-based _bitsPerSize
   (target.PointerSize * 8) for correct cross-architecture analysis.

4. SOSDacImpl: Restore GetMethodDescPtrFromFrame implementation that
   was incorrectly stubbed with E_FAIL. Restores the cDAC
   implementation with debug validation against legacy DAC.

5. ReadyToRunJitManager: Fix GetEHClauses clause address computation
   to include entry.ExceptionInfoRva — was computing from imageBase
   directly, missing the RVA offset to the exception info section.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix several bugs in the cDAC's stack reference walking that caused
mismatches against the legacy DAC during GC stress testing:

- Fix GC_CALLER_SP_REL using wrong base address: GcScanner used the
  current context's StackPointer for GC_CALLER_SP_REL slots instead
  of the actual caller SP. Fixed by computing the caller SP via
  clone+unwind, with lazy caching to avoid repeated unwinds.

- Fix IsFirst/ActiveStackFrame tracking: The cDAC used a simple
  isFirstFramelessFrame boolean to determine active frame status.
  Replaced with an IsFirst state machine in StackWalkData matching
  native CrawlFrame::isFirst semantics - starts true, set false
  after frameless frames, restored to true after FRAME_ATTR_RESUMABLE
  frames (ResumableFrame, RedirectedThreadFrame, HijackFrame).

- Fix FaultingExceptionFrame incorrectly treated as resumable:
  FaultingExceptionFrame has FRAME_ATTR_FAULTED but NOT
  FRAME_ATTR_RESUMABLE. Including it in the resumable check caused
  IsFirst=true on the wrong managed frame, producing spurious
  scratch register refs.

- Skip Frames below initial context SP in CreateStackWalk: Matches
  the native DAC behavior where StackWalkFrames with a profiler
  filter context skips Frames at lower SP (pushed more recently).
  Without this, RedirectedThreadFrame from GC stress redirect
  incorrectly set IsFirst=true for non-leaf managed frames.

- Refactor scratch stack slot detection into IsScratchStackSlot on
  platform traits (AMD64, ARM64, ARM), matching the native
  GcInfoDecoder per-platform IsScratchStackSlot pattern.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The initial Frame skip used the leaf's SP as the threshold, which
missed active InlinedCallFrames whose address was above the leaf SP
but below the caller SP. These Frames would be processed as SW_FRAME,
causing UpdateContextFromFrame to restore the IP to the P/Invoke
return address within the same method and producing duplicate GC refs.

Use the caller SP (computed by unwinding the initial managed frame)
as the skip threshold, matching the native CheckForSkippedFrames
which uses EnsureCallerContextIsValid + GetSP(pCallerContext). This
correctly skips all Frames between the managed frame and its caller,
including both RedirectedThreadFrame and active InlinedCallFrames.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Newer fields added to RealCodeHeader (EHInfo), ReadyToRunInfo
(ExceptionInfoSection), and ExceptionInfo (ExceptionFlags,
StackLowBound, StackHighBound, PassNumber, CSFEHClause,
CSFEnclosingClause, CallerOfActualHandlerFrame,
LastReportedFuncletInfo) may not exist in older contract versions.
Guard each with type.Fields.ContainsKey and default to safe values
to prevent KeyNotFoundException when analyzing older dumps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove unused usings in GcScanContext.cs (Data namespace, StackWalk_1 static)
- Fix trailing semicolon on class closing brace in StackWalk_1.cs
- Discard unused pMethodDesc assignment in StackWalk_1.cs
- Add buffer length validation in SOSStackRefEnum.Next to prevent IndexOutOfRangeException
- Use Debug.ValidateHResult in GetMethodDescPtrFromFrame to match codebase pattern

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove unused 'using Microsoft.Diagnostics.DataContractReader.Contracts.Extensions' from StackWalk_1.cs
- Remove unused 'using System.Linq' and 'using System' from StackReferenceDumpTests.cs
- Remove unused 'using System' from StackRefData.cs and GcScanSlotLocation.cs
- Clear ppEnum.Interface on failure paths in SOSDacImpl.GetStackReferences

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Restore the full GetMethodDescPtr(IStackDataFrameHandle) documentation
  in StackWalk.md that describes the ReportInteropMD special case. The
  docs were incorrectly simplified but the implementation was unchanged.
- Use specific friend declaration in patchpointinfo.h instead of generic
  template friend, matching the codebase convention.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The m_lastReportedFunclet field was added to ExInfo but is never
written by the runtime, making it always zero-initialized. The cDAC
code that reads it can never trigger. Remove the field from ExInfo,
the data descriptor entry, and the managed LastReportedFuncletInfo
data class. Mark the Filter code path as explicitly unreachable
with a TODO for when runtime support is added.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Max Charlamb and others added 25 commits March 17, 2026 13:17
…2-with-stress

# Conflicts:
#	src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ContextHolder.cs
#	src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformAgnosticContext.cs
Break out of the while loop when Split-Path -Parent returns the same
path (filesystem root), preventing infinite iteration on Windows where
C:\ is its own parent.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
RegisterNumber on RegisterAttribute is no longer needed since PR dotnet#125621
added explicit TrySetRegister(int)/TryReadRegister(int) switch dispatch
directly on each context struct. Revert these files to match main.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ToRunInfo fields

Add missing fields to test mock type descriptors:
- ExceptionInfoSection in ReadyToRunInfoFields
- EHInfo in RealCodeHeaderFields (increase RealCodeHeaderSize to 0x38)
- ExceptionFlags, StackLowBound, StackHighBound, PassNumber, CSFEHClause,
  CSFEnclosingClause, CallerOfActualHandlerFrame in ExceptionInfoFields

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Move cdac_data<ExInfo> specialization out of #ifndef TARGET_UNIX guard
  so ExceptionFlagsValue, StackLowBound, and StackHighBound are available
  on all platforms. Only ExceptionWatsonBucketTrackerBuckets remains
  Windows-only.
- Replace _wfopen with fopen + WideCharToMultiByte on Unix in
  cdacgcstress.cpp since _wfopen is not available on non-Windows platforms.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add StackPointerRegister property to IPlatformContext and all context
structs, returning the platform-specific SP register number (AMD64: 4,
ARM64: 31, ARM: 13, X86: 4, LoongArch64: 3, RISCV64: 2).

GcScanner now computes the correct register encoding for stack slots:
- GC_SP_REL: SP register number (was incorrectly 1)
- GC_CALLER_SP_REL: -(SP + 1) (was incorrectly 0)
- GC_FRAMEREG_REL: actual frame base register (was incorrectly 2)

This matches the native GCInfoDecoder::GetStackReg() behavior, ensuring
SOSStackRefData.Register/Offset metadata is compatible with DAC output.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Expand the GC stress comparison from (Object, Flags) to
(Address, Object, Flags). Both sides normalize register refs to
Address=0 and stack refs to the actual stack slot address, so all
three fields should match between cDAC and runtime.

Also capture Register, Offset, and StackPointer from cDAC's
SOSStackRefData in the StackRef struct and log them on failures
for easier debugging.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
If QueryInterface for ISOSDacInterface fails, treat it as an
initialization failure and clean up, rather than setting
s_initialized=true and risking a null dereference in
VerifyAtStressPoint when calling s_cdacSosDac->GetStackReferences.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rowing

Remove the default implementation that throws NotImplementedException,
forcing implementers to provide a real implementation at compile time
rather than silently compiling and failing at runtime.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
DOTNET_ContinueOnAssert=1 suppresses debug asserts, which would
prevent -FailFast from stopping the process on the first mismatch.
Only set it in the non-failfast path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CreateStackWalk is used by both ClrDataStackWalk (SOS frame iteration)
and WalkStackReferences (GC root enumeration). The skipBelowSP logic
pre-advances the FrameIterator past explicit Frames below the initial
caller SP, which is needed for GC reference enumeration to match the
native DacStackReferenceWalker, but must not apply to ClrDataStackWalk
which must yield the same frame sequence as the legacy DAC.

Refactor into a single CreateStackWalkCore(threadData, skipInitialFrames)
helper. CreateStackWalk passes false; WalkStackReferences passes true.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reduce state flags by removing SkipCurrentFrameInCheck and simplifying IsFirst tracking to match native behavior. Consolidate duplicate ICF skipping logic into CheckForSkippedFrames.
The runtime's promote callback reports real ppObj addresses for both
register and stack refs, while cDAC reports Address=0 for register refs.
Instead of trying to normalize the runtime side (unreliable since
REGDISPLAY/CONTEXT can be within managed stack bounds), use two-phase
matching:
  Phase 1: Match stack refs (cDAC Address != 0) by exact (Address, Object, Flags)
  Phase 2: Match register refs (cDAC Address == 0) by (Object, Flags) only

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SOSDacImpl.GetStackReferences leaks a ref-count via ConvertToUnmanaged
for COM compat. The GC stress caller must Release twice to avoid leaking.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add GCRefMap-based and MetaSig-based scanning for stub frames in the cDAC
stack walker. This implements Frame::GcScanRoots dispatch for:

- StubDispatchFrame: GCRefMap path (when cached) + MetaSig fallback
- ExternalMethodFrame: GCRefMap path
- PrestubMethodFrame / CallCountingHelperFrame: MetaSig path
- DynamicHelperFrame: Flag-based register scanning

Key components:
- GCRefMapDecoder: managed port of native gcrefmap.h bitstream decoder
- CorSigParser: ECMA-335 signature parser with GC type classification,
  including ELEMENT_TYPE_INTERNAL for dynamic method signatures
- OffsetFromGCRefMapPos: maps GCRefMap positions to TransitionBlock offsets
- Platform-guarded TransitionBlock offset globals in datadescriptor.inc

Bug fixes found during implementation:
- ScanFrameRoots was passing frame address to GetFrameName instead of the
  frame's VTable identifier, causing all frames to hit the no-op default
- Added per-frame error isolation so one bad frame doesn't abort the walk

Reduces GC stress failure delta from 3 to 1 for all 55 remaining failures.
The remaining delta is from RangeList-based code heap resolution (separate issue).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix GetExceptionClauses to use code start for offset calculation.
Wire up ParentOfFuncletStackFrame and unwind-target-PC override
for catch handler GC reporting. Fix AMD64Unwinder null check.

Add GC stress verification infrastructure that compares cDAC stack
reference enumeration against the runtime at GC stress points:
- DAC-like callback for runtime stack ref collection
- xUnit test framework with 7 debuggees (BasicAlloc, DeepStack,
  Generics, ExceptionHandling, PInvoke, MultiThread, Comprehensive)
- Step throttling, allocation-point hooks, and reentrancy guard
- On-demand build subset and project exclusion from main test project

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove code referencing runtime features that were removed in PR dotnet#119863
(Move coreclr EH second pass to native code):

- ForceGcReportingStage enum and related TODO comments
- ShouldSaveFuncletInfo, ShouldParentToFuncletReportSavedFuncletSlots,
  IsFilterFunclet, IsFilterFuncletCached fields from GCFrameData
- funcletNotSeen, foundFirstFunclet variables
- Unreachable ExInfo block gated by '&& false'
- Dead PeekByte() and ClassifyElementType() from CorSigParser
- Inner try/catch around ScanFrameRoots (outer catch suffices)
- Exclude GCStressTests from main cDAC test project

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduce a separate DOTNET_CdacStress config with bit flags for
controlling cDAC stack reference verification independently of GCStress:
  0x1 ALLOC  - verify at allocation points (fast, no JIT overhead)
  0x2 GC     - verify at GC trigger points (future)
  0x4 UNIQUE - deduplicate by (IP, SP) hash
  0x8 INSTR  - verify at instruction traps (needs GCStress=0x4)

Follow the GCStress<T> template pattern with CdacStress<T>::MaybeVerify
that compiles to nothing when HAVE_GCCOVER is not defined, eliminating
#ifdef guards at call sites.

Rename CdacGcStress -> CdacStress (class, files, config vars) to reflect
that this verifies the cDAC's stack walk, not GC behavior.

Legacy DOTNET_GCStress=0x20 continues to work (maps to CDACSTRESS_ALLOC).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Match the native DAC behavior for both ClrDataStackWalk::Init and
DacStackReferenceWalker::WalkStack: check the thread's
DebuggerFilterContext and ProfilerFilterContext before falling back
to TryGetThreadContext. During debugger breaks or profiler stack
walks, these contexts hold the correct managed frame state.

Add DebuggerFilterContext and ProfilerFilterContext fields to the
Thread data descriptor and Data.Thread class.

Add diagnostic logging for unique Source IPs in cDAC stress failures
to show which frames the cDAC actually walked.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix SkipDuplicateActiveICF regression from base branch commit 650ffb5:
restore one-shot SkipCurrentFrameInCheck behavior so InlinedCallFrames
are not permanently lost from the FrameIterator.

Fix SW_SKIPPED_FRAME context restoration: call UpdateContextFromFrame
for skipped Frames so SoftwareExceptionFrame context is restored.

Add IsAtFirstPassExceptionThrowSite to suppress throw-site refs during
exception first-pass dispatch, matching legacy DAC behavior.

Restructure CdacStress flags into trigger points (ALLOC/GC/INSTR),
validation types (REFS/WALK/USE_DAC), and modifiers (UNIQUE).

Add three-way comparison infrastructure:
- Load legacy DAC (mscordaccore.dll) in-process via InProcessDataTarget
- CompareStackWalks: frame-by-frame IXCLRDataStackWalk IP+SP+FrameAddr
- CompareRefSets: two-phase ref matching (stack + register refs)
- CollectStackRefs: merged cDAC/DAC collection into single function
- FilterAndDedup: combined interior pointer filter + dedup

Refactor VerifyAtStressPoint into clean 5-step flow:
1. Collect raw refs (cDAC always, DAC if USE_DAC, RT always)
2. Compare cDAC vs DAC raw (before filtering)
3. Filter cDAC refs and compare vs RT
4. Pass/fail based on RT match; DAC mismatch logged separately
5. Log all three ref sets on failure

Update known-issues.md with current findings: single remaining issue
is m_pFrame=FRAME_TOP during EH first-pass dispatch where the cDAC
cannot unwind through native frames.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag
See info in area-owners.md if you want to be subscribed.

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.

1 participant