Repository navigation
Size the RESOLVE_UPDATE_METADATA events in DbgTransportSession::GetEventSize - #134717
Conversation
On Unix, DbgTransportSession::GetEventSize had no case for the four DB_IPCE_RESOLVE_UPDATE_METADATA_* events, so release builds sent them header-only and the receiver read stale bytes in place of the MetadataUpdateRequest payload. Requesting the locals of a method that a profiler had given new locals could then crash the debuggee. Size _1, _1_RESULT and _2 as MetadataUpdateRequest, and add _2_RESULT, which carries only the header hr, to the zero-payload group. Fix dotnet#134714
|
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. |
|
Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag |
|
A follow-up on the "should ship together" note in the servicing template, now measured. This is local 10.0.12 linux-x64 release, the #134714 repro, netcoredbg, 3 runs. With this PR and #134987 in
In all three runs the value in The reverse pairing (an unpatched mscordbi with a runtime carrying this PR) still crashes in Zeroing the unsent tail of each received event closes both: Note This comment and the measurements in it were produced with AI assistance (Anthropic Claude and OpenAI Codex), under my direction. I reviewed it before posting. |
|
@steveisok @tommcdon — gentle ping on this one. It's a 7-line fix for a debuggee crash that any profiler adding locals can trigger on Linux (present since 6.0, repro and per-branch patches on #134714). Build Analysis is green; the two reds are known issues #133645 and #133953. If release/11.0 is in scope the servicing template is in the description. #134987 and #135114 are independent siblings in the same area if it helps to look at them together. Happy to rebase or add a test wherever you'd like it. |
|
Thanks for merging this. Would you consider it for Note This comment was prepared with AI assistance (Anthropic Claude, checked by OpenAI Codex) at my request. I reviewed it before posting. |
|
@steveisok @tommcdon thanks for merging this. Could one of you run The two small follow-ups in the same code, #134987 (check the |
|
/backport to release/11.0 |
|
Started backporting to |
|
@pcshrosbree thanks for the contribution! I kicked off a backport to 11. I'm not opposed to trying to work this into 10, but will need to hone a good justification for it to meet the bar. It would be helpful if you could share from your perspective how this would be blocking you if we didn't take it into release/10.0. |
|
@steveisok thanks, and for the 11 backport (#135597). I'll narrow the ask to How it blocks us. We are building a profiler whose instrumentation rewrites methods at JIT time with Without a 10.0 fix we cannot reliably combine our JIT-time instrumentation with debugging on Linux or macOS. The choices are to decline instrumenting any method that needs a new local-signature row while a managed debugger might attach, which for a development-time tool is the main scenario, or to ship the workaround we have been building: a build step that writes the expected local signatures into the assembly on disk, so the debugger's metadata copy already holds the rows and does not request a refresh for them. Coverage depends on the exact required signature already being present in each loaded assembly. If it is absent, for example in an assembly the build step did not prepare, the guard declines the method or uses a hook that adds no local. The same exposure applies to any profiler whose rewrite adds a local. Why it services well. Both halves ship in the runtime package. On every launch kind I measured (local launch, local attach, self-contained, container, musl), vsdbg from the C# extension 2.160.4 and Rider 2026.1 loaded the target runtime's own Logistics. The Added 2026-10-11, after posting: one point I should have made explicit. This is not only a development-time problem. We also reproduced this crash after local debugger attach on Linux: the attach cells above were exactly that, a late attach to a running process with the full profiler, and the process died at the first exception stop under both netcoredbg and VS Code on each of 8.0.31 and 10.0.12. In production, the same exception-stop locals request could kill the attached process. In the observed crashes, application output stopped mid-run; SIGSEGV appeared only in the system's core-dump log. Our production configuration therefore switches the managed debugger off ( Note This comment was prepared with AI assistance (Anthropic Claude, checked by OpenAI Codex) at my request. I reviewed it before posting. |
Problem: on Linux, a debugger can crash the process it is debugging when it requests the locals of a method that a profiler has rewritten. If a profiler has given a method new locals with
SetILFunctionBody, a debugger that requests that method's locals can make the debuggee die with SIGSEGV inDebugger::SerializeModuleMetaData. An IDE's Variables pane can make that request automatically, for example at an exception stop. In my VS Code sessions, the Debug Console reported the crashed debuggee asexited with code 0.With checked builds, an unpatched process that sends one of the affected events asserts and aborts instead; with an unpatched checked
mscordbi, that is the debugger itself. I reproduced the crash on 8.0, 9.0, 10.0, 11.0 RC1 andmain, and the omission is present in the source back to at least 6.0. Standard Windows builds do not use this transport. macOS does, and the minimal repro crashes there too (official 10.0.12 and 8.0.31osx-arm64, netcoredbg, Apple silicon; added 2026-10-11).Cause: the Unix debugger transport sizes each event it sends with
DbgTransportSession::GetEventSize, which has no case for the fourDB_IPCE_RESOLVE_UPDATE_METADATA_*events. They fall todefault:. Release builds therefore send all four with only the event header; for the three that carry a payload, the receiver reads stale bytes where theMetadataUpdateRequestpayload should be. Checked builds assert"Unknown debugger event type"in the sending process. Under the defaultLegacyCompatPolicy, the debugger starts this exchange when it meets a local-signature token that is not in its cached metadata, such as a new signature that a profiler has added.Fix: size the three events that carry
MetadataUpdateRequest, and add_2_RESULT, which carries only the headerhr, to the existing zero-payload group. The linked issue has the details, a minimal repro, and results on 8.0 to 11.0._1vmModule_1_RESULTpMetadataStart,nMetadataSize_2pMetadataStart(the buffer to free)_2_RESULTGetEventSizeis compiled into bothmscordbiandcoreclr(debug/di/shared.cpp,debug/ee/shared.cpp), and each side sizes the events it sends, so both binaries need the change.Validation
With the minimal repro from the issue (a small C profiler that adds one unused local, and a debugger requesting locals at an exception stop: netcoredbg, or VS Code where marked), 3 runs per cell unless noted:
GetEventSize, 3/3mainatc29faec90e46, linux-x64 (VS Code; release, and checked for "after"¹)¹ The checked
mainbuild also swaps the DAC, JIT and CoreLib.Within each release configuration, only
libcoreclr.soandlibmscordbi.sodiffer between the before and after builds. macOS shares the transport: in my local runs on 2026-10-11, the minimal repro on official 10.0.12 and 8.0.31osx-arm64under netcoredbg 3.2.0 (Apple silicon) crashed the debuggee in 9 of 9localruns with clean controls; the three crash reports macOS wrote show the sameSerializeModuleMetaDatacrash site as Linux. The patched build was not run on macOS. The controls (no profiler; an unchanged body; a new MemberRef without a new local) read the expected locals under netcoredbg on 8.0, 9.0 and 10.0. On 11.0 RC1, netcoredbg returns only$exceptionat the stop even with no profiler, so the 11.0 rows use VS Code.Tests
I did not find a test in this repo that exercises the debugger transport, so this PR adds no test, as with #97476 and #110122. The repro is attached to the issue. #134715 proposes a checked-build check that every declared event type is either sized or explicitly listed as never sent. I am happy to add a test if you can point me at the right place.
Servicing
The omission is present on every supported branch. I'd suggest this for
release/11.0, ideally before GA; per-branch patches for 10.0, 9.0 and 8.0 are attached to the issue in case you judge those worth servicing. If you do service it, the text below may save time:Servicing template
Customer Impact
On Linux, when a profiler has given a method new locals with
SetILFunctionBody, a debugger that requests that method's locals (an IDE's Variables pane can do so automatically, e.g. at an exception stop) can crash the debuggee. macOS uses the same transport and reproduces the crash (official 10.0.12 and 8.0.31osx-arm64, netcoredbg, 2026-10-11); standard Windows builds do not use it.Regression
Present since at least 6.0 (checked from
v6.0.36).Testing
The minimal repro in #134714: release and checked 10.0.12 builds (linux-x64), release (linux-arm64), the 11.0 RC1 tag and
main(linux-x64, VS Code).Risk
Low. Cases are added to a size switch for events that were sent header-only. Only the sent length of these three events grows, to include their payload; no other event, struct or framing changes. The debugger (
libmscordbi.so) and the runtime (libcoreclr.so) should ship together: a fixedmscordbiwith an unpatchedcoreclrcan send a stale pointer back in_2for the runtime to free (see the issue). Both are in the runtime package.Resolves #134714
Note
This change and description were prepared with AI assistance (Anthropic Claude and OpenAI Codex), under my direction. I reviewed them before posting.