diff --git a/src/coreclr/vm/crst.cpp b/src/coreclr/vm/crst.cpp index 76139417c32d77..647d9f4f4e9979 100644 --- a/src/coreclr/vm/crst.cpp +++ b/src/coreclr/vm/crst.cpp @@ -24,6 +24,10 @@ #ifndef DACCESS_COMPILE Volatile g_ShutdownCrstUsageCount = 0; +#ifdef _DEBUG +thread_local int t_unsafeAnyModeHeldCount = 0; +#endif + //----------------------------------------------------------------- // Initialize critical section //----------------------------------------------------------------- @@ -220,6 +224,18 @@ void CrstBase::Enter(INDEBUG(NoLevelCheckFlag noLevelCheckFlag/* = CRST_LEVEL_CH _ASSERTE(IsCrstInitialized()); +#ifdef _DEBUG + // Detect attempts to take a default (GC_TRIGGERS) lock while holding a CRST_UNSAFE_ANYMODE lock. + // Taking a default lock can trigger a GC, which is illegal while a CRST_UNSAFE_ANYMODE lock is held. + if (!(m_dwFlags & (CRST_UNSAFE_ANYMODE | CRST_UNSAFE_COOPGC | CRST_GC_NOTRIGGER_WHEN_TAKEN))) + { + _ASSERTE_MSG(t_unsafeAnyModeHeldCount == 0, + "Taking a CRST_DEFAULT lock while a CRST_UNSAFE_ANYMODE lock or " + "SimpleRWLock COOPERATIVE_OR_PREEMPTIVE lock is held is illegal. " + "The default lock may trigger a GC, which is not allowed under ANYMODE locks."); + } +#endif + BOOL fIsCriticalSectionEnteredAfterFailingOnce = FALSE; Thread * pThread; @@ -260,6 +276,11 @@ void CrstBase::Enter(INDEBUG(NoLevelCheckFlag noLevelCheckFlag/* = CRST_LEVEL_CH #ifdef _DEBUG PostEnter(); + + if (m_dwFlags & CRST_UNSAFE_ANYMODE) + { + t_unsafeAnyModeHeldCount++; + } #endif if (fToggle) @@ -280,6 +301,11 @@ void CrstBase::Leave() _ASSERTE(IsCrstInitialized()); #ifdef _DEBUG + if (m_dwFlags & CRST_UNSAFE_ANYMODE) + { + t_unsafeAnyModeHeldCount--; + } + PreLeave (); #endif //_DEBUG diff --git a/src/coreclr/vm/crst.h b/src/coreclr/vm/crst.h index fe499fd365b298..280c575aaa8352 100644 --- a/src/coreclr/vm/crst.h +++ b/src/coreclr/vm/crst.h @@ -95,6 +95,12 @@ // Total count of Crst lock of the type (Shutdown) that are currently in use extern Volatile g_ShutdownCrstUsageCount; +#ifdef _DEBUG +// Per-thread count of CRST_UNSAFE_ANYMODE (and equivalent) locks currently held. +// Used to detect illegal acquisition of GC_TRIGGERS locks under ANYMODE locks. +extern thread_local int t_unsafeAnyModeHeldCount; +#endif + // The CRST. class CrstBase { diff --git a/src/coreclr/vm/simplerwlock.cpp b/src/coreclr/vm/simplerwlock.cpp index dfe54a987f10bf..f63cd6d9236217 100644 --- a/src/coreclr/vm/simplerwlock.cpp +++ b/src/coreclr/vm/simplerwlock.cpp @@ -44,6 +44,16 @@ void SimpleRWLock::EnterRead() CheckGCNoTrigger(); #endif //ENABLE_CONTRACTS_IMPL +#ifdef _DEBUG + if (m_gcMode == PREEMPTIVE) + { + _ASSERTE_MSG(t_unsafeAnyModeHeldCount == 0, + "Taking a PREEMPTIVE SimpleRWLock while a COOPERATIVE_OR_PREEMPTIVE lock or " + "CRST_UNSAFE_ANYMODE lock is held is illegal. " + "The PREEMPTIVE lock may trigger a GC, which is not allowed under ANYMODE locks."); + } +#endif + GCX_MAYBE_PREEMP(m_gcMode == PREEMPTIVE); #ifdef _DEBUG @@ -135,6 +145,16 @@ void SimpleRWLock::EnterWrite() CheckGCNoTrigger(); #endif //ENABLE_CONTRACTS_IMPL +#ifdef _DEBUG + if (m_gcMode == PREEMPTIVE) + { + _ASSERTE_MSG(t_unsafeAnyModeHeldCount == 0, + "Taking a PREEMPTIVE SimpleRWLock while a COOPERATIVE_OR_PREEMPTIVE lock or " + "CRST_UNSAFE_ANYMODE lock is held is illegal. " + "The PREEMPTIVE lock may trigger a GC, which is not allowed under ANYMODE locks."); + } +#endif + GCX_MAYBE_PREEMP(m_gcMode == PREEMPTIVE); #ifdef _DEBUG @@ -267,6 +287,11 @@ void SimpleRWLock::PostEnter() INCONTRACT(pThread->BeginNoTriggerGC(__FILE__, __LINE__)); } } + + if (m_gcMode == COOPERATIVE_OR_PREEMPTIVE) + { + t_unsafeAnyModeHeldCount++; + } } //===================================================================== @@ -276,6 +301,11 @@ void SimpleRWLock::PreLeave() { WRAPPER_NO_CONTRACT; + if (m_gcMode == COOPERATIVE_OR_PREEMPTIVE) + { + t_unsafeAnyModeHeldCount--; + } + if (m_countNoTriggerGC > 0) { DWORD countNoTriggerGC = InterlockedDecrement(&m_countNoTriggerGC); diff --git a/src/coreclr/vm/simplerwlock.hpp b/src/coreclr/vm/simplerwlock.hpp index d8b90515a817a0..71780ddce8b30f 100644 --- a/src/coreclr/vm/simplerwlock.hpp +++ b/src/coreclr/vm/simplerwlock.hpp @@ -9,6 +9,10 @@ #include "threads.h" +#ifdef _DEBUG +extern thread_local int t_unsafeAnyModeHeldCount; +#endif + class SimpleRWLock; //-------------------------------------------------------------------------------------------