Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2309 lines
68 KiB

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