Why is my thread blocked by a critical partition that is not held by anything?

I have a problem with a critical section in C ++. I get a freezing window, and when I reset the process, I see a thread waiting for a critical section:

16 Id: b10.b88 Suspend: 1 Teb: 7ffae000 Unfrozen ChildEBP RetAddr 0470f158 7c90df3c ntdll!KiFastSystemCallRet 0470f15c 7c91b22b ntdll!NtWaitForSingleObject+0xc 0470f1e4 7c901046 ntdll!RtlpWaitForCriticalSection+0x132 0470f1ec 0415647e ntdll!RtlEnterCriticalSection+0x46 

Line data etc. mean input to a specific critical section. The only problem is that no other threads open this critical section. There is nothing specified by the Windbg team! Locks and resetting the critical section indicates that it is not locked, as seen from the owner null and -1 LockCount in the structure below.

 0:016> dt _RTL_CRITICAL_SECTION 42c2318 _RTL_CRITICAL_SECTION +0x000 DebugInfo : 0x02c8b318 _RTL_CRITICAL_SECTION_DEBUG +0x004 LockCount : -1 +0x008 RecursionCount : -1 +0x00c OwningThread : (null) +0x010 LockSemaphore : 0x00000340 +0x014 SpinCount : 0 0:016> dt _RTL_CRITICAL_SECTION_DEBUG 2c8b318 _RTL_CRITICAL_SECTION_DEBUG +0x000 Type : 0 +0x002 CreatorBackTraceIndex : 0x2911 +0x004 CriticalSection : 0x042c2318 _RTL_CRITICAL_SECTION +0x008 ProcessLocksList : _LIST_ENTRY [ 0x2c8b358 - 0x2c8b2e8 ] +0x010 EntryCount : 1 +0x014 ContentionCount : 1 +0x018 Flags : 0xbaadf00d +0x01c CreatorBackTraceIndexHigh : 0xf00d +0x01e SpareWORD : 0xbaad 

How is this possible? Even at a dead end, where another thread did not name LeaveCriticalSection, I expected to see that the critical section itself was marked as blocked. Does anyone have any suggestions for debugging or possible fixes?

+6
source share
1 answer

This turned out to be an error in which a LeaveCriticalSection is called without the corresponding EnterCriticalSection. This caused the critical section to reduce LockCount and RecursionCount in the following state (by default, LockCount is -1 and RecursionCount is 0):

 0:016> dt _RTL_CRITICAL_SECTION 1092318 _RTL_CRITICAL_SECTION +0x000 DebugInfo : 0x....... _RTL_CRITICAL_SECTION_DEBUG +0x004 LockCount : -2 +0x008 RecursionCount : -1 +0x00c OwningThread : (null) +0x010 LockSemaphore : 0x....... +0x014 SpinCount : 0 

When the subsequent EnterCriticalSection was executed, it hung because the RecursionCount was nonzero - the thread can only accept part of the critical section if RecursionCount is 0. However, it increased LockCount (returning it to -1, seen in my original question), just to confuse the questions.

In general, if you see a critical section stopping a thread using LockCount and RecursionCount -1, it means there has been excessive unlocking.

As for the code calling it:

 if (SysStringLen(bstrState) > 0) CHECKHR_CS( m_pStateManager->SetState(bstrState), &m_csStateManagerLock ); 

And the definition of the error checking macro:

 #define CHECKHR_CS(x, cs) \ EnterCriticalSection(cs); \ if( FAILED(hr = (x)) ) { \ LeaveCriticalSection(cs); \ return hr; \ } \ LeaveCriticalSection(cs); 

The macro lacks curly braces around its contents, so the if statement is not executed, it just skips EnterCriticalSection. Obviously a problem.

+8
source

Source: https://habr.com/ru/post/905789/


All Articles