Debug Memory Leaks on Windows Platform

Introduction

A memory leak is a time-consuming bug that rarely gets created and messes up with Memory & Performance of the applications. The detection of memory leaks is often tedious. Things get worst if the code is not written by you, or if the code base is quite huge.

Though there are very good tools available in the market that will help you in memory leak detection, most of these tools are not free. I found Windbg & DebugDiag provided by Microsoft as a freeware powerful tool to solve memory leak bugs on the Windows platform. At least, we get an idea about the code location which might be suspected to cause memory leaks.

In this article, we'll discuss very basic techniques about using Windbg, which is a powerful user/kernel space debugger from Microsoft, which can be downloaded and installed from Here, WinDbg can be used to debug Managed & UnManaged memory leaks

Sample Memory Leak Program:

https://github.com/ShivaGadapa/Low_Level_Design/blob/master/CppMemoryLeak.cpp

Pre-requisites :

Most import things to consider before starting your analysis using Windbg:

Trust me, the below-mentioned things will save lot of your time while tracing the memory leaks, so pay close attention to the details

  1. Know the "platform type" of your application, whether it's a 32-bit or 64-bit application?
  2. Create the dump file based on the application "platform type", else you are just wasting time with the acquired dump file
  3. Users can create Mini-Dump file from Windows Task Manager, To create 32-Bit dump file: "C:\windows\syswow64\Taskmgr.exe" To create 64-Bit dump file: Default windows Task manager
  4. Get your application Source path & Debug binaries(.PDB) and get it included with WindDbg, using ".sympath+" command under WinDbg prompt, There are cases if your application is built on .Net Framework/Uses Microsoft Libraries, you might need to download Microsoft symbols as well
  5. Try loading the valid Dependent/External DLL's using ".load" command

You can find all WinDbg Commands at:

http://windbg.info/doc/1-common-cmds.html#20_memory_heap

Step-By-Step :

Step-1:

Now, let's start with running the WinDbg tool, upon installation of Windows-10 SDK, you'll find WinDbg tool in the location the following location: "C:\Program Files (x86)\Windows Kits\10\Debuggers"

No alt text provided for this image

Now, again under the Debuggers directory, we have 32-bit WinDbg tool under "\x86" directory & 64-Bit WinDbg tool under "\x64", Run the 32-bit debugger if you're application and the dump file are 32-bit, just to make sure everything is under the same page

Step-2:

a) Open the applicable WinDbg tool, Goto "File" Menu -> Select "Open Crash Dump" -> select the dump file from your local computer, we'll see similar output

No alt text provided for this image

b) The application wants you to run the command "!analyze -v", under the WinDbg command prompt, which displays the detailed content about any kind of Exception/Error which you dump file holds

APPLICATION_VERIFIER_FLAGS:  0


EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 0000000000000000
   ExceptionCode: 80000003 (Break instruction exception)
  ExceptionFlags: 00000000
NumberParameters: 0


FAULTING_THREAD:  00004f88


PROCESS_NAME:  apple.exe


ERROR_CODE: (NTSTATUS) 0x80000003 - {EXCEPTION}  Breakpoint  A breakpoint has been reached.


EXCEPTION_CODE_STR:  80000003


STACK_TEXT:  
0000001f`772ff1e0 00007fff`16af477c : 00007fff`136cca26 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlpxLookupFunctionTable+0xf2
0000001f`772ff280 00007fff`16af3b99 : 00007fff`16c5a558 0000001f`772ff390 00000000`00000006 00000000`00000000 : ntdll!RtlpLookupFunctionEntryForStackWalks+0x15c
0000001f`772ff2f0 00007fff`16af375a : 0000020b`ec309230 00000000`00000002 0000001f`772ff9d0 00000000`00000000 : ntdll!RtlpWalkFrameChain+0x3e9
0000001f`772ff950 00007fff`16af36d2 : 00000000`00000020 00000000`00000000 00000000`00000001 00000000`00000050 : ntdll!RtlWalkFrameChain+0x2a
0000001f`772ff980 00007fff`16bf6851 : 0000020b`94163850 0000001f`772ffbb9 0000020b`ec350000 00000000`00000011 : ntdll!RtlCaptureStackBackTrace+0x42
0000001f`772ff9b0 00007fff`16be2aa3 : 00000000`00000050 00000000`00000000 0000020b`ec350000 0000001f`772ffbb9 : ntdll!RtlpStackTraceDatabaseLogPrefix+0x51
0000001f`772ffb00 00007fff`16afda74 : 0000020b`94163850 0000020b`ec350000 0000020b`94163850 00007fff`00000000 : ntdll!RtlpCallInterceptRoutine+0x3f
0000001f`772ffb30 00007fff`136cca26 : 00000000`00000001 00000000`00000020 0000020b`ec3585f0 00000000`00000000 : ntdll!RtlpAllocateHeapInternal+0x9e4
0000001f`772ffc20 00007ff6`f3b4101b : 00000000`00215d6f 00000000`00000000 00000000`40000024 00000000`00000000 : ucrtbase!_malloc_base+0x36
0000001f`772ffc50 00007ff6`f3b41279 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : apple!main+0x1b
0000001f`772ffc80 00007fff`16237974 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : apple!__scrt_common_main_seh+0x11d
0000001f`772ffcc0 00007fff`16b5a271 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0x14
0000001f`772ffcf0 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21




STACK_COMMAND:  ~0s; .ecxr ; kb


FAULTING_SOURCE_LINE:  c:\users\apple\apple.cpp


FAULTING_SOURCE_FILE:  c:\users\apple\apple.cpp


FAULTING_SOURCE_LINE_NUMBER:  30


FAULTING_SOURCE_CODE:  
    13: 
    14: 
    15: 
    16: 
>   17: 
    18: 
    19: 
    20: 
    21: 
    22: 




SYMBOL_NAME:  apple!main+1b


MODULE_NAME: apple


IMAGE_NAME:  apple.exe


FAILURE_BUCKET_ID:  BREAKPOINT_80000003_apple.exe!main


OS_VERSION:  10.0.17763.1


BUILDLAB_STR:  rs5_release


OSPLATFORM_TYPE:  x64


OSNAME:  Windows 10


FAILURE_ID_HASH:  {41426f55-f2e5-465c-c1b9-93557afa13e4}


Followup:     MachineOwner

c) Now, if you have all the symbols(.DLL's or .PDB's or Application Source path) related to your application are loaded correctly, then you can find the information related to the faulty module, the file name and also the line number which is causing the memory leak in the above output

d) If you can't find any information related to your project or the output doesn't make any sense, just include the symbol path using the command: ".sympath+ C:\Temp\MyProject\SourceFolder" and if you're application dependent on other DLL's then load the respective module using the command ".load C:\Temp\3rdPartyLibs\Abc.dll", you can load multiple symbol path and valid DLL's, to get the accurate results from the WinDbg commands

Step-3:

Incomplete Call Stack Output:

Run command "k", to view the call stack, Sometimes even after including all the symbols, source information the debugger won't be able to display the valid output, The below output(incomplete call stack) tells us that there are still some deferred symbols apple!main+0x1b --[c:\users\sg185301\source\repos\apple\apple\apple.cpp @ 30], but we actually know that problem residing inside multiple function calls which are stacked up 

 # Child-SP          RetAddr           Call Site
00 0000001f`772ff1e0 00007fff`16af477c ntdll!RtlpxLookupFunctionTable+0xf2
01 0000001f`772ff280 00007fff`16af3b99 ntdll!RtlpLookupFunctionEntryForStackWalks+0x15c
02 0000001f`772ff2f0 00007fff`16af375a ntdll!RtlpWalkFrameChain+0x3e9
03 0000001f`772ff950 00007fff`16af36d2 ntdll!RtlWalkFrameChain+0x2a
04 0000001f`772ff980 00007fff`16bf6851 ntdll!RtlCaptureStackBackTrace+0x42
05 0000001f`772ff9b0 00007fff`16be2aa3 ntdll!RtlpStackTraceDatabaseLogPrefix+0x51
06 0000001f`772ffb00 00007fff`16afda74 ntdll!RtlpCallInterceptRoutine+0x3f
07 0000001f`772ffb30 00007fff`136cca26 ntdll!RtlpAllocateHeapInternal+0x9e4
08 0000001f`772ffc20 00007ff6`f3b4101b ucrtbase!_malloc_base+0x36
0b 0000001f`772ffc50 00007ff6`f3b41279 apple!main+0x1b [c:\users\Temp\apple\apple\apple.cpp @ 30] 
0c (Inline Function) --------`-------- apple!invoke_main+0x22 [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 78] 
0d 0000001f`772ffc80 00007fff`16237974 apple!__scrt_common_main_seh+0x11d [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 283] 
0e 0000001f`772ffcc0 00007fff`16b5a271 kernel32!BaseThreadInitThunk+0x14
0f 0000001f`772ffcf0 00000000`00000000 ntdll!RtlUserThreadStart+0x21

You can verify if things are loaded correctly using the following commands:

Run ".sympath" (To Verify Debug symbols & Source Path info)

************* Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       srv*
OK                                             C:\Temp\apple

Run ".lm", (To Verify Deferred Modules & Symbols info)

0:000> lm
start             end                 module name
00007ff6`f3b40000 00007ff6`f3b47000   apple    C (private pdb symbols)  C:\ProgramData\dbg\sym\apple.pdb\E413EC11B66148EB843C815F8205CFC58\apple.pdb
00007fff`105e0000 00007fff`105f7000   VCRUNTIME140   (deferred)             
00007fff`136c0000 00007fff`137ba000   ucrtbase   (pdb symbols)          C:\ProgramData\dbg\sym\ucrtbase.pdb\012A78335BB70F0E966EBE286E5364741\ucrtbase.pdb
00007fff`139c0000 00007fff`13c55000   KERNELBASE   (pdb symbols)          C:\ProgramData\dbg\sym\kernelbase.pdb\E7C1891B988087BD7F07596A6F866BC71\kernelbase.pdb
00007fff`16220000 00007fff`162d3000   kernel32   (pdb symbols)          C:\ProgramData\dbg\sym\kernel32.pdb\2662E0289AC6F2BAEE6190EB49F51E071\kernel32.pdb
00007fff`16af0000 00007fff`16cdd000   ntdll      (pdb symbols)          C:\ProgramData\dbg\sym\ntdll.pdb\FF98FE65248A4F35130AD2BCEDC0BE371\ntdll.pdb

Run ".ld *", to load the unloaded symbols or Deferred Symbols/Links

Step-4:

After verification, now run the final command to view the detailed call stack of your application

Run "k" command, Bingo... Now the results are quite interesting, Now I can see at line-16 in Func2(), the problem exists

0:000> k
 # Child-SP          RetAddr           Call Site
00 0000001f`772ff1e0 00007fff`16af477c ntdll!RtlpxLookupFunctionTable+0xf2
01 0000001f`772ff280 00007fff`16af3b99 ntdll!RtlpLookupFunctionEntryForStackWalks+0x15c
02 0000001f`772ff2f0 00007fff`16af375a ntdll!RtlpWalkFrameChain+0x3e9
03 0000001f`772ff950 00007fff`16af36d2 ntdll!RtlWalkFrameChain+0x2a
04 0000001f`772ff980 00007fff`16bf6851 ntdll!RtlCaptureStackBackTrace+0x42
05 0000001f`772ff9b0 00007fff`16be2aa3 ntdll!RtlpStackTraceDatabaseLogPrefix+0x51
06 0000001f`772ffb00 00007fff`16afda74 ntdll!RtlpCallInterceptRoutine+0x3f
07 0000001f`772ffb30 00007fff`136cca26 ntdll!RtlpAllocateHeapInternal+0x9e4
08 0000001f`772ffc20 00007ff6`f3b4101b ucrtbase!_malloc_base+0x36

09 (Inline Function) --------` apple!Func2+0x15 [c:\Temp\apple\apple.cpp @ 16] 
0a (Inline Function) --------` apple!Func1+0x15 [c:\Temp\apple\apple.cpp @ 23] 
0b 0000001f`772ffc50 00007ff6` apple!main+0x1b [c:\Temp\apple\apple.cpp @ 30] 

0c (Inline Function) --------`-------- apple!invoke_main+0x22 [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 78] 
0d 0000001f`772ffc80 00007fff`16237974 apple!__scrt_common_main_seh+0x11d [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 283] 
0e 0000001f`772ffcc0 00007fff`16b5a271 kernel32!BaseThreadInitThunk+0x14
0f 0000001f`772ffcf0 00000000`00000000 ntdll!RtlUserThreadStart+0x21

To view or add a comment, sign in

More articles by ShivaPrasad Gadapa

  • Regular Expressions... a Nightmare

    The word regular expressions has tendency to change the face expressions of every IT guy who has worked on building a…

Others also viewed

Explore content categories