Tuesday, January 25, 2011

LeakMon - Track Handle leak, GDI leak and Memory leak in your applications

LeakMon is a light weight resource leak tracking utility which can track Memory leaks, GDI object leaks and handle leaks of a process. This tool is suitable mainly for tracking down the leaks that happens in between an operation.

Downloads
LeakMon

[Download from Codeproject]
LeakMon

Prerequisite

• You need to have installed VS2010 or Microsoft Visual C++ 2010 Redistributable Package.

Visual C++ 2010 Redistributable Package can be downloaded from the below path

For 32 bit applications (4.8 MB)

http://www.microsoft.com/downloads/en/details.aspx?familyid=A7B7A05E-6DE6-4D3A-A423-37BF0912DB84&displaylang=en

For 64 bit application (5.5 MB)
http://www.microsoft.com/downloads/en/details.aspx?familyid=BD512D9E-43C8-4655-81BF-9350143D5867&displaylang=en

How to use

This tool consists of three binaries, Injector, HookDll and a DumpViewer.
To start with, run the Injector.exe.



• Refresh :- Refresh the process list
• Inject :- Injects the hook DLL to the target process to start tracking of the leak
• Dump : - Dumps the leak found so far to a file.
• Reset: :- Ignore/Clear all the leaks found up to this point.
• PDB Info : - After Injecting the DLL to the target process, you can click this button to view and make sure that all the pdb’s of necessary DLL’s are loaded correctly.

Using the injector.exe, select the target process that you want to debug. In this case say "MultiThread.exe". Now to start tracking, click the “Inject” button. On doing this, a settings window as in the below figure will pop up. (Note: The settings window is actually shown in the target process' context).



The setting window allows you to choose the “type of leak” you want to track. The types include memory leak, GDI leak and Handle leak.

The next option in the Settings dialog is “Stack Depth”. The value in the stack depth controls the number of functions that will be retrieved while tracking the allocation call stack. The value you enter in here can considerably affect the speed of the application. Lesser the value, the faster the application will be.

Collecting the call stack will never be perfect, without proper PDB files. So to get proper call stack information, specify the path PDB files of the binaries used in your application. Without the pdb’s of Microsoft dll’s such as MSVCRT.dll, MFCxx.dll etc, you will not be able to see the call stack of memory allocated using new and new[] sometimes. If you don’t have the symbols for Microsoft dlls, click on the “Add Symbol server”. Also it is a must that you have to specify the Folder in which the LeakMon binary resides. (“T:\LeakMon” in the below sample). Once you have set all the necessary pdb’s path click OK. The tracking starts from this moment

So now, once you have finished your processing and want to see all the allocations that haven’t de-allocated, press the “Dump” button in the injector. If there is some leak, it will prompt you with a save dialog, though which you can save the leak information file.

Analyzing the leak dump file


I will explain the format of the dump file with the following example. Consider the below code


i.e. The sequence of calling is in the order


CMulitThreadDlg::OnBnClickedButton1()->func1()->func2().

Now the information regarding the memory leak in the above code will look as follows.


-->Bytes allocated -- 76

_heap_alloc_base f:\dd\vctools\crt_bld\self_x86\crt\src\malloc.c(105)
_heap_alloc_dbg_impl f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c(427)
_nh_malloc_dbg_impl f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c(239)
_nh_malloc_dbg f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c(296)
_malloc_dbg f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c(160)
operator new f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\afxmem.cpp(407)
operator new[] f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\afxmem.cpp(442)
operator new[] f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\afxmem.cpp(67)
func2 t:\naveen\pgms\cpp\2008\mulitthread\mulitthreaddlg.cpp(178)
func1 t:\naveen\pgms\cpp\2008\mulitthread\mulitthreaddlg.cpp(184)
CMulitThreadDlg::OnBnClickedButton1 t:\naveen\pgms\cpp\2008\mulitthread\mulitthreaddlg.cpp(189)
_AfxDispatchCmdMsg f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\cmdtarg.cpp(82)
CCmdTarget::OnCmdMsg f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\cmdtarg.cpp(381)
CDialog::OnCmdMsg f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\dlgcore.cpp(85)
CWnd::OnCommand f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp(2364)
CWnd::OnWndMsg f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp(1769)
CWnd::WindowProc f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\wincore.cpp(1755)
Starting from the top function, traverse down, until you find a function from your file. In the above case, func2().  So it can be concluded that, some memory that has allocated from the func2() haven’t de-allocated.

Analyzing the leak with DumpViewer

Even though you can viewer the dump file in any text editor, DumpViewer provides you some extra features that are really handy. Most of the features are self explanatory. One of the main feature is that, when you double click on a particular function in the tree, it will open the source file in visual studio with the line in which leak occurred as selected.


Under the Hood

This application basically works by hooking all the possible functions that allocates and de allocates a resource. For example when tracking memory leak it hooks the memory allocation API's such as HeapAlloc, HeapFree, VirtualAlloc, VirtualFree etc. A more detailed step by step explanation of this tool will be posted in next posts.

I have tried my best to remove the bugs in this application. But still if you encounter any bugs, let me know. Suggestions or improvements are highly appreciated.

[Update] :- Part 2  Leakmon- Under the hood

16 comments:

  1. Hi, this looks like an interesting project, so I wondered whether you could open source it somewhere (like on codeplex, sourceforge or google code) so it could become a (compatible?) replacement for valgrind on Windows.
    This would mean that visualization tools must not be reinvented and also your app could be extended so it works as a profiling app. If I can help you anyhow just say how.

    ReplyDelete
  2. Hi SaroEngels,

    I am happy to make this project as open source. Please let me know which site is good. I mean, I haven't worked in any open source project so far, so I dont know which site is better. Please contact me at nave432@gmail.com

    ReplyDelete
  3. I have created feature request for your LeakMon DumpViewer tool:

    http://code.google.com/p/leakmon/issues/detail?id=1

    ReplyDelete
  4. Thanks Rolf. I will definitly make this changes and update in next version. Also let me see whether I can add support to browse VLD file also.

    Thanks

    ReplyDelete
  5. You should have said that this project is just an overwrite from Matt Pietreks "GDIDebug".
    Steel code isn't a fine manner!

    Cheers

    ReplyDelete
  6. maddin, either you havent understood what my application does or what Matt's application does. And you wont be able to show me a single line of look alike code. After all, the GDI leakage was added only at a later stage of application development. For 2, 3 years this one just used to track memory leaks.

    First of GDI leak is one among the 3 leaks that this application can track.
    Second, it is not possible to view the call stack of allocation in the other application, which is the what Leakmon mainly does.

    ReplyDelete
  7. good works.

    but
    1. when I "inject" to some process(32bit executable) in win7, neither failed message shown nor setting dialog shown. so can any way to solve this?

    2. After I succeed injected to a process, then I click"reset" and "end" to exit the injector, then restart and try to inject, it always prompt "Dlls already injected..", I have to restart my PC to make it works again. it seems when the inject exit, the injector doesn't de-inject the dlls .

    thx a lot.

    ReplyDelete
  8. Thanks

    1) May be those process are running in elevated mode. Try to run the "Injector" as administrator and inject. Let me know if it still didnt work.

    2) One problem with the Injector is, once you inject the dll to a process, it will be there in the process, unless you terminate that process. And there is a limitation that you can inject to only one process at a time. But you dont have to restart your PC, just terminate that process.

    ReplyDelete
  9. I tried using your application for tracking down GDI leaks but the injector does not prompt any notification or Setting dialog similar to Sail reported above. I am using Windows 7 SP1 x86_64 architecture.I will look into your source code which you attached with your next blog. If you already know the solution for this issue, I will appreciate if you could share that here or drop me email on jpratap@vectorworks.net. Anyways, thanks for putting the code together! All the best. -- Jeet

    ReplyDelete
  10. When I try to download, Google docs blocks me saying the file contains a virus.

    ReplyDelete
    Replies
    1. Please try below link, not sure why they report it has virus.

      http://sdrv.ms/Q5DKOf

      Delete
  11. Hi,

    usefull tool, but something wrong when trying to inject to a service process. OpenProcess() returns ERROR_ACCESS_DENIED even if the injector is ran with Administrator privileges. This was with Win2008R2.

    ReplyDelete
    Replies
    1. Strange.. are you trying to inject it to some other user's or system's process?

      Delete
  12. Hi,

    Nice tool, thought of an enhancement of sorts, that is to timestamp the allocation. I am trying to track down a handle leak and my application allocates so many during it's procesing, I would like to know how old the allocation is to see if that helps identify the issue. I have alot of MSXML objects, and it appears to be leaking Semaphore and Event objects....

    Regards,

    ReplyDelete
    Replies
    1. Sure.. I will consider adding that feature, but of-course if time allows you can modify the code and we can merge it to the svn.

      Delete
  13. Fantastic tool! Thank you for saving my day. :-)

    ReplyDelete