HowTo: Track down a handle leak in your code - trace the stacks
Hi
This is also a test in posting images in my blog ..
In this scenario you may have noticed a handle leak in an application via perfmon using the Process counters:
Or simply via Task Manager :
Once you know which process is leaking handles you can approach it in a more direct manner. Depending on the code size it may be easy to track down where the bug is, but in my case .. the OS is a pretty big piece of code to try and find the leak without some help. I suppose I could set a break on access for the handle table and log the stacks everytime we increment the count, but that could get ugly.
I think this would be easier...
Download and install Application verifier
Configure it to track handles:
Let the application run for a bit – presumably leaking like a sieve.
Attach the debugger to the process, and make sure you have good symbols. For this example I used the Microsoft public symbols server:
0:005> .sympath
Symbol search path is: SRV*c:\symbols*https://msdl.microsoft.com/download/symbols
0:005> !htrace
--------------------------------------
Handle = 0x000001A6 - CLOSE
Thread ID = 0x000008B4, Process ID = 0x00000564
0x77DA2DDC: ADVAPI32!BaseRegCloseKeyInternal+0x0000004F
0x77DA2D8D: ADVAPI32!RegCloseKey+0x00000075
0x7738D531: SHELL32!CDrivesFolder::_FillIDDrive+0x0000007F
0x7738EF07: SHELL32!CDrivesFolder::ParseDisplayName+0x00000088
0x7738D68A: SHELL32!CRegFolder::ParseDisplayName+0x0000007A
0x7738ECC0: SHELL32!CDesktopFolder::_ChildParseDisplayName+0x00000020
0x7738EC00: SHELL32!CDesktopFolder::ParseDisplayName+0x0000007C
0x7738D68A: SHELL32!CRegFolder::ParseDisplayName+0x0000007A
0x773916AC: SHELL32!SHSimpleIDListFromFindData+0x00000077
0x773917A1: SHELL32!SHGetFileInfoW+0x0000011C
0x762B205A: comdlg32!GetFileTitleX+0x0000007A
<snip>
0x77DA2DDC: ADVAPI32!BaseRegCloseKeyInternal+0x0000004F
0x77DA2D8D: ADVAPI32!RegCloseKey+0x00000075
0x772B3440: SHLWAPI!CAssocShellElement::SetString+0x00000055
0x77395956: SHELL32!CAssocArray::_GetElement+0x0000003B
0x77395C53: SHELL32!CAssocArray::_FirstElement+0x00000016
0x773996EA: SHELL32!CFileSysItemString::AssocCreate+0x0000009C
0x773F7DA9: SHELL32!CFileSysItemString::_ClassFlags+0x00000060
0x7738E11B: SHELL32!CFileSysItemString::GetJunctionClsid+0x0000007B
0x7738FDAC: SHELL32!CFSFolder::GetAttributesOf+0x00000273
0x762B348E: comdlg32!SHGetAttributes+0x00000051
0x762B5D5F: comdlg32!CFileOpenBrowser::IncludeObject+0x0000005C
--------------------------------------
Handle = 0x000005DC - OPEN
Thread ID = 0x000008B4, Process ID = 0x00000564
0x77DA4985: ADVAPI32!BaseRegOpenClassKeyFromLocation+0x0000011A
0x77DA4873: ADVAPI32!BaseRegOpenClassKey+0x0000005F
0x77DA4D60: ADVAPI32!LocalBaseRegOpenKey+0x000000E4
0x77DA1949: ADVAPI32!RegOpenKeyExW+0x0000010B
0x5A61ABD0: verifier!AVrfpRegOpenKeyExW+0x00000060
0x772B3305: SHLWAPI!CRegistrySource::Init+0x0000003A
0x772B32B7: SHLWAPI!QuerySourceCreateFromKey+0x0000004F
0x77298F1A: SHLWAPI!CAssocProgidElement::_InitSource+0x00000073
0x772B3440: SHLWAPI!CAssocShellElement::SetString+0x00000055
0x77395956: SHELL32!CAssocArray::_GetElement+0x0000003B
--------------------------------------
Handle = 0x00000600 - CLOSE
Thread ID = 0x000008B4, Process ID = 0x00000564
0x77DA4E2A: ADVAPI32!BaseRegConstructUserClassPrefix+0x0000005C
0x77DA4DEC: ADVAPI32!BaseRegTranslateToUserClassKey+0x00000020
0x77DA4901: ADVAPI32!BaseRegOpenClassKeyFromLocation+0x00000084
0x77DA4873: ADVAPI32!BaseRegOpenClassKey+0x0000005F
0x77DA4D60: ADVAPI32!LocalBaseRegOpenKey+0x000000E4
0x77DA1949: ADVAPI32!RegOpenKeyExW+0x0000010B
--------------------------------------
Parsed 0x892 stack traces.
Dumped 0x892 stack traces
If you are doing this from Kernel, you specify the process and you will see the stacks reflect the calls to the Object Manager to open and close the handles.
NOTE: if you cant do a live debug you can get a kernel dump of the machine and it will contain the stacks. A user mode dump will not have the stack data.
Now, unfortunately there is no snap comparison tool like UMDH to compare and log the 'bad stacks' but it wouldnt be too hard to do this when you look at unmatched opens.
I am pretty sure this only works on XP and greater...
July 17 2005- added this:
Looks like its user mode only..
---------------------------------------------------------
!htrace -enable
...
!htrace -snapshot
... leak code
!htrace -diff
---------------------------------------------------------
Hope it helps someone one day ;o)
Spat
Additonal random posts I found interesting this morning:
New Rootkit Revealer available!
Why does the debugger show me the wrong virtual function?
HOWTO: Setup for SmartPhone Development (UPDATED)
Ourmedia.org and Brightcove: 2 sides of the broadband content coin - this one is pretty cool. I may try to host some video here soon.
[ edit -- guess that didnt work so well eh? I'll try to fix it in a bit -- tips from anyone else on how to do this? :: UPDATE - looks like it did work after all]
Comments
- Anonymous
July 10, 2006
Very good!!! :-)
silvstedt victoria - Anonymous
October 21, 2010
I have a serious handle leak in "System". Can you assist me from this point? Thanks