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]