diff --git a/src/coreclr/debug/di/dbgtransportmanager.cpp b/src/coreclr/debug/di/dbgtransportmanager.cpp index 677d30854b6503..de3ee71b093944 100644 --- a/src/coreclr/debug/di/dbgtransportmanager.cpp +++ b/src/coreclr/debug/di/dbgtransportmanager.cpp @@ -74,7 +74,9 @@ DbgTransportTarget::DbgTransportTarget() // Initialization routine called only by the DbgTransportManager. HRESULT DbgTransportTarget::Init() { - m_sLock.Init("DbgTransportTarget Lock", RSLock::cLockFlat, RSLock::LL_DBG_TRANSPORT_TARGET_LOCK); + // The Unix loader does not invoke DbgDllMain DLL_PROCESS_DETACH for mscordbi at process exit, + // so Shutdown() may never run. Mark the lock as allowing leak to skip the destructor assert. + m_sLock.Init("DbgTransportTarget Lock", RSLock::cLockFlat | RSLock::cLockAllowLeak, RSLock::LL_DBG_TRANSPORT_TARGET_LOCK); return S_OK; } diff --git a/src/coreclr/debug/di/rspriv.h b/src/coreclr/debug/di/rspriv.h index 6caf7a556bf06f..076720e7999b46 100644 --- a/src/coreclr/debug/di/rspriv.h +++ b/src/coreclr/debug/di/rspriv.h @@ -716,6 +716,10 @@ class RSLock // to count this lock in m_cTotalDbgApiLocks, which is asserted to be 0 on entry // to public APIs. Example of such a lock: LL_SHIM_PROCESS_DISPOSE_LOCK cLockNonDbgApi = 0x00000004, + + // Skip the leak assert in the destructor. Use for static-lifetime locks + // whose owning shutdown path is not guaranteed to run. + cLockAllowLeak = 0x00000008, }; // To prevent deadlocks, we order all locks. diff --git a/src/coreclr/debug/di/rspriv.inl b/src/coreclr/debug/di/rspriv.inl index c88416b505c247..755de8d2bc7a64 100644 --- a/src/coreclr/debug/di/rspriv.inl +++ b/src/coreclr/debug/di/rspriv.inl @@ -504,9 +504,9 @@ inline RSLock::RSLock() inline RSLock::~RSLock() { - // If this lock is still ininitialized, then no body ever deleted the critical section - // for it and we're leaking. - CONSISTENCY_CHECK_MSGF(!IsInit(), ("Leaking Critical section for RS Lock '%s'", m_szTag)); + // If this lock is still initialized, then nobody ever deleted the critical section + // for it and we're leaking. cLockAllowLeak opts out of this assert. + CONSISTENCY_CHECK_MSGF(!IsInit() || (m_eAttr & cLockAllowLeak), ("Leaking Critical section for RS Lock '%s'", m_szTag)); } #endif