Skip to content

Fix double COM release of SOS debugger services - #6080

Merged
max-charlamb merged 1 commit into
mainfrom
dev/max-charlamb/fix-hostservices-debugger-release
Oct 1, 2026
Merged

max-charlamb merged 1 commit into
mainfrom
dev/max-charlamb/fix-hostservices-debugger-release

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Problem

HostServices.Uninitialize releases the native debugger-services COM reference twice:

  1. DebuggerServices is registered in the global service container as SOSHost.INativeDebugger. Although that interface does not inherit IDisposable, the concrete object inherits CallableCOMWrapper, which does.
  2. ServiceContainer.DisposeServices() checks the concrete instances for IDisposable and calls DebuggerServices.Dispose(), releasing the wrapper's owned COM reference.
  3. Uninitialize then calls DebuggerServices.ReleaseWithCheck(), which invokes a raw COM Release() again rather than respecting the wrapper's disposed state.

This is a double COM release, not necessarily an immediate double free in every run. With other references outstanding, it incorrectly consumes another owner's reference; if the first release destroys the native object, the second release can call through freed memory.

Provenance

The explicit release predates service-container ownership and was originally appropriate. #3448 introduced global service disposal while leaving DebuggerServices outside the container. #4285 subsequently registered the same wrapper as SOSHost.INativeClient so SOSHost could use the existing native debugger client, but retained the manual release. #4437 later renamed that interface to INativeDebugger.

CallableCOMWrapper already implemented IDisposable when the registration was added, so this is an ownership mismatch rather than a recent ClrMD disposal-contract change.

Fix

  • Remove the redundant explicit release; the service container disposes DebuggerServices exactly once.
  • Detach DiagnosticLoggingService from its debugger-backed console before disposing global services. Its singleton retains a ConsoleServiceFromDebuggerServices that forwards trace output to the native debugger interface; leaving that connection active during disposal could issue output through a released pointer.
  • Preserve target destruction and the shutdown event before global service disposal.

This was found while investigating Windows ARM64 SOS tests in #6075, but the ownership bug is architecture-independent. This PR does not establish that it caused the separate Output versus Output2 callback behavior.

Validation

Targeted restore and build of src\SOS\SOS.Extensions\SOS.Extensions.csproj succeeded for net8.0 and net462 with zero warnings and errors. No native teardown reproduction or ARM64 runtime validation has been performed for this fix.

Let the global service container dispose DebuggerServices once instead of explicitly releasing its COM reference again. Detach diagnostic logging before disposal so trace output cannot call through the released debugger interface.

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

Copilot-Session: 13f45840-6112-4dc4-ab2f-c020bd189022
@max-charlamb
max-charlamb requested a review from a team as a code owner September 30, 2026 21:04
@max-charlamb
max-charlamb enabled auto-merge (squash) October 1, 2026 16:12
@max-charlamb

Copy link
Copy Markdown
Member Author

/ba-g unrelated transient symbol server test flake

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants