Skip to content

[release/10.0] Don't crash when walking callstack roots in the debugger - #136161

Open
github-actions[bot] wants to merge 1 commit into
release/10.0from
backport/pr-124402-to-release/10.0
Open

github-actions[bot] wants to merge 1 commit into
release/10.0from
backport/pr-124402-to-release/10.0

Conversation

@github-actions

@github-actions github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Backport of #124402 to release/10.0

Fixes #135590

/cc @max-charlamb @leculver

Customer Impact

  • Customer reported
  • Found internally

Reported in #135590 on .NET 10.0.12. Debugger and diagnostics tools crash with a native SIGSEGV inside libmscordaccore when the DAC walks stack roots. Examples are ClrMD EnumerateStackRoots() on a live process, and dotnet-dump clrstack -gc / gcroot on Linux amd64 dumps. Expected: stack roots are enumerated. Actual: the tool process crashes. This affects any tool built on the DAC stack-root enumeration (dotnet-dump, ClrMD-based tools, and memory/heap analysis in debuggers).

Regression

  • Yes
  • No

Introduced by #108480 ("Improve software exception handling performance", 1fa1745), which has been in release/10.0 since 10.0.0-preview.1. A partial fix (1a5af14) handled x86 only. This change covers the remaining architectures.

Testing

Verified locally on Linux x64 Release, using an unmodified 10.0.12 runtime and swapping only libmscordaccore.so. The repro is the one from #135590 (live ClrMD EnumerateStackRoots() under load):

  • Unpatched DAC (shipped 10.0.12 and a private unpatched build): 6/6 SIGSEGV within seconds. LLDB shows the fault in GetStackSlot (GC_FRAMEREG_REL) dereferencing pCurrentContextPointers->Rbp, an unmapped target-process address, while the local context copy was valid.
  • Patched DAC: 3/3 clean 120 s external-target runs, with 2,150-2,658 attachments and 130K-160K stack roots each, and no crashes.

Risk

Low. The change only affects DACCESS_COMPILE code (SoftwareExceptionFrame / FaultingExceptionFrame UpdateRegDisplay). It makes the DAC register pointers refer to the local pRD->pCurrentContext copy instead of target memory. The runtime (non-DAC) paths are unchanged. It is the same diff that has been on main since #124402.

IMPORTANT: This backport targets release/10.0 (no -staging suffix), as required for .NET 10+.

Changeset
1fa1745
introduced a stack walking regression where we will crash trying to
unwind/report registers. The real fix here is in
cgenamd64.cpp/excep.cpp, which will point the context to a local copy
before we try to use it.

I've also added some changes in gcinfodecoder.cpp that aren't strictly
necessary but would have avoided the problem to begin with.

Fixes #124401.
@azure-pipelines

Copy link
Copy Markdown
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.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.

This branch has not been deployed

No deployments
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