/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: critsect.c Abstract: This module implements verification functions for critical section interfaces. Author: Daniel Mihai (DMihai) 27-Mar-2001 Revision History: --*/ #include "pch.h" #include "verifier.h" #include "critsect.h" #include "support.h" #include "deadlock.h" #include "logging.h" // // Ntdll functions declarations. // VOID RtlpWaitForCriticalSection ( IN PRTL_CRITICAL_SECTION CriticalSection ); // // The root of our critical section splay tree, ordered by // the address of the critical sections. // PRTL_SPLAY_LINKS CritSectSplayRoot = NULL; // // Global lock protecting the access to our splay tree. // // N.B. // // WE CANNOT HOLD THIS LOCK AND CALL ANY API THAT WILL // TRY TRY TO AQUIRE ANOTHER LOCK (e.g. RtlAllocateHeap) // BECAUSE THE FUNCTIONS BELOW CAN BE CALLED WITH THAT OTHER // LOCK HELD BY ANOTHER THREAD AND WE WILL DEADLOCK. // RTL_CRITICAL_SECTION CriticalSectionLock; BOOL CriticalSectionLockInitialized = FALSE; NTSTATUS CritSectInitialize ( VOID ) { NTSTATUS Status = STATUS_SUCCESS; Status = RtlInitializeCriticalSectionAndSpinCount (&CriticalSectionLock, 0x80000000); if (NT_SUCCESS (Status)) { CriticalSectionLockInitialized = TRUE; } return Status; } VOID CritSectUninitialize ( VOID ) { if (CriticalSectionLockInitialized) { RtlDeleteCriticalSection (&CriticalSectionLock); CriticalSectionLockInitialized = FALSE; } } VOID AVrfpVerifyCriticalSectionOwner ( volatile RTL_CRITICAL_SECTION *CriticalSection, BOOL VerifyCountOwnedByThread ) { HANDLE CurrentThread; PAVRF_TLS_STRUCT TlsStruct; // // Verify that the CS is locked. // if (CriticalSection->LockCount < 0) { // // The CS is not locked // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_OVER_RELEASED | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "critical section over-released or corrupted", CriticalSection, "Critical section address", CriticalSection->LockCount, "Lock count", 0, "Expected minimum lock count", CriticalSection->DebugInfo, "Critical section debug info address"); } // // Verify that the current thread owns the CS. // CurrentThread = NtCurrentTeb()->ClientId.UniqueThread; if (CriticalSection->OwningThread != CurrentThread) { VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_OWNER | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "invalid critical section owner thread", CriticalSection, "Critical section address", CriticalSection->OwningThread, "Owning thread", CurrentThread, "Expected owning thread", CriticalSection->DebugInfo, "Critical section debug info address"); } // // Verify the recursion count. // // ntdll\ia64\critsect.s is using RecursionCount = 0 first time // the current thread is acquiring the CS. // // ntdll\i386\critsect.asm is using RecursionCount = 1 first time // the current thread is acquiring the CS. // #if defined(_IA64_) if (CriticalSection->RecursionCount < 0) { VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "invalid critical section recursion count", CriticalSection, "Critical section address", CriticalSection->RecursionCount, "Recursion count", 0, "Expected minimum recursion count", CriticalSection->DebugInfo, "Critical section debug info address"); } #else //#if defined(_IA64_) if (CriticalSection->RecursionCount < 1) { VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "invalid critical section recursion count", CriticalSection, "Critical section address", CriticalSection->RecursionCount, "Recursion count", 1, "Expected minimum recursion count", CriticalSection->DebugInfo, "Critical section debug info address"); } #endif //#if defined(_IA64_) if (VerifyCountOwnedByThread != FALSE) { // // Verify that the current thread owns at least one critical section. // TlsStruct = AVrfpGetVerifierTlsValue(); if (TlsStruct != NULL && TlsStruct->CountOfOwnedCriticalSections <= 0) { VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_OVER_RELEASED | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "critical section over-released or corrupted", TlsStruct->CountOfOwnedCriticalSections, "Number of critical sections owned by curent thread.", NULL, "", NULL, "", NULL, ""); } } } VOID AVrfpDumpCritSectTreeRecursion( PRTL_SPLAY_LINKS Root, ULONG RecursionLevel ) { ULONG RecursionCount; PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; for (RecursionCount = 0; RecursionCount < RecursionLevel; RecursionCount += 1) { DbgPrint (" "); } CritSectSplayNode = CONTAINING_RECORD (Root, CRITICAL_SECTION_SPLAY_NODE, SplayLinks); DbgPrint ("%p (CS = %p, DebugInfo = %p), left %p, right %p, parent %p\n", Root, CritSectSplayNode->CriticalSection, CritSectSplayNode->DebugInfo, Root->LeftChild, Root->RightChild, Root->Parent); if (Root->LeftChild != NULL) { AVrfpDumpCritSectTreeRecursion (Root->LeftChild, RecursionLevel + 1 ); } if (Root->RightChild != NULL) { AVrfpDumpCritSectTreeRecursion (Root->RightChild, RecursionLevel + 1 ); } } VOID AVrfpDumpCritSectTree( ) { // // N.B. // // This code is dangerous because we are calling DbgPrint // with CriticalSectionLock held. If DbgPrint is using // the heap internally it might need the heap lock // which might be help by another thread waiting for CriticalSectionLock. // We are going to use this function only in desperate cases // for debugging verifier issues with the CS tree. // if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_VERIFIER) != 0) { AVrfpVerifyCriticalSectionOwner (&CriticalSectionLock, FALSE); if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_DUMP_TREE) != 0) { DbgPrint ("================================================\n" "Critical section tree root = %p\n", CritSectSplayRoot); if (CritSectSplayRoot != NULL) { AVrfpDumpCritSectTreeRecursion( CritSectSplayRoot, 0 ); } DbgPrint ("================================================\n"); } } } NTSTATUS AVrfpInsertCritSectInSplayTree ( PRTL_CRITICAL_SECTION CriticalSection ) { PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; PCRITICAL_SECTION_SPLAY_NODE NewCritSectSplayNode; PRTL_SPLAY_LINKS Parent; NTSTATUS Status; ASSERT (CriticalSection->DebugInfo != NULL); Status = STATUS_SUCCESS; NewCritSectSplayNode = NULL; // // The caller must be the owner of the splay tree lock. // if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_VERIFIER) != 0) { AVrfpVerifyCriticalSectionOwner (&CriticalSectionLock, FALSE); DbgPrint ("\n\nAVrfpInsertCritSectInSplayTree( %p )\n", CriticalSection); AVrfpDumpCritSectTree (); } // // Allocate a new node. // // N.B. // // We need to drop CriticalSectionLock while using the heap. // Otherwise we might deadlock. This also means that another thread // might come along and initialize this critical section again. // We don;t expect this to happen often and we will detect this // only later on, in ntdll!RtlCheckForOrphanedCriticalSections. // RtlLeaveCriticalSection (&CriticalSectionLock); try { NewCritSectSplayNode = AVrfpAllocate (sizeof (*NewCritSectSplayNode)); } finally { RtlEnterCriticalSection (&CriticalSectionLock); } if (NewCritSectSplayNode == NULL) { Status = STATUS_NO_MEMORY; } else { // // Initialize the data members of the node structure. // NewCritSectSplayNode->CriticalSection = CriticalSection; NewCritSectSplayNode->DebugInfo = CriticalSection->DebugInfo; // // Insert the node in the tree. // ZeroMemory( &NewCritSectSplayNode->SplayLinks, sizeof(NewCritSectSplayNode->SplayLinks)); // // If the tree is currently empty set the new node as root. // if (CritSectSplayRoot == NULL) { NewCritSectSplayNode->SplayLinks.Parent = &NewCritSectSplayNode->SplayLinks; CritSectSplayRoot = &NewCritSectSplayNode->SplayLinks; } else { // // Search for the right place to insert our CS in the tree. // Parent = CritSectSplayRoot; while (TRUE) { CritSectSplayNode = CONTAINING_RECORD (Parent, CRITICAL_SECTION_SPLAY_NODE, SplayLinks); if (CriticalSection < CritSectSplayNode->CriticalSection) { // // Starting address of the virtual address descriptor is less // than the parent starting virtual address. // Follow left child link if not null. Otherwise // return from the function - we didn't find the CS. // if (Parent->LeftChild) { Parent = Parent->LeftChild; } else { // // Insert the node here. // RtlInsertAsLeftChild (Parent, NewCritSectSplayNode); break; } } else { // // Starting address of the virtual address descriptor is greater // than the parent starting virtual address. // Follow right child link if not null. Otherwise // return from the function - we didn't find the CS. // if (Parent->RightChild) { Parent = Parent->RightChild; } else { // // Insert the node here. // RtlInsertAsRightChild (Parent, NewCritSectSplayNode); break; } } } CritSectSplayRoot = RtlSplay( CritSectSplayRoot ); } } return Status; } PCRITICAL_SECTION_SPLAY_NODE AVrfpFindCritSectInSplayTree ( PRTL_CRITICAL_SECTION CriticalSection ) { PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; PCRITICAL_SECTION_SPLAY_NODE FoundNode; PRTL_SPLAY_LINKS Parent; FoundNode = NULL; // // The caller must be the owner of the splay tree lock. // if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_VERIFIER) != 0) { AVrfpVerifyCriticalSectionOwner (&CriticalSectionLock, FALSE); DbgPrint ("\n\nAVrfpFindCritSectInSplayTree( %p )\n", CriticalSection); AVrfpDumpCritSectTree (); } if (CritSectSplayRoot == NULL) { goto Done; } // // Search for our CS in the tree. // Parent = CritSectSplayRoot; while (TRUE) { CritSectSplayNode = CONTAINING_RECORD (Parent, CRITICAL_SECTION_SPLAY_NODE, SplayLinks); if (CriticalSection == CritSectSplayNode->CriticalSection) { // // Found it. // FoundNode = CritSectSplayNode; break; } else if (CriticalSection < CritSectSplayNode->CriticalSection) { // // Starting address of the virtual address descriptor is less // than the parent starting virtual address. // Follow left child link if not null. Otherwise // return from the function - we didn't find the CS. // if (Parent->LeftChild) { Parent = Parent->LeftChild; } else { break; } } else { // // Starting address of the virtual address descriptor is greater // than the parent starting virtual address. // Follow right child link if not null. Otherwise // return from the function - we didn't find the CS. // if (Parent->RightChild) { Parent = Parent->RightChild; } else { break; } } } Done: return FoundNode; } VOID AVrfpDeleteCritSectFromSplayTree ( PRTL_CRITICAL_SECTION CriticalSection ) { PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; // // The caller must be the owner of the splay tree lock. // if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_VERIFIER) != 0) { AVrfpVerifyCriticalSectionOwner (&CriticalSectionLock, FALSE); DbgPrint ("\n\nAVrfpDeleteCritSectFromSplayTree( %p )\n", CriticalSection); AVrfpDumpCritSectTree (); } // // Find the critical section in the tree and delete it. // CritSectSplayNode = AVrfpFindCritSectInSplayTree (CriticalSection); if (CritSectSplayNode != NULL) { CritSectSplayRoot = RtlDelete (&CritSectSplayNode->SplayLinks); // N.B. // // We need to drop CriticalSectionLock while using the heap. // Otherwise we might deadlock. This also means that another thread // might come along and initialize this critical section again. // We don;t expect this to happen often and we will detect this // only later on, in ntdll!RtlCheckForOrphanedCriticalSections. // RtlLeaveCriticalSection (&CriticalSectionLock); try { AVrfpFree (CritSectSplayNode); } finally { RtlEnterCriticalSection (&CriticalSectionLock ); } } else { if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE ) { VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "critical section not initialized", CriticalSection, "Critical section address", CriticalSection->DebugInfo, "Critical section debug info address", NULL, "", NULL, ""); } } } PCRITICAL_SECTION_SPLAY_NODE AVrfpVerifyInitializedCriticalSection ( volatile RTL_CRITICAL_SECTION *CriticalSection ) { PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; CritSectSplayNode = NULL; // // Sanity test for DebugInfo. // if (CriticalSection->DebugInfo == NULL) { // // This CS is not initialized. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "critical section not initialized", CriticalSection, "Critical section address", CriticalSection->DebugInfo, "Critical section debug info address", NULL, "", NULL, ""); } else if (CriticalSection != NtCurrentPeb()->LoaderLock) { // // The loader lock is not in our tree because it is initialized in ntdll // but is exposed via the pointer in the PEB so various pieces of code // are (ab)using it... // // // Grab the CS splay tree lock. // RtlEnterCriticalSection (&CriticalSectionLock ); try { // // If the CS was initialized it should be in our tree. // CritSectSplayNode = AVrfpFindCritSectInSplayTree ((PRTL_CRITICAL_SECTION)CriticalSection); if (CritSectSplayNode == NULL) { // // This CS is not initialized. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "critical section not initialized", CriticalSection, "Critical section address", CriticalSection->DebugInfo, "Critical section debug info address", NULL, "", NULL, ""); } } finally { // // Release the CS splay tree lock. // RtlLeaveCriticalSection( &CriticalSectionLock ); } } return CritSectSplayNode; } VOID AVrfpVerifyInitializedCriticalSection2 ( volatile RTL_CRITICAL_SECTION *CriticalSection ) { if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE ) { // // Grab the CS splay tree lock. // RtlEnterCriticalSection( &CriticalSectionLock ); try { // // Verify that the CS was initialized. // AVrfpVerifyInitializedCriticalSection (CriticalSection); } finally { // // Release the CS splay tree lock. // RtlLeaveCriticalSection( &CriticalSectionLock ); } } } VOID AVrfpVerifyNoWaitersCriticalSection ( volatile RTL_CRITICAL_SECTION *CriticalSection ) { PAVRF_TLS_STRUCT TlsStruct; PTEB Teb; Teb = NtCurrentTeb(); // // Verify that no thread owns or waits for this CS or // the owner is the current thread. // // ntdll\ia64\critsect.s is using RecursionCount = 0 first time // the current thread is acquiring the CS. // // ntdll\i386\critsect.asm is using RecursionCount = 1 first time // the current thread is acquiring the CS. // if (CriticalSection->LockCount != -1) { if (CriticalSection->OwningThread != Teb->ClientId.UniqueThread || #if defined(_WIN64) CriticalSection->RecursionCount < 0) { #else CriticalSection->RecursionCount < 1) { #endif //#if defined(_IA64_) VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_LOCK_COUNT | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "deleting critical section with invalid lock count", CriticalSection, "Critical section address", CriticalSection->LockCount, "Lock count", -1, "Expected lock count", CriticalSection->OwningThread, "Owning thread"); } else { // // Deleting CS currently owned by the current thread. // Unfortunately we have to allow this because various // components have beein doing it for years. // AVrfpIncrementOwnedCriticalSections (-1); // // For debugging purposes, keep the address of the critical section deleted while // its LockCount was incorrect. Teb->CountOfOwnedCriticalSections might be left > 0 // although no critical section is owned by the current thread in this case. // TlsStruct = AVrfpGetVerifierTlsValue(); if (TlsStruct != NULL) { TlsStruct->IgnoredIncorrectDeleteCS = (PRTL_CRITICAL_SECTION)CriticalSection; } } } } VOID AVrfpFreeMemLockChecks ( VERIFIER_DLL_FREEMEM_TYPE FreeMemType, PVOID StartAddress, SIZE_T RegionSize, PWSTR UnloadedDllName ) { PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; PRTL_SPLAY_LINKS Parent; PVOID TraceAddress = NULL; // // Check for leaked critical sections in this memory range. // if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE ) { // // Grab the CS tree lock. // RtlEnterCriticalSection( &CriticalSectionLock ); // // Search the CS tree. // try { if (CritSectSplayRoot != NULL) { // // Look in the splay tree for any critical sections // that might live in the memory range that isbeing deleted. // Parent = CritSectSplayRoot; while (TRUE) { CritSectSplayNode = CONTAINING_RECORD (Parent, CRITICAL_SECTION_SPLAY_NODE, SplayLinks); if ( (PCHAR)CritSectSplayNode->CriticalSection >= (PCHAR)StartAddress && (PCHAR)CritSectSplayNode->CriticalSection < (PCHAR)StartAddress + RegionSize) { // // Found a CS that is about to be leaked. // if (AVrfpGetStackTraceAddress != NULL) { TraceAddress = AVrfpGetStackTraceAddress ( CritSectSplayNode->DebugInfo->CreatorBackTraceIndex); } else { TraceAddress = NULL; } switch (FreeMemType) { case VerifierFreeMemTypeFreeHeap: // // We are releasing a heap block that contains this CS // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_IN_FREED_HEAP | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "releasing heap allocation containing active critical section", CritSectSplayNode->CriticalSection, "Critical section address", TraceAddress, "Initialization stack trace. Use dds to dump it if non-NULL.", StartAddress, "Heap block address", RegionSize, "Heap block size" ); break; case VerifierFreeMemTypeVirtualFree: // // We are releasing a virtual memory that contains this CS // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_IN_FREED_MEMORY | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "releasing virtual memory containing active critical section", CritSectSplayNode->CriticalSection, "Critical section address", TraceAddress, "Initialization stack trace. Use dds to dump it if non-NULL.", StartAddress, "Memory block address", RegionSize, "Memory block size"); break; case VerifierFreeMemTypeUnloadDll: ASSERT (UnloadedDllName != NULL); // // We are unloading a DLL that contained this CS // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_IN_UNLOADED_DLL | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "unloading dll containing active critical section", CritSectSplayNode->CriticalSection, "Critical section address", TraceAddress, "Initialization stack trace. Use dds to dump it if non-NULL.", UnloadedDllName, "DLL name address. Use du to dump it.", StartAddress, "DLL base address"); break; case VerifierFreeMemTypeUnmap: // // We are unmapping memory that contains this CS // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_IN_FREED_MEMORY | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "Unmapping memory region containing active critical section", CritSectSplayNode->CriticalSection, "Critical section address", TraceAddress, "Initialization stack trace. Use dds to dump it if non-NULL.", StartAddress, "Memory block address", RegionSize, "Memory block size" ); break; default: ASSERT (FALSE); } // // Try to find other leaked critical sections only // with address greater than the current one // (only in the right subtree). // if (Parent->RightChild) { Parent = Parent->RightChild; } else { break; } } else if ((PCHAR)StartAddress < (PCHAR)CritSectSplayNode->CriticalSection) { // // Starting address of the virtual address descriptor is less // than the parent starting virtual address. // Follow left child link if not null. Otherwise // return from the function - we didn't find the CS. // if (Parent->LeftChild) { Parent = Parent->LeftChild; } else { break; } } else { // // Starting address of the virtual address descriptor is greater // than the parent starting virtual address. // Follow right child link if not null. Otherwise // return from the function - we didn't find the CS. // if (Parent->RightChild) { Parent = Parent->RightChild; } else { break; } } } } } finally { // // Release the CS splay tree lock. // RtlLeaveCriticalSection( &CriticalSectionLock ); } } } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif //NTSYSAPI BOOL NTAPI AVrfpRtlTryEnterCriticalSection( PRTL_CRITICAL_SECTION CriticalSection ) { BOOL Result; HANDLE CurrentThread; LONG LockCount; PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; PTEB Teb; BOOL AlreadyOwner; Teb = NtCurrentTeb(); if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE ) { CurrentThread = Teb->ClientId.UniqueThread; // // Verify that the CS was initialized. // CritSectSplayNode = AVrfpVerifyInitializedCriticalSection (CriticalSection); if (CritSectSplayNode != NULL) { InterlockedExchangePointer (&CritSectSplayNode->TryEnterThread, (PVOID)CurrentThread); } // // The TryEnterCriticalSection algorithm starts here. // LockCount = InterlockedCompareExchange( &CriticalSection->LockCount, 0, -1 ); if (LockCount == -1) { // // The CS was unowned and we just acquired it // // // Sanity test for the OwningThread. // if (CriticalSection->OwningThread != 0) { // // The loader lock gets handled differently, so don't assert on it. // if (CriticalSection != NtCurrentPeb()->LoaderLock || CriticalSection->OwningThread != CurrentThread) { // // OwningThread should have been 0. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_OWNER | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "invalid critical section owner thread", CriticalSection, "Critical section address", CriticalSection->OwningThread, "Owning thread", 0, "Expected owning thread", CriticalSection->DebugInfo, "Critical section debug info address"); } } // // Sanity test for the RecursionCount. // if (CriticalSection->RecursionCount != 0) { // // The loader lock gets handled differently, so don't assert on it. // if (CriticalSection != NtCurrentPeb()->LoaderLock) { // // RecursionCount should have been 0. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "invalid critical section recursion count", CriticalSection, "Critical section address", CriticalSection->RecursionCount, "Recursion count", 0, "Expected recursion count", CriticalSection->DebugInfo, "Critical section debug info address"); } } // // Set the CS owner // CriticalSection->OwningThread = CurrentThread; // // Set the recursion count // // ntdll\ia64\critsect.s is using RecursionCount = 0 first time // the current thread is acquiring the critical section. // // ntdll\i386\critsect.asm is using RecursionCount = 1 first time // the current thread is acquiring the critical section. // #if defined(_IA64_) CriticalSection->RecursionCount = 0; #else //#if defined(_IA64_) CriticalSection->RecursionCount = 1; #endif AVrfpIncrementOwnedCriticalSections (1); // // We are updating this counter on all platforms, // unlike the ntdll code that does this only on x86 chk. // We need the updated counter in the TEB to speed up // ntdll!RtlCheckHeldCriticalSections. // Teb->CountOfOwnedCriticalSections += 1; // // All done, CriticalSection is owned by the current thread. // Result = TRUE; } else { // // The CS is currently owned by the current or another thread. // if (CriticalSection->OwningThread == CurrentThread) { // // The current thread is already the owner. // // // Interlock increment the LockCount, and increment the RecursionCount. // InterlockedIncrement (&CriticalSection->LockCount); CriticalSection->RecursionCount += 1; // // All done, CriticalSection was already owned by // the current thread and we have just incremented the RecursionCount. // Result = TRUE; } else { // // Another thread is the owner of this CS. // Result = FALSE; } } } else { // // The CS verifier is not enabled // Result = RtlTryEnterCriticalSection (CriticalSection); if (Result != FALSE) { #if defined(_IA64_) AlreadyOwner = (CriticalSection->RecursionCount > 0); #else AlreadyOwner = (CriticalSection->RecursionCount > 1); #endif //#if defined(_IA64_) if (AlreadyOwner == FALSE) { AVrfpIncrementOwnedCriticalSections (1); #if !DBG || !defined (_X86_) // // We are updating this counter on all platforms, // unlike the ntdll code that does this only on x86 chk. // We need the updated counter in the TEB to speed up // ntdll!RtlCheckHeldCriticalSections. // Teb->CountOfOwnedCriticalSections += 1; #endif //#if !DBG || !defined (_X86_) } } } if (Result != FALSE) { // // Tell deadlock verifier that the lock has been acquired. // if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DEADLOCK_CHECKS) != 0) { AVrfDeadlockResourceAcquire (CriticalSection, _ReturnAddress(), TRUE); } // // We will introduce a random delay // in order to randomize the timings in the process. // if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_RACE_CHECKS)) { AVrfpCreateRandomDelay (); } } return Result; } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif //NTSYSAPI NTSTATUS NTAPI AVrfpRtlEnterCriticalSection( volatile RTL_CRITICAL_SECTION *CriticalSection ) { NTSTATUS Status; HANDLE CurrentThread; LONG LockCount; ULONG_PTR SpinCount; PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; PTEB Teb; BOOL AlreadyOwner; Teb = NtCurrentTeb(); if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE ) { CurrentThread = Teb->ClientId.UniqueThread; // // Verify that the CS was initialized. // CritSectSplayNode = AVrfpVerifyInitializedCriticalSection (CriticalSection); if (CritSectSplayNode != NULL) { InterlockedExchangePointer (&CritSectSplayNode->EnterThread, (PVOID)CurrentThread); } // // The EnterCriticalSection algorithm starts here. // Status = STATUS_SUCCESS; SpinCount = CriticalSection->SpinCount; if (SpinCount == 0) { // // Zero spincount for this CS. // EnterZeroSpinCount: LockCount = InterlockedIncrement (&CriticalSection->LockCount); if (LockCount == 0) { EnterSetOwnerAndRecursion: // // The current thread is the new owner of the CS. // // // Sanity test for the OwningThread. // if (CriticalSection->OwningThread != 0) { // // The loader lock gets handled differently, so don't assert on it. // if (CriticalSection != NtCurrentPeb()->LoaderLock || CriticalSection->OwningThread != CurrentThread) { // // OwningThread should have been 0. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_OWNER | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "invalid critical section owner thread", CriticalSection, "Critical section address", CriticalSection->OwningThread, "Owning thread", 0, "Expected owning thread", CriticalSection->DebugInfo, "Critical section debug info address"); } } // // Sanity test for the RecursionCount. // if (CriticalSection->RecursionCount != 0) { // // The loader lock gets handled differently, so don't assert on it. // if (CriticalSection != NtCurrentPeb()->LoaderLock) { // // RecursionCount should have been 0. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "invalid critical section recursion count", CriticalSection, "Critical section address", CriticalSection->RecursionCount, "Recursion count", 0, "Expected recursion count", CriticalSection->DebugInfo, "Critical section debug info address"); } } // // Set the CS owner // CriticalSection->OwningThread = CurrentThread; // // Set the recursion count // // ntdll\ia64\critsect.s is using RecursionCount = 0 first time // the current thread is acquiring the CS. // // ntdll\i386\critsect.asm is using RecursionCount = 1 first time // the current thread is acquiring the CS. // #if defined(_IA64_) CriticalSection->RecursionCount = 0; #else //#if defined(_IA64_) CriticalSection->RecursionCount = 1; #endif AVrfpIncrementOwnedCriticalSections (1); // // We are updating this counter on all platforms, // unlike the ntdll code that does this only on x86 chk. // We need the updated counter in the TEB to speed up // ntdll!RtlCheckHeldCriticalSections. // Teb->CountOfOwnedCriticalSections += 1; #if DBG && defined (_X86_) CriticalSection->DebugInfo->EntryCount += 1; #endif // // All done, CriticalSection is owned by the current thread. // } else if (LockCount > 0) { // // The CS is currently owned by the current or another thread. // if (CriticalSection->OwningThread == CurrentThread) { // // The current thread is already the owner. // CriticalSection->RecursionCount += 1; #if DBG && defined (_X86_) // // In a chk build we are updating this additional counter, // just like the original function in ntdll does. // CriticalSection->DebugInfo->EntryCount += 1; #endif // // All done, CriticalSection was already owned by // the current thread and we have just incremented the RecursionCount. // } else { // // The current thread is not the owner. Wait for ownership // if (CritSectSplayNode != NULL) { InterlockedExchangePointer (&CritSectSplayNode->WaitThread, (PVOID)CurrentThread); } RtlpWaitForCriticalSection ((PRTL_CRITICAL_SECTION)CriticalSection); if (CritSectSplayNode != NULL) { InterlockedExchangePointer (&CritSectSplayNode->WaitThread, (PVOID)( (ULONG_PTR)CurrentThread | 0x1 )); } // // We have just aquired the CS. // goto EnterSetOwnerAndRecursion; } } else { // // The original LockCount was < -1 so the CS was // over-released or corrupted. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_OVER_RELEASED | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "critical section over-released or corrupted", CriticalSection, "Critical section address", CriticalSection->LockCount, "Lock count", 0, "Expected minimum lock count", CriticalSection->DebugInfo, "Critical section debug info address"); } } else { // // SpinCount > 0 for this CS // if( CriticalSection->OwningThread == CurrentThread ) { // // The current thread is already the owner. // InterlockedIncrement( &CriticalSection->LockCount ); CriticalSection->RecursionCount += 1; #if DBG && defined (_X86_) // // In a chk build we are updating this additional counter, // just like the original function in ntdll does. // CriticalSection->DebugInfo->EntryCount += 1; #endif // // All done, CriticalSection was already owned by the current thread // and we have just incremented the LockCount and RecursionCount. // } else { // // The current thread is not the owner. Attempt to acquire. // EnterTryAcquire: LockCount = InterlockedCompareExchange( &CriticalSection->LockCount, 0, -1 ); if (LockCount == -1) { // // We have just aquired the CS. // goto EnterSetOwnerAndRecursion; } else { // // Look if there are already other threads spinning while // waiting for this CS. // if (CriticalSection->LockCount >= 1) { // // There are other waiters for this CS. // Do not spin, just wait for the CS to be // released as if we had 0 spin count from the beginning. // goto EnterZeroSpinCount; } else { // // No other threads are waiting for this CS. // EnterSpinOnLockCount: if (CriticalSection->LockCount == -1) { // // We have a chance for aquiring it now // goto EnterTryAcquire; } else { // // The CS is still owned. // Decrement the spin count and decide if we should continue // to spin or simply wait for the CS's event. // SpinCount -= 1; if (SpinCount > 0) { // // Spin // goto EnterSpinOnLockCount; } else { // // Spun enough, just wait for the CS to be // released as if we had 0 spin count from the beginning. // goto EnterZeroSpinCount; } } } } } } } else { // // The CS verifier is not enabled // Status = RtlEnterCriticalSection ((PRTL_CRITICAL_SECTION)CriticalSection); if (NT_SUCCESS(Status)) { #if defined(_IA64_) AlreadyOwner = (CriticalSection->RecursionCount > 0); #else AlreadyOwner = (CriticalSection->RecursionCount > 1); #endif //#if defined(_IA64_) if (AlreadyOwner == FALSE) { AVrfpIncrementOwnedCriticalSections (1); #if !DBG || !defined (_X86_) // // We are updating this counter on all platforms, // unlike the ntdll code that does this only on x86 chk. // We need the updated counter in the TEB to speed up // ntdll!RtlCheckHeldCriticalSections. // Teb->CountOfOwnedCriticalSections += 1; #endif //#if !DBG || !defined (_X86_) } } } if (NT_SUCCESS (Status)) { // // Tell deadlock verifier that the lock has been acquired. // if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DEADLOCK_CHECKS) != 0) { AVrfDeadlockResourceAcquire ((PVOID)CriticalSection, _ReturnAddress(), FALSE); } // // We will introduce a random delay // in order to randomize the timings in the process. // if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_RACE_CHECKS)) { AVrfpCreateRandomDelay (); } } return Status; } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif //NTSYSAPI NTSTATUS NTAPI AVrfpRtlLeaveCriticalSection( volatile RTL_CRITICAL_SECTION *CriticalSection ) { NTSTATUS Status; PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; BOOL LeavingRecursion; // // Tell deadlock verifier that the lock has been released. // Note that we need to do this before the actual critical section // gets released since otherwise we get into race issues where some other // thread manages to enter/leave the critical section. // if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DEADLOCK_CHECKS) != 0) { AVrfDeadlockResourceRelease ((PVOID)CriticalSection, _ReturnAddress()); } if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE) { // // Verify that the CS was initialized. // CritSectSplayNode = AVrfpVerifyInitializedCriticalSection (CriticalSection); if (CritSectSplayNode != NULL) { InterlockedExchangePointer (&CritSectSplayNode->LeaveThread, (PVOID)NtCurrentTeb()->ClientId.UniqueThread); // // Verify that the CS is owned by the the current thread. // AVrfpVerifyCriticalSectionOwner (CriticalSection, TRUE); } } // // We need to know if we are just leaving CS ownership recursion // because in that case we don't decrement Teb->CountOfOwnedCriticalSections. // // ntdll\ia64\critsect.s is using RecursionCount = 0 first time // the current thread is acquiring the CS. // // ntdll\i386\critsect.asm is using RecursionCount = 1 first time // the current thread is acquiring the CS. // #if defined(_IA64_) LeavingRecursion = (CriticalSection->RecursionCount > 0); #else LeavingRecursion = (CriticalSection->RecursionCount > 1); #endif //#if defined(_IA64_) Status = RtlLeaveCriticalSection ((PRTL_CRITICAL_SECTION)CriticalSection); if (NT_SUCCESS (Status)) { if (LeavingRecursion == FALSE) { AVrfpIncrementOwnedCriticalSections (-1); #if !DBG || !defined (_X86_) // // We are updating this counter on all platforms, // unlike the ntdll code that does this only on x86 chk. // We need the updated counter in the TEB to speed up // ntdll!RtlCheckHeldCriticalSections. // NtCurrentTeb()->CountOfOwnedCriticalSections -= 1; #endif //#if !DBG || !defined (_X86_) } } return Status; } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif //NTSYSAPI NTSTATUS NTAPI AVrfpRtlInitializeCriticalSectionAndSpinCount( PRTL_CRITICAL_SECTION CriticalSection, ULONG SpinCount ) { NTSTATUS Status; PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; PVOID TraceAddress; Status = STATUS_SUCCESS; if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_INITIALIZE_DELETE) != 0) { DbgPrint ("AVrfpRtlInitializeCriticalSectionAndSpinCount (%p)\n", CriticalSection); } // // We cannot use the CriticalSectionLock after shutdown started, // because the RTL critical sections stop working at that time. // if (RtlDllShutdownInProgress() == FALSE) { // // Grab the CS splay tree lock. // RtlEnterCriticalSection( &CriticalSectionLock ); try { // // Check if the CS is already initialized. // CritSectSplayNode = AVrfpFindCritSectInSplayTree (CriticalSection); if (CritSectSplayNode != NULL && (AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0) { // // The caller is trying to reinitialize this CS. // if (AVrfpGetStackTraceAddress != NULL) { TraceAddress = AVrfpGetStackTraceAddress (CritSectSplayNode->DebugInfo->CreatorBackTraceIndex); } else { TraceAddress = NULL; } VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_ALREADY_INITIALIZED | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "reinitializing critical section", CritSectSplayNode->CriticalSection, "Critical section address", CritSectSplayNode->DebugInfo, "Critical section debug info address", TraceAddress, "First initialization stack trace. Use dds to dump it if non-NULL.", NULL, "" ); } // // Call the regular CS initialization routine in ntdll. // This will allocate heap for the DebugInfo so we need to temporarily // drop CriticalSectionLock, otherwise we can deadlock with the heap lock. // RtlLeaveCriticalSection (&CriticalSectionLock); try { Status = RtlInitializeCriticalSectionAndSpinCount (CriticalSection, SpinCount); } finally { RtlEnterCriticalSection (&CriticalSectionLock); } if (NT_SUCCESS (Status)) { // // Insert the CS in our splay tree. // Status = AVrfpInsertCritSectInSplayTree (CriticalSection); if (!NT_SUCCESS( Status )) { // // Undo the ntdll initialization. This will use the heap to free up // the debug info so we need to temporarily drop CriticalSectionLock, // otherwise we can deadlock with the heap lock. // RtlLeaveCriticalSection (&CriticalSectionLock); try { RtlDeleteCriticalSection (CriticalSection); } finally { RtlEnterCriticalSection (&CriticalSectionLock); } } } } finally { // // Release the CS splay tree lock. // RtlLeaveCriticalSection( &CriticalSectionLock ); } } else { Status = RtlInitializeCriticalSectionAndSpinCount (CriticalSection, SpinCount); } // // Register the lock with deadlock verifier. // if (NT_SUCCESS(Status)) { if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DEADLOCK_CHECKS) != 0) { AVrfDeadlockResourceInitialize (CriticalSection, _ReturnAddress()); } } return Status; } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif //NTSYSAPI NTSTATUS NTAPI AVrfpRtlInitializeCriticalSection( PRTL_CRITICAL_SECTION CriticalSection ) { return AVrfpRtlInitializeCriticalSectionAndSpinCount (CriticalSection, 0); } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif //NTSYSAPI NTSTATUS NTAPI AVrfpRtlDeleteCriticalSection( PRTL_CRITICAL_SECTION CriticalSection ) { NTSTATUS Status; PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_INITIALIZE_DELETE) != 0) { DbgPrint ("AVrfpRtlDeleteCriticalSection (%p)\n", CriticalSection); } // // We cannot use the CriticalSectionLock after shutdown started, // because the RTL critical sections stop working at that time. // if (RtlDllShutdownInProgress() == FALSE) { // // Grab the CS splay tree lock. // RtlEnterCriticalSection( &CriticalSectionLock ); try { if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE ) { // // Verify that the CS was initialized. // CritSectSplayNode = AVrfpVerifyInitializedCriticalSection (CriticalSection); if (CritSectSplayNode != NULL) { // // Verify that no thread owns or waits for this CS or // the owner is the current thread. // AVrfpVerifyNoWaitersCriticalSection (CriticalSection); } } // // Remove the critical section from our splay tree. // AVrfpDeleteCritSectFromSplayTree (CriticalSection); } finally { // // Release the CS splay tree lock. // RtlLeaveCriticalSection( &CriticalSectionLock ); } } // // Regular ntdll CS deletion. // Status = RtlDeleteCriticalSection (CriticalSection); // // Deregister the lock from deadlock verifier structures. // if (NT_SUCCESS(Status)) { if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DEADLOCK_CHECKS) != 0) { AVrfDeadlockResourceDelete (CriticalSection, _ReturnAddress()); } } return Status; } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif VOID AVrfpRtlInitializeResource( IN PRTL_RESOURCE Resource ) { NTSTATUS Status; PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; PVOID TraceAddress; if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_INITIALIZE_DELETE) != 0) { DbgPrint ("AVrfpRtlInitializeResource (%p), CS = %p\n", Resource, &Resource->CriticalSection); } // // We cannot use the CriticalSectionLock after shutdown started, // because the RTL critical sections stop working at that time. // if (RtlDllShutdownInProgress() == FALSE) { // // Grab the CS splay tree lock. // RtlEnterCriticalSection( &CriticalSectionLock ); try { // // Check if the CS is already initialized. // CritSectSplayNode = AVrfpFindCritSectInSplayTree (&Resource->CriticalSection); if (CritSectSplayNode != NULL && (AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0) { // // The caller is trying to reinitialize this CS. // if (AVrfpGetStackTraceAddress != NULL) { TraceAddress = AVrfpGetStackTraceAddress (CritSectSplayNode->DebugInfo->CreatorBackTraceIndex); } else { TraceAddress = NULL; } VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_ALREADY_INITIALIZED | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "reinitializing critical section", CritSectSplayNode->CriticalSection, "Critical section address", CritSectSplayNode->DebugInfo, "Critical section debug info address", TraceAddress, "First initialization stack trace. Use dds to dump it if non-NULL.", NULL, "" ); } // // Call the regular CS initialization routine in ntdll. // This will allocate heap for the DebugInfo so we need to temporarily // drop CriticalSectionLock, otherwise we can deadlock with the heap lock. // RtlLeaveCriticalSection (&CriticalSectionLock); try { RtlInitializeResource (Resource); } finally { RtlEnterCriticalSection (&CriticalSectionLock); } // // Insert the CS in our splay tree. // Status = AVrfpInsertCritSectInSplayTree (&Resource->CriticalSection); if (!NT_SUCCESS( Status )) { // // Undo the ntdll initialization. This will use the heap to free up // the debug info so we need to temporarily drop CriticalSectionLock, // otherwise we can deadlock with the heap lock. // RtlLeaveCriticalSection (&CriticalSectionLock); try { RtlDeleteResource (Resource); } finally { RtlEnterCriticalSection (&CriticalSectionLock); } // // Raise an exception for failure case, just like ntdll does for resources. // RtlRaiseStatus(Status); } } finally { // // Release the CS splay tree lock. // RtlLeaveCriticalSection( &CriticalSectionLock ); } } else { RtlInitializeResource (Resource); } } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif VOID AVrfpRtlDeleteResource ( IN PRTL_RESOURCE Resource ) { PRTL_CRITICAL_SECTION CriticalSection; PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode; CriticalSection = &Resource->CriticalSection; if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_INITIALIZE_DELETE) != 0) { DbgPrint ("AVrfpRtlDeleteResource (%p), CS = %p\n", Resource, CriticalSection); } // // We cannot use the CriticalSectionLock after shutdown started, // because the RTL critical sections stop working at that time. // if (RtlDllShutdownInProgress() == FALSE) { // // Grab the CS splay tree lock. // RtlEnterCriticalSection( &CriticalSectionLock ); try { if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE ) { // // Verify that the CS was initialized. // CritSectSplayNode = AVrfpVerifyInitializedCriticalSection (CriticalSection); if (CritSectSplayNode != NULL) { // // Verify that no thread owns or waits for this CS or // the owner is the current thread. // AVrfpVerifyNoWaitersCriticalSection (CriticalSection); } } // // Remove the critical section from our splay tree. // AVrfpDeleteCritSectFromSplayTree (CriticalSection); } finally { // // Release the CS splay tree lock. // RtlLeaveCriticalSection( &CriticalSectionLock ); } } // // Regular ntdll resource deletion. // RtlDeleteResource (Resource); } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif BOOLEAN AVrfpRtlAcquireResourceShared ( IN PRTL_RESOURCE Resource, IN BOOLEAN Wait ) { // // Verify that the CS was initialized. // AVrfpVerifyInitializedCriticalSection2 (&Resource->CriticalSection); // // Call the regular ntdll function. // return RtlAcquireResourceShared (Resource, Wait); } BOOLEAN AVrfpRtlAcquireResourceExclusive ( IN PRTL_RESOURCE Resource, IN BOOLEAN Wait ) { // // Verify that the CS was initialized. // AVrfpVerifyInitializedCriticalSection2 (&Resource->CriticalSection); // // Call the regular ntdll function. // return RtlAcquireResourceExclusive (Resource, Wait); } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif VOID AVrfpRtlReleaseResource ( IN PRTL_RESOURCE Resource ) { // // Verify that the CS was initialized. // AVrfpVerifyInitializedCriticalSection2 (&Resource->CriticalSection); // // Call the regular ntdll function. // RtlReleaseResource (Resource); } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif VOID AVrfpRtlConvertSharedToExclusive( IN PRTL_RESOURCE Resource ) { // // Verify that the CS was initialized. // AVrfpVerifyInitializedCriticalSection2 (&Resource->CriticalSection); // // Call the regular ntdll function. // RtlConvertSharedToExclusive (Resource); } #if defined(_X86_) #pragma optimize("y", off) // disable FPO #endif VOID AVrfpRtlConvertExclusiveToShared ( IN PRTL_RESOURCE Resource ) { // // Verify that the CS was initialized. // AVrfpVerifyInitializedCriticalSection2 (&Resource->CriticalSection); // // Call the regular ntdll function. // RtlConvertExclusiveToShared (Resource); } LONG AVrfpCSCountHacks = 0; VOID AVrfpIncrementOwnedCriticalSections ( LONG Increment ) { PAVRF_TLS_STRUCT TlsStruct; TlsStruct = AVrfpGetVerifierTlsValue(); if (TlsStruct != NULL) { TlsStruct->CountOfOwnedCriticalSections += Increment; if (TlsStruct->CountOfOwnedCriticalSections < 0 && (AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE ) { VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_OVER_RELEASED | APPLICATION_VERIFIER_CONTINUABLE_BREAK, "critical section over-released or corrupted", TlsStruct->CountOfOwnedCriticalSections, "Number of critical sections owned by curent thread.", NULL, "", NULL, "", NULL, ""); // // Hack: // // If the number of owned critical sections became -1 (over-release) we are // resetting it to 0 because otherwise we will keep breaking for // every future legitimate critical section usage by this thread. // if (TlsStruct->CountOfOwnedCriticalSections == -1) { InterlockedIncrement (&AVrfpCSCountHacks); TlsStruct->CountOfOwnedCriticalSections = 0; } } } }