Commit 33db161
[cDAC] Enumerate R2R hashmap pages into triage dumps for odd entry points (#129931)
## Summary
Fix the cDAC's R2R stack walk aborting a frame past a
`SoftwareExceptionFrame` when reading macOS triage minidumps. The root
cause is an odd-entry-point optimization in the legacy DAC that skips a
hashmap probe, so the bucket pages that probe would touch are never
enumerated into the triage dump -- and the cDAC consumer then faults
reading those not-in-dump pages.
Tracking issue: dotnet/diagnostics#5910 -- full repro, captured failure
trace, and dump-file page-map evidence are there.
## Root cause
`ReadyToRunInfo::GetMethodDescForEntryPointInNativeImage` looks up an
entry point in the `EntryPointToMethodDescMap` hashmap. It has an
x64/x86 fast path that returns early when the entry point is odd:
```cpp
#if defined(TARGET_AMD64) || defined(TARGET_X86)
// A normal method entry point is always 8 byte aligned, but a funclet can start at an odd address.
if ((entryPoint & 0x1) != 0)
return NULL;
#endif
```
This is purely a **performance optimization**: the map only ever
contains true method entry points (4-byte aligned on every
architecture), so a lookup for an odd (funclet) address is always a
miss. (`PtrHashMap` handles odd keys fine -- they're just never
present.)
The problem is the side effect in **DAC builds**. When `createdump`
enumerates memory for a triage minidump (`DOTNET_DbgMiniDumpType=3`), it
drives stack walking through this same path. The fast path makes it
return without ever probing the hashmap for odd (funclet) entry points,
so the bucket pages that probe would touch are never read and never
captured into the dump.
The cDAC consumer, walking the same stack later, probes the hashmap for
that odd entry point, lands in a bucket page absent from the dump,
throws `VirtualReadException`, and aborts the walk -- SOS reports
`<failed>` one frame past the `SoftwareExceptionFrame`.
## Fix
Make the producer enumerate the pages instead of mirroring the bail on
the consumer:
- **`src/coreclr/vm/readytoruninfo.cpp`**: gate the odd-entry-point
optimization with `!defined(DACCESS_COMPILE)`. The live runtime keeps
the perf win; DAC builds perform the lookup so the bucket pages are
enumerated into triage minidumps. Also removed the inaccurate
"PtrHashMap can't handle odd pointers" comment.
- **cDAC `ExecutionManagerCore.ReadyToRunJitManager`**: removed the bail
entirely. With the DAC enumerating the pages, the consumer reads them
naturally.
This is a root-cause fix (complete dump enumeration) rather than masking
the symptom on the consumer side, and it benefits the legacy DAC
consumer too, not just the cDAC.
## Validation
- **Native build**: rebuilt `coreclr.dll` (non-DAC) and
`mscordaccore.dll` (DAC); both compilations of `readytoruninfo.cpp`
succeed with 0 warnings / 0 errors, confirming the `#if` change is valid
in both configurations.
- **cDAC unit tests**
(`Microsoft.Diagnostics.DataContractReader.Tests`): all green.
- **End to end**: the failing diagnostics CI tests create fresh triage
dumps, so once this change rides in via the runtime -> diagnostics flow,
the dumps will contain the previously-missing bucket pages and the cDAC
walk completes. (Dumps captured by an older, still-bailing DAC won't
contain those pages; this fix applies to newly created dumps.)
> [!NOTE]
> This PR description was drafted with assistance from GitHub Copilot.
---------
Co-authored-by: Max Charlamb <maxcharlamb@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent 19a803d commit 33db161
1 file changed
Lines changed: 7 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
368 | 368 | | |
369 | 369 | | |
370 | 370 | | |
371 | | - | |
| 371 | + | |
372 | 372 | | |
373 | | - | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
374 | 379 | | |
375 | 380 | | |
376 | 381 | | |
| |||
0 commit comments