From c6980093ca8a087fb44628880bd71ef02d0db787 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Thu, 12 Dec 2024 14:48:29 +0200 Subject: [PATCH] [RTL] Update CountOfOwnedCriticalSections in the TEB Useful for debugging. Motivation: With SMP on x64 I found a number of instances where critical sections would be left abandoned, causing lockups. From what I can tell it was exceptions inside rpcrt4, which leave the process in a blocked state. Might or might not be related to x64 / SMP. For real value, you still need to put checks at certain places manually, but this is not super straight forward, because there can be false positives, e.g. when a process is terminated due to an exception, where the abandoned lock is acceptable, and we have this during testing. It's difficult to 100% distinguish this from silent and very bad lock leaks. Problematic code: __try { SomeFunction(); // throws an exception with a CS held, e.g. heap code } __except(1) { DPRINT1("Oops. let's just pretend it's all ok!\n"); } --- sdk/lib/rtl/critical.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sdk/lib/rtl/critical.c b/sdk/lib/rtl/critical.c index c70ff191bbcec..4678230e57b53 100644 --- a/sdk/lib/rtl/critical.c +++ b/sdk/lib/rtl/critical.c @@ -521,6 +521,7 @@ RtlEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) */ CriticalSection->OwningThread = Thread; CriticalSection->RecursionCount = 1; + NtCurrentTeb()->CountOfOwnedCriticalSections++; return STATUS_SUCCESS; } @@ -800,6 +801,7 @@ RtlLeaveCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) * See comment above. */ CriticalSection->OwningThread = 0; + NtCurrentTeb()->CountOfOwnedCriticalSections--; /* Was someone wanting us? This needs to be done atomically. */ if (-1 != InterlockedDecrement(&CriticalSection->LockCount)) @@ -837,8 +839,9 @@ RtlTryEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) if (InterlockedCompareExchange(&CriticalSection->LockCount, 0, -1) == -1) { /* It's ours */ - CriticalSection->OwningThread = NtCurrentTeb()->ClientId.UniqueThread; + CriticalSection->OwningThread = NtCurrentTeb()->ClientId.UniqueThread; CriticalSection->RecursionCount = 1; + NtCurrentTeb()->CountOfOwnedCriticalSections++; return TRUE; } else if (CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread)