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
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;
|
|
}
|
|
}
|
|
}
|
|
}
|