Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results
The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.
Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/
I am tracing critical section leaks and trying to figure out how to locate the source code behind which holds the critical section. I have an app which contains PDB file and I created memory dump.
For example, critical section below is one of the most busiest (high ContentionCount) and I would like to understand where in the source is the critical section created. For some reason I am not able to use Display Type (dt) command for some critical sections, for some critical sections dt command works fine.
Does all critical sections listed in user mode memory dump belong to process or is it possible that some belong to drivers ?
Any guidelines how to track down the location of critical section ?
0:000> !locks -v CritSec +adf30be8 at 0000003eadf30be8 LockCount NOT LOCKED RecursionCount 0 OwningThread 0 EntryCount 0 ContentionCount 797047 0:000> dt _RTL_CRITICAL_SECTION 0000003eadf30be8 myapp!_RTL_CRITICAL_SECTION +0x000 DebugInfo : 0x00000089`3a3d81a0 _RTL_CRITICAL_SECTION_DEBUG +0x008 LockCount : 0n-1 +0x00c RecursionCount : 0n0 +0x010 OwningThread : (null) +0x018 LockSemaphore : 0xffffffff`ffffffff Void +0x020 SpinCount : 0x200013c 0:000> dx -r1 ((myapp!_RTL_CRITICAL_SECTION_DEBUG *)0x893a3d81a0) ((myapp!_RTL_CRITICAL_SECTION_DEBUG *)0x893a3d81a0) : 0x893a3d81a0 [Type: _RTL_CRITICAL_SECTION_DEBUG *] [+0x000] Type : 0x0 [Type: unsigned short] [+0x002] CreatorBackTraceIndex : 0x0 [Type: unsigned short] [+0x008] CriticalSection : 0x3eadf30be8 [Type: _RTL_CRITICAL_SECTION *] [+0x010] ProcessLocksList [Type: _LIST_ENTRY] [+0x020] EntryCount : 0x0 [Type: unsigned long] [+0x024] ContentionCount : 0x797047 [Type: unsigned long] [+0x028] Flags : 0x0 [Type: unsigned long] [+0x02c] CreatorBackTraceIndexHigh : 0x0 [Type: unsigned short] [+0x02e] SpareWORD : 0x74 [Type: unsigned short] 0:000> dx -r1 ((myapp!_RTL_CRITICAL_SECTION *)0x3eadf30be8) ((myapp!_RTL_CRITICAL_SECTION *)0x3eadf30be8) : 0x3eadf30be8 [Type: _RTL_CRITICAL_SECTION *] [+0x000] DebugInfo : 0x893a3d81a0 [Type: _RTL_CRITICAL_SECTION_DEBUG *] [+0x008] LockCount : -1 [Type: long] [+0x00c] RecursionCount : 0 [Type: long] [+0x010] OwningThread : 0x0 [Type: void *] [+0x018] LockSemaphore : 0xffffffffffffffff [Type: void *] [+0x020] SpinCount : 0x200013c [Type: unsigned __int64] 0:000> dt 0000003eadf30be8 Symbol not found at address 0000003eadf30be8. 0:000> ln 0000003eadf30be8 Browse module Set bu breakpoint
Upcoming OSR Seminars | ||
---|---|---|
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead! | ||
Writing WDF Drivers | 7 Dec 2020 | LIVE ONLINE |
Internals & Software Drivers | 25 Jan 2021 | LIVE ONLINE |
Developing Minifilters | 8 March 2021 | LIVE ONLINE |
Comments
No, you have issued two very different commands.
That tells the debugger to pretend that this address is an 'RTL_CRITICAL_SECTION' structure and show you the contents.
That tells the debugger to go figure out which module that contains that address, then go find the symbol file for that module, then look up that address in the symbol file, then figure out what type of thing is stored at that address, and dump it. If that address is not in one of your modules, then you won't have symbol files. And if the structure was allocated from the heap, the debugger won't be able to find anything at all.
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
Tim, thanks for explanations.
Now I am still kind of stuck, I would like to find the module who created that very busy critical section. And other sections I don't have reference in my symbol file.
The memory dump in question was created using ProcDump -mp (Write a dump file with thread and handle information, and all read/write process memory).
!locks -v
give me a true output and I can suspect critical section leak when comparing user mode memory dump output over time (lets say 24 hour) ?I'm not sure what you mean by "critical section leak". Unlike other synchronization objects, critical sections aren't centrally allocated -- the user allocates the space from normal memory. "!locks -v" is supposed to show you every critical section that has been initialized in this process, but it can't know about kernel locks. No one knows which code initialized the section. You could set a breakpoint at RtlInitializeCriticalSection and do a traceback to figure out who called it.
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
By leak I mean that the output of
!locks -v
grows over time.Wait 24 hours
I created 2 very simple test applications using VS2008:
1) do not call any InitializeCriticalSection
2) call 100 x InitializeCriticalSection, see example below.
Both times windbg did not indicate any increase of critical sections. It reported 4 ciritical sections, none of them were initialized by test app.
So, I still do not follow which module created 4 ciritical sections. I assume that they are coming from CRT or any other system module listed by
!peb
?Any reason why I wasn't able to see the following static critical sections listed under windbg ?
All Your Code Does is initialize 256 CriticalSections.
why do you think !locks will show some increase or decrease ?
what is the reason for the 24 hours wait before trying to do another !locks ?
if this were not a dump but a live session you could try !gflags "user stack trace database"
to locate your creation with !cs -o
the lock count increases only if a thread Entered Your Critical Section and successfully acquired it
the lock count will decrease if the thread that acquired the CriticalSection Relinquished it with LeaveCriticalSection
A thread can die without relinquishing the ownership of Critical Section
if a CriticalSection is owned and locked by a thread any other thread that tried to acquire it will not be granted ownership and will go into a WaitState if the other thread went into a waitstate the contention count will be increased .
check the code and windbg display
this code Initialises one CriticalSection.
and creates ten threads.
each one of the thread will try to acquire ownership of the criticalsection
the first thread will succeed but it has a 10 second long work to perform before it can relinquish the CriticalSection
so all other thread will get into a wait state so the contention count will be 9 when
when you reach the main there is no Critical Section
on executing the InitializeCritical Section() Api a critical section is initialized with NULL will be created
Setting a breakpoint on the ThreadProc and continuing all the threads will be created and the first hit on ThreadProc will happen
if you keep on stepping you can see the contetion count increasing upto 9 when all the ten threads have called thier ThreadProcs thecounter increased by 1 by the thread which suceeded to acquire the CriticalSection .
the gflags +ust is also enabled so stack trace is also available
There seems to be a misunderstanding. I am not tracing the owner thread of the lock. I am trying to understand and "interpret" the output of the
!locks -v
command. The question is why does the count of locks grows over time. Is it a leak ?!locks -v
is extremely slow, it takes 30 minutes to list the output to the console or to file. Considering there are more than 100K locks in the output. Majority of these locks in the output do not belong to my process, at least lock address points to "Symbol not found at address".Can anyone create a sample program that will demonstrate the "leaking" locks problem ? I would understand the locks issue more clearly if I was able to re-create the output of memory dump. For example, create memory dump, let test process run, create another memory dump -- the output of
!locks
command needs to be an increasing number.No ntsdexts!locks output is for the current process only
if the output contains > 100K then your process must behaving them
yes !locks -v is a time consuming operation
if you need a very quick confirmation of the count you can run this script to get the count of CriticalSections
executing the script you can see the comparative time
and
Can someone demonstrate C code that will generate an increasing locks output ?
I hope explorer.exe is an acceptable program
As just using commctrl File->Open Dialog can show the locks increasing
To Check you can debug windbg with windbg
write 2 scripts as follows
Script 1
Script 2
The first script disables all output in command window
and sets a prompt command which will always be executed
when ctrl+break or alt+delete is hit or DebugMenu->break is Clicked
Second Script is just a fast critical section counter
Same as !locks output's last line which says scanned xxx cs
execute
this will open windbg as debugger execute the prompt script and run the
debuggee
hit ctrl+break
you will see an output like
you can run !locks or !locks-v if you want to just in case
hit g to continue and in the debuggee use file->open
but do not select any file
return to the debugger and hit ctrl+break
you will see a tremndous increase in locks
hit g to continue and hit cancel in File->Open Dialog and return to
repeat in debugger
you can see critical sections count has gone down considerably
Repeat but this time click some more icons like desktop / etc and break
select a file as debugees's debugee
as you can see if you had dumped the process in these scenerios
you will get different counts of locks so count of locks isn't a suitable metric to prove or disprove leak