[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");
    }
This commit is contained in:
Timo Kreuzer 2024-12-12 14:48:29 +02:00
parent 848ad61bba
commit fe7a58d92e

View file

@ -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)