Search code examples
windowswindbgresource-leak

Where was handle allocated?


I am wondering if it is possible to use WinDbg to kwown the callstack that lead to the allocation of a handle.

For example:

#include <windows.h>
#include <conio.h>
#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    cout << "Press ENTER to leak handles." << endl;

    _getch();

    cout << "Leaking handles" << endl;

    for (int i = 0; i < 100; ++i)
    {
        HANDLE h = CreateEvent(NULL, FALSE, FALSE, NULL);
        if (h != NULL)
        {
            cout << ".";
        }
    }

    cout << "Handles leaked. Press ENTER to exit." << endl;

    _getch();

    return 0;
}

After building this sample and firing it up in WinDbg is it possible to get the callstack that allocated the handles, in the sample above the line:

HANDLE h = CreateEvent(NULL, FALSE, FALSE, NULL);

I am poking around with the !handle command but no progress so far.

This is pertinent to handle leak analysis. I am aware of !htrace -enable and !htrace -diff but this is a different usage scenario (unless there is some way to combine or other usage vector for it, please provide information).


Solution

  • Found what seems to be a solution:

    1. Enable traces by using !htrace -enable
    2. Run the program and wait for handle leaks
    3. Check the handles of the program and peak one for analysis with !htrace <handle>
    0:001> !htrace -enable
    Handle tracing enabled.
    Handle tracing information snapshot successfully taken.
    0:001> g
    0:001> !handle
    ...
    
    Handle 7d8
      Type          Event
    ...
    111 Handles
    Type            Count
    Event           103
    File            3
    Port            1
    Directory       2
    WindowStation   1
    KeyedEvent      1
    0:001> !htrace 7d8
    --------------------------------------
    Handle = 0x000007d8 - OPEN
    Thread ID = 0x00000fc4, Process ID = 0x000017a8
    
    0x0040106d: TestMemHandleLeak!wmain+0x0000006d
    0x0040151b: TestMemHandleLeak!__tmainCRTStartup+0x0000010f
    0x7c817077: kernel32!BaseProcessStart+0x00000023
    
    --------------------------------------
    Parsed 0x64 stack traces.
    Dumped 0x1 stack traces.
    

    And to get the line of code at that address I did:

    0:001> ln TestMemHandleLeak!wmain+0x0000006d
    f:\temp\windowsapplication3\testmemhandleleak\testmemhandleleak.cpp(22)