From e964c1c271b17cf3b95be5b6ff5f747dd45a6fab Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Mon, 4 May 2026 16:27:28 +0200 Subject: [PATCH] [debug/di] Release DbgTransportTarget RSLock on static destruction The static g_DbgTransportTarget instance is destroyed after the host process's main() returns. On Unix the dynamic loader does not invoke DbgDllMain(DLL_PROCESS_DETACH) for mscordbi.dylib, so DbgTransportTarget::Shutdown() may never run and the embedded RSLock m_sLock is left in its initialized state. In debug builds the RSLock destructor asserts that the lock was Destroy()'d before destruction, so the host process aborts with 'Leaking Critical section for RS Lock DbgTransportTarget Lock' and exits 134. The test harness then marks every otherwise successful debugger test as a failure during teardown. Add a defensive ~DbgTransportTarget() that invokes Shutdown() when the lock is still initialized. This affects every debugger test that exits cleanly through the static destructor path. Locally on osx-arm64 Debugger.Tests --clrinterpreter the xunit fail count drops from 230 to 65, with the following tests no longer reported as failing on top of the existing baseline: - Inspection.BasicInspection, Inspection.EnumNames, Inspection.GenericInterfaces, Inspection.GenericSharedStatic, Inspection.GenericStatics, Inspection.NestedGenerics, Inspection.inspect_SetVars - Stackwalking.ClrMethods - Stepping.setIPTestwithUnvaildPos, Stepping.stepin, Stepping.stepover - Async.AsyncStepInto Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/debug/di/dbgtransportmanager.cpp | 10 ++++++++++ src/coreclr/debug/di/dbgtransportmanager.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/coreclr/debug/di/dbgtransportmanager.cpp b/src/coreclr/debug/di/dbgtransportmanager.cpp index 828af8928724f6..3a2e1f7bbe8e18 100644 --- a/src/coreclr/debug/di/dbgtransportmanager.cpp +++ b/src/coreclr/debug/di/dbgtransportmanager.cpp @@ -15,6 +15,16 @@ DbgTransportTarget::DbgTransportTarget() { } +DbgTransportTarget::~DbgTransportTarget() +{ +#ifdef _DEBUG + if (m_sLock.IsInit()) + { + Shutdown(); + } +#endif // _DEBUG +} + // Initialization routine called only by the DbgTransportManager. HRESULT DbgTransportTarget::Init() { diff --git a/src/coreclr/debug/di/dbgtransportmanager.h b/src/coreclr/debug/di/dbgtransportmanager.h index f03dd9a401fecf..5b9cda2f9532f8 100644 --- a/src/coreclr/debug/di/dbgtransportmanager.h +++ b/src/coreclr/debug/di/dbgtransportmanager.h @@ -32,6 +32,7 @@ class DbgTransportTarget { public: DbgTransportTarget(); + ~DbgTransportTarget(); // Given a PID attempt to find or create a DbgTransportSession instance to manage a connection to a // runtime in that process. Returns E_UNEXPECTED if the process can't be found. Also returns a handle that