/*++ Copyright (c) 1989 Microsoft Corporation 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" VOID RtlpWaitForCriticalSection ( IN PRTL_CRITICAL_SECTION CriticalSection ); //NTSYSAPI BOOL NTAPI AVrfpRtlTryEnterCriticalSection( PRTL_CRITICAL_SECTION CriticalSection ) { BOOL Result; HANDLE CurrentThread; LONG LockCount; if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE ) { // // Sanity test for DebugInfo. // if (CriticalSection->DebugInfo == NULL) { // // This critical section is not initialized. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED, "critical section not initialized", CriticalSection, "Critical section address", CriticalSection->DebugInfo, "Critical section debug info address", NULL, "", NULL, ""); } CurrentThread = NtCurrentTeb()->ClientId.UniqueThread; LockCount = InterlockedCompareExchange( &CriticalSection->LockCount, 0, -1 ); if (LockCount == -1) { // // The critical section 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, "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, "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 critical section 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\ia64\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 #if DBG // // In a chk build we are updating this additional counter, // just like the original function in ntdll does. // NtCurrentTeb()->CountOfOwnedCriticalSections += 1; #endif // // All done, CriticalSection is owned by the current thread. // Result = TRUE; } else { // // The critical section is currently owned by the current or another thread. // if (CriticalSection->OwningThread == CurrentThread) { // // The current thread is already the owner. // // // Inrelock 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 critical section. // Result = FALSE; } } } else { // // The critical section verifier is not enabled // Result = RtlTryEnterCriticalSection (CriticalSection); } return Result; } //NTSYSAPI NTSTATUS NTAPI AVrfpRtlEnterCriticalSection( volatile RTL_CRITICAL_SECTION *CriticalSection ) { NTSTATUS Status; HANDLE CurrentThread; LONG LockCount; ULONG_PTR SpinCount; if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE ) { // // Sanity test for DebugInfo. // if (CriticalSection->DebugInfo == NULL) { // // This critical section is not initialized. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED, "critical section not initialized", CriticalSection, "Critical section address", CriticalSection->DebugInfo, "Critical section debug info address", NULL, "", NULL, ""); } Status = STATUS_SUCCESS; CurrentThread = NtCurrentTeb()->ClientId.UniqueThread; SpinCount = CriticalSection->SpinCount; if (SpinCount == 0) { // // Zero spincount for this critical section. // EnterZeroSpinCount: LockCount = InterlockedIncrement (&CriticalSection->LockCount); if (LockCount == 0) { EnterSetOwnerAndRecursion: // // The current thread is the new owner of the critical section. // // // 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, "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, "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 critical section 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\ia64\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 #if DBG // // In a chk build we are updating these additional counters, // just like the original function in ntdll does. // NtCurrentTeb()->CountOfOwnedCriticalSections += 1; CriticalSection->DebugInfo->EntryCount += 1; #endif // // All done, CriticalSection is owned by the current thread. // } else if (LockCount >= 0) { // // The critical section 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 // // 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 // RtlpWaitForCriticalSection ((PRTL_CRITICAL_SECTION)CriticalSection); // // We have just aquired the critical section. // goto EnterSetOwnerAndRecursion; } } else { // // The original LockCount was < -1 so the critical section was // over-released or corrupted. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_OVER_RELEASED, "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 critical section // if( CriticalSection->OwningThread == CurrentThread ) { // // The current thread is already the owner. // InterlockedIncrement( &CriticalSection->LockCount ); CriticalSection->RecursionCount += 1; #if DBG // // 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 critical section. // goto EnterSetOwnerAndRecursion; } else { // // Look if there are already other threads spinning while // waiting for this critical section. // if (CriticalSection->LockCount >= 1) { // // There are other waiters for this critical section. // Do not spin, just wait for the critical section to be // released as if we had 0 spin count from the beginning. // goto EnterZeroSpinCount; } else { // // No other threads are waiting for this critical section. // EnterSpinOnLockCount: if (CriticalSection->LockCount == -1) { // // We have a chance for aquiring it now // goto EnterTryAcquire; } else { // // The critical section is still owned. // Decrement the spin count and decide if we should continue // to spin or simply wait for the critical section's event. // SpinCount -= 0; if (SpinCount > 0) { // // Spin // goto EnterSpinOnLockCount; } else { // // Spun enough, just wait for the critical section to be // released as if we had 0 spin count from the beginning. // goto EnterZeroSpinCount; } } } } } } } else { // // The critical section verifier is not enabled // Status = RtlEnterCriticalSection ((PRTL_CRITICAL_SECTION)CriticalSection); } return Status; } //NTSYSAPI NTSTATUS NTAPI AVrfpRtlLeaveCriticalSection( volatile RTL_CRITICAL_SECTION *CriticalSection ) { NTSTATUS Status; HANDLE CurrentThread; if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE) { // // Sanity test for DebugInfo. // if (CriticalSection->DebugInfo == NULL) { // // This critical section is not initialized. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED, "critical section not initialized", CriticalSection, "Critical section address", CriticalSection->DebugInfo, "Critical section debug info address", NULL, "", NULL, ""); } // // Verify that the critical section is locked before releasing. // if (CriticalSection->LockCount < 0) { // // The critical section is not locked // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_OVER_RELEASED, "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 critical section. // CurrentThread = NtCurrentTeb()->ClientId.UniqueThread; if (CriticalSection->OwningThread != CurrentThread) { VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_OWNER, "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 critical section. // // ntdll\ia64\critsect.asm is using RecursionCount = 1 first time // the current thread is acquiring the critical section. // #if defined(_IA64_) if (CriticalSection->RecursionCount < 0) { VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT, "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, "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_) } Status = RtlLeaveCriticalSection ((PRTL_CRITICAL_SECTION)CriticalSection); return Status; } //NTSYSAPI NTSTATUS NTAPI AVrfpRtlInitializeCriticalSection( PRTL_CRITICAL_SECTION CriticalSection ) { NTSTATUS Status; // // If we could have pointers to ntdll!RtlCriticalSectionLock and // RtlCriticalSectionList we could check for double-initialized // critical sections here. // Status = RtlInitializeCriticalSection (CriticalSection); return Status; } //NTSYSAPI NTSTATUS NTAPI AVrfpRtlInitializeCriticalSectionAndSpinCount( PRTL_CRITICAL_SECTION CriticalSection, ULONG SpinCount ) { NTSTATUS Status; // // If we could have pointers to ntdll!RtlCriticalSectionLock and // RtlCriticalSectionList we could check for double-initialized // critical sections here. // Status = RtlInitializeCriticalSectionAndSpinCount (CriticalSection, SpinCount); return Status; } //NTSYSAPI NTSTATUS NTAPI AVrfpRtlDeleteCriticalSection( PRTL_CRITICAL_SECTION CriticalSection ) { NTSTATUS Status; if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 && RtlDllShutdownInProgress() == FALSE ) { // // Sanity test for DebugInfo. // if (CriticalSection->DebugInfo == NULL) { // // This critical section is not initialized. // VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED, "critical section not initialized", CriticalSection, "Critical section address", CriticalSection->DebugInfo, "Critical section debug info address", NULL, "", NULL, ""); } // // Verify that no thread owns or waits for this critical section or // the owner is the current thread. // // ntdll\ia64\critsect.s is using RecursionCount = 0 first time // the current thread is acquiring the critical section. // // ntdll\ia64\critsect.asm is using RecursionCount = 1 first time // the current thread is acquiring the critical section. // if (CriticalSection->LockCount != -1 && (CriticalSection->OwningThread != NtCurrentTeb()->ClientId.UniqueThread || #if defined(_IA64_) CriticalSection->RecursionCount < 0) ) { #else CriticalSection->RecursionCount < 1) ) { #endif //#if defined(_IA64_) VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_LOCK_COUNT, "deleting critical section with invalid lock count", CriticalSection, "Critical section address", CriticalSection->LockCount, "Lock count", -1, "Expected lock count", CriticalSection->OwningThread, "Owning thread"); } } Status = RtlDeleteCriticalSection (CriticalSection); return Status; }