windows-nt/Source/XPSP1/NT/base/win32/verifier/critsect.c
2020-09-26 16:20:57 +08:00

752 lines
23 KiB
C

/*++
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;
}