Click here to Skip to main content
Click here to Skip to main content

Memory(-Leak) and Exception Trace (CRT and COM Leaks)

By , 1 Dec 2005
 

Introduction

With this utility you can simply find memory leaks in your program (CRT and COM-Leaks!). Each leak is displayed with the callstack (including the source line) of the allocation. So, you can easily find leaks, while using the STL. It will also write a file with the callstack if your application crashes (it can also handle stack-overflows!). It almost has no runtime-overhead (runtime-cost). And the best: it is free (GNU Lesser General Public License).

Finding memory leaks

It is easy to implement this in your existing VC code:

  1. Add Stackwalker.cpp and Stackwalker.h to your project.
  2. Include Stackwalker.h in your main source file.
  3. Call InitAllocCheck() right after the beginning of your main.
  4. Call DeInitAllocCheck() just before the end of your main (here all the leaks will be reported).

All the leaks will be listed in the file YouAppName.exe.mem.log in the application directory (only in debug builds; it is deactivated for release builds). This will also activate exception-handling by default (release and debug builds).

Only use exception-handling

If you only want to use exception handing, you need to do the following:

  1. Add Stackwalker.cpp and Stackwalker.h to your project.
  2. Include Stackwalker.h in your main source file.
  3. Call OnlyInstallUnhandeldExceptionFilter() right after the beginning of your main.

If an exception occurs, it will write a file with the callstack in the application directory with the name YouAppName.exe.exp.log.

Example

A simple example is given below:

#include <windows.h>
#include "Stackwalker.h"

void main()
{
  // Uncomment the following if you only
  // need the UnhandledException-Filter
  // (to log unhandled exceptions)
  // then you can remove the "(De)InitAllocCheck" lines
  //OnlyInstallUnhandeldExceptionFilter();

  InitAllocCheck();

  // This shows how the mem-leak function works
  char *pTest1 = new char[100];

  // This shows a COM-Leak
  CoTaskMemAlloc(120);

  // This shows the exception handling
  // and log-file writing for an exception:
  // If you want to try it, please comment it out...
  //char *p = NULL;
  //*p = 'A'; // BANG!

  DeInitAllocCheck();
}

If you execute this example, you will get a file Appication-Name.exe.mem.log with the following content:

##### Memory Report ########################################
11/07/02 09:43:56

##### Leaks: ###############################################
RequestID:           42, Removed: 0, Size:          100
1: 11/07/02 09:43:56
1: f:\vs70builds\9466\vc\crtbld\crt\src\dbgheap.c(359)
                              +30 bytes (_heap_alloc_dbg)
1: f:\vs70builds\9466\vc\crtbld\crt\src\dbgheap.c(260)
                              +21 bytes (_nh_malloc_dbg)
1: f:\vs70builds\9466\vc\crtbld\crt\src\dbgheap.c(139) +21 bytes (malloc)
1: f:\vs70builds\9466\vc\crtbld\crt\src\newop.cpp(12) +9 bytes (operator new)
1: d:\privat\memory_and_exception_trace\
            memory_and_exception_trace\main.cpp(9) +7 bytes (main)
1: f:\vs70builds\9466\vc\crtbld\crt\src\crt0.c(259)
                               +25 bytes (mainCRTStartup)

**** Number of leaks: 1

##### COM-Leaks: ###############################################
(shortened)
**** Number of leaks: 1

Explanation

Now, I will explain the Memory-Report-File:

RequestID:           42, Removed: 0, Size:          100

This line is the beginning of one leak. If you have more than one leak, then each leak will start with a RequestID.

  • RequestID

    For CRT: This is the RequestID which is passed to the AllocHook. This ID clearly identifies an allocation. The CRT just increments this number for each allocation. You can also use this number with the _CrtSetBreakAlloc function.

    For COM: This is the address of the allocated memory.

  • Removed

    In a memory leak dump this must always be 0 (false).

  • Size

    This is the size of the allocated memory block.

1: f:\vs70builds\9466\vc\crtbld\crt\src\dbgheap.c(359)
                                   +30 bytes (_heap_alloc_dbg)

This is an actual stack entry. The stack is shown from the last function on the top going through each callee until the end of the stack is reached.

  • 1:

    This number is incremented for each complete callstack. You can ignore this.

  • f:\vs70builds\9466\vc\crtbld\crt\src\dbgheap.c

    The actual filename.

  • (359)

    The line number inside the file.

  • +30 bytes

    This is the offset from this line in bytes (if a line produces more than one assembler instruction).

  • (_heap_alloc_dbg)

    The name of the function.

    More options by calling InitAllocCheck

    InitAllocCheck has three parameters:

    Parameter name Description
    • eAllocCheckOutput
    • eOutput

    This is an enum for output-format. The following is possible:

    • ACOutput_Simple (default)

      This outputs the callstack as seen above.

    • ACOutput_Advanced

      This has a more detailed output of the callstack. For more info see here.

    • ACOutput_XML

      This outputs the leaks in an XML file so that you can read it easily from other applications or use some XSLT to transform it to a more readable format you want. For more info see here.

    • BOOL
    • bSetUnhandledExeptionFilter (default: TRUE)

    If this is set, an UnhandledExceptionFilter will be installed. If an (unhandled) exception occurs it will write the callstack in a log file and terminate. For more info see here.

    • ULONG
    • ulShowStackAtAlloc (default: 0)

    Notice: This works only for CRT-allocs.

    Here you can specify the level of mallocs/frees logging. By default nothing will be logged in the log file at runtime. If you need to know what happens while executing the program you can specify a value. Then the malloc/free action will be logged to the file (either with or without callstack).

    Valid values are:

    • 0 = Do not write any output during runtime-alloc-call (default).
    • 1 = Write only the alloc action (malloc, realloc, free).
    • 2 = Write alloc action and callstack only for malloc/realloc.
    • 3 = Write alloc action and callstack for all actions.

    Log-output with more info

    You can also get an output with more info about each stack entry. For this you have to call InitAllocCheck with the first parameter set to ACOutput_Advanced. If you execute the following sample you will get a file Appication-Name.exe.mem.log with more info:

    #include <windows.h>
    #include "Stackwalker.h"
    
    void main()
    {
      InitAllocCheck(ACOutput_Advanced);
      // This shows how the mem-leak function works
      char *pTest1 = new char[100];
      DeInitAllocCheck();
    }

    And here is the (shortened) output:

    ##### Memory Report ########################################
    11/04/02 09:04:04
    
    ##### Leaks: ###############################################
    RequestID:           45, Removed: 0, Size:          100
    1: 11/04/02 09:04:04
    // ...
    1:   5     main +49 bytes
    1:     Decl: main
    1:     Line: d:\privat\memory_and_exception_trace\main.cpp(27) +7 bytes
    1:     Mod:  Memory_and_Exception_Trace, base: 00400000h
    
    1:   6     mainCRTStartup +363 bytes
    1:     Decl: mainCRTStartup
    1:     Line: f:\vs70builds\9466\vc\crtbld\crt\src\crt0.c(259) +25 bytes
    1:     Mod:  Memory_and_Exception_Trace, base: 00400000h
    
    1:   7     _BaseProcessStart@4 +35 bytes
    1:     Decl: _BaseProcessStart@4
    1:     Mod:  kernel32, base: 77e40000h
    
    **** Number of leaks: 1
    // ...

    Explanation

    Here, I will explain the Memory-Report-File:

    RequestID:           45, Removed: 0, Size:          100

    This line is the same as above:

    1:   5     main +49 bytes
    • 1:

      This number is incremented for each complete callstack. You can ignore this.

    • 5

      This is the depth of the callstack. This number is incremented for each stack entry. The stack is shown from the last function on the top (number 0) going through each callee until the end of the stack is reached.

    • main +49 bytes

      The number of bytes from the beginning of this function, where the instruction for this callstack is stored.

    1:     Decl: main
    1:     Line: d:\privat\memory_and_exception_trace\main.cpp(27) +7 bytes
    1:     Mod:  Memory_and_Exception_Trace, base: 00400000h
    • Decl: main

      This is the declaration of the function.

    • Line: ....xyz.cpp(27) +7 bytes

      This shows the actual line (in brackets) of the callstack (here: line 27). In addition, it gives the offset from this line in bytes (if a line produces more than one assembler instruction).

    • Mod: Memory_and_Exception_Trace

      The name of the module (EXE, DLL, OCX, a.s.o.).

    • base: 00400000h

      The base address of this module.

    XML output

    If you set the first parameter to ACOutput_XML an XML file will be produced. It has the following contents:

    <MEMREPORT date="11/08/02" time="10:43:47">
      <LEAK requestID="47" size="100">
        <!-- shortened -->
        <STACKENTRY decl="main" decl_offset="+100"
                        srcfile="d:\...\main.cpp" line="16"
          line_offset="+7" module="Memory_and_Exception_Trace" base="00400000"/>
        <STACKENTRY decl="mainCRTStartup" decl_offset="+363"
                        srcfile="f:\...\crt0.c" line="259"
          line_offset="+25" module="Memory_and_Exception_Trace" base="00400000"/>
      </LEAK>
    </MEMREPORT>

    It is pretty self explaining if you take a look at the "advanced log output".

    Mem-leak-analyse tool

    If you are using the XML-output format then you can use my MemLeakTool to display the leaks in a sorted order (sorted by callstack). Just select the "xml-leak"-File and press "Read". The callstack will be displayed in a TreeView. If you select a node, the source code will be shown in the right part (if it could be found).

    Information: This program requires .NET Framework 1.0!

    A word on leaks

    You should be aware, that some leaks might be the result of other leaks. For example the following code throws two leaks, but if you remove the "originator" of the leaks, the other leak will also disappear. For example:

    #include <windows.h>
    #include <stdlib.h>
    #include "stackwalker.h"
    class MyTest
    {
      public:
        MyTest(const char *szName)
        {
          // The following is the second resulting leak
          m_pszName = strdup(szName);
        }
        ~MyTest()
        {
          if (m_pszName != NULL)
            free(m_pszName);
          m_pszName = NULL;
        }
      protected:
        char *m_pszName;
    };
    
    void main()
    {
      InitAllocCheck();
    
      // This is the "main" leak
      MyTest *pTest = new MyTest("This is an example");
    
      DeInitAllocCheck();
    }

    How it works (CRT)

    The basis of the memory leak logger is a Hashtable with information about all the allocated memory (including callstack). Basically _CrtSetAllocHook is called to hook all the memory allocations / frees. Therefore only C/C++ allocations are logged. On every allocation a portion of the callstack and the Instruction-Pointer is caught and stored in the Hashtable, with some other information about the allocation.

    If the application calls DeinitAllocCheck then the Hashtable will be iterated and the (saved) callstack of all the entries will be listed in the file. For this we provide a pointer to our ProcessMemoryRoutine function to the StackWalk function.

    In detail

    Hashtable

    The Hashtable contains by default 1024 entries. You can change this value if you are doing many allocations and want to reduce the collisions. Just change the ALLOC_HASH_ENTRIES define.

    As hash-key, the lRequestID for each allocation is used. This ID is passed to the AllocHook function (at least for allocs). If it is not passed (for example, for freeing), then an (valid) address is passed. By having this address it is also possible to get the lRequestID, by looking into the _CrtMemBlockHeader of the allocated block.

    For hashing, a very simple and fast hash-function is used:

    static inline ULONG AllocHashFunction(long lRequestID) {
      return lRequestID % ALLOC_HASH_ENTRIES;
    }  // AllocHashFunction

    Insert an allocation into the Hashtable

    If a new allocation should be inserted into the Hashtable, first a thread context for the actual thread is made by calling GetThreadContext. This function requires a "real" thread handle and not a pseudo handle which is returned by GetCurrentThred. So, for this I have to create a "real" handle by calling DuplicateHandle.

    Actually, I only need the current Ebp and Eip registers. This could also be done by just reading the registers with the inline assembler. Now having the registers, I read the memory at the specified address. For Eip, I only need to read 4 bytes. I do not know why StackWalk needs to read the Eip values, but if the values could not be read from StackWalk it fails to build the callstack. The real important part is the callstack which is stored in the memory pointing from Ebp (or Esp).

    At the moment, I just try to read 0x500 bytes by calling the ReadProcessMemory function. I don't read the complete stack, because it might use too much memory for many allocations. So, I reduced the maximum size to 0x500. If you need a deeper callstack, you can change the MAX_ESP_LEN_BUF define.

    If the callstack is not 0x500 bytes deep, then the ReadProcessMemory will fail with ERROR_PARTIAL_COPY. If this happens, I need to ask how many are possible, to read without any error. For this I need to query this value by calling VirtualQuery. Then, I try to read as many bytes as possible.

    Having the callstack I can simply insert the entry into the Hashtable. If the given hash-entry is already occupied, I make a linked list and append this entry to the end.

    Building the leak-list

    If you call DeInitAllocCheck I simply walk through the Hashtable and output every entry which was not freed. For this I call StackWalk with a pointer to my own memory-reading-function (ReadProcMemoryFromHash). This function is called from the internals of StackWalk. If it is called it looks up the Hashtable for the given lRequestID and returns the memory which was stored in the Hashtable. The lRequestID is passed in the hProcess parameter of the StackWalk function (as stated in the documentation of StackWalk).

    Ignoring allocations

    Allocations/frees for _CRT_BLOCK are ignored (for more info, see here). This is because CRT dynamically allocates some memory for "special purposes". The tool also checks the _CRTDBG_ALLOC_MEM_DF flag of the _crtDbgFlag variable. If it is off, then all the allocations are ignored. For more details see _CrtSetDbgFlag.

    How it works (COM)

    To track COM-memory-leaks, you have to provide an IMallocSpy interface. This interface must be registered with CoRegisterMallocSpy. After that the (own) IMallocSpy instance is called for every memory (re)allocation/free. So, you can track all memory actions.

    The storage of the callstack is done in the same way as for CRT-allocs (in a Hashtable). So, for more info please read the CRT-section.

    A word on COM-leaks

    Actually, there is nothing to say, but...

    If you are using MSXML 3 or 4 implementation, you have to be aware of the fact that this parser uses a "smart" pseudo-garbage collector. This means that they allocate memory and will not free it after it is used! So, you may see some leaks which are only "cached memory". If you first call CoUninitialize, then all the cached memory will be freed and the "real" COM-leaks will be reported.

    For more info see: Understanding the MSXML Garbage Collection Mechanism.

    MFC usage

    The problem with MFC is that the derived CWinApp class is instantiated by the C-runtime, because it is a global variable. The easiest solution to implement the Leak-Finder is to declare the following static struct inside your MainApp.cpp.

    You also have to add stackwalk.cpp and stackwalk.h to your project. You also need to add the #include <stdafx.h> on top of the stackwalk.cpp file (if you use precompiled headers). A sample of an MFC application is also available from the top of this article:

    static struct _test
    {
      _test()
      {
        InitAllocCheck();
      }
    
      ~_test()
      {
        DeInitAllocCheck();
      }
    } _myLeakFinder;

    Temporarily disable logging (only CRT)

    When you don't want to log a special allocation of your application (for whatever reason; MFC does this often), then you can simply deactivate it by disabling the CRT flag _CRTDBG_ALLOC_MEM_DF with the _CrtSetDbgFlag function. Here is an example of how you can do this:

    #include "Stackwalker.h"
    
    #include <crtdbg.h>
    
    bool EnableMemoryTracking(bool bTrack)
    {
      int nOldState = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
      if (bTrack)
        _CrtSetDbgFlag(nOldState | _CRTDBG_ALLOC_MEM_DF);
      else
        _CrtSetDbgFlag(nOldState & ~_CRTDBG_ALLOC_MEM_DF);
      return nOldState & _CRTDBG_ALLOC_MEM_DF;
    }
    
    void main()
    {
      InitAllocCheck();
    
      // The following will be logged
      char *pTest1 = new char[100];
    
      EnableMemoryTracking(false);  // disable logging
      // The following will NOT be logged
      char *pTest2 = new char[200];
      EnableMemoryTracking(true);  // enable logging
    
      // The following will be logged
      char *pTest3 = new char[300];
    
      DeInitAllocCheck();
    }

    Unhandled exceptions

    There are three ways to use this tool for unhandled exceptions.

    Simple using

    If you just call InitAllocCheck with no parameters or with the second parameter set to TRUE, then an unhandled exception filter will be installed. If an unhandled exception occurs, a log file with the callstack will be written, a dialog box with the exception message will be displayed, and the application will be terminated with FatalAppExit.

    Second simple using

    If you don't want the AllocCheck-overhead (the (small) overhead is only present in debug builds), you can simply call OnlyInstallUnhandeldExceptionFilter. This will install the UnhandledExceptionFilter which writes a log file if an (unhandled) exception occurs. The log file will be stored in the application directory with the name YouAppName.exe.exp.log:

    int main()
    {
      OnlyInstallUnhandeldExceptionFilter();
    
      // do your main code here...
    }

    Advanced using

    You can write your own exception filter and just call StackwalkFilter to produce the callstack. Then you can do whatever you want. Here is a small example:

    static LONG __stdcall MyUnhandlerExceptionFilter(EXCEPTION_POINTERS* pExPtrs)
    {
       LONG lRet;
       lRet = StackwalkFilter(pExPtrs,
                 EXCEPTION_EXECUTE_HANDLER, _T("\\exception.log"));
       TCHAR lString[500];
       _stprintf(lString,
          _T("*** Unhandled Exception!\n")
          _T("   ExpCode: 0x%8.8X\n")
          _T("   ExpFlags: %d\n")
          _T("   ExpAddress: 0x%8.8X\n")
          _T("   Please report!"),
          pExPtrs->ExceptionRecord->ExceptionCode,
          pExPtrs->ExceptionRecord->ExceptionFlags,
          pExPtrs->ExceptionRecord->ExceptionAddress);
       FatalAppExit(-1,lString);
       return lRet;
    }
    
    int main()
    {
      InitAllocCheck(ACOutput_Advanced, FALSE);
      SetUnhandledExceptionFilter(MyUnhandlerExceptionFilter);
    
      // do some stuff...
    
      DeInitAlloocCheck();
    }

    Common mistakes

    One of the most common mistakes while using this tool is that you statically instantiate classes in your main function. The problem is that the destructor of the class is called after the call to DeInitAllocCheck. If some memory was allocated inside this class, this memory will appear as a leak. For example:

    #include <windows.h>
    #include "Stackwalker.h"
    #include <string>
    
    void main()
    {
      InitAllocCheck();
      std::string szTemp;
      szTemp = "This is a really long string";
      DeInitAllocCheck();
    }

    There are two solutions for this. You can start a block after the call to InitAllocCheck and end it before the call to DeInitAllocCheck. With this you can be sure that the destructors are called before the leak file is produced. For example:

    #include <windows.h>
    #include "Stackwalker.h"
    #include <string>
    
    void main()
    {
      InitAllocCheck();
      {
        std::string szTemp;
        szTemp = "This is a really long string";
      }
      DeInitAllocCheck();
    }

    The second solution is to use the same technique that is used for MFC applications (see above).

    Visual Studio 7 and Win2K / NT

    I found a problem with the executables built with VS7 and run on Win2K or NT. The problem is due to an old version of dbghelp.dll. The PDB files generated from VS7 are in a newer format (DIA). It appears that the VS installations do not update dbghelp.dll on Win2K. So the original version (5.0.*) is still on the system and will be used. But with this version it is not possible to read the new PDB format. So, no callstack can be displayed.

    To get it to work you have to do the following

    Download the latest Debugging Tools for Windows (which includes dbghelp.dll). You have to install it to get the files. But you only need the dbghelp.dll! Now we have another problem. The installer does not replace the original dbghelp.dll. So we need to copy the dbghelp.dll in our EXE dir. Now to make sure the right version is loaded you have to put a file with the name appname.local in your EXE dir (please replace appname with the EXE name (without extension)). Now it should also work on WinNT/2K.

    Known issues

    • The memory leak works correctly only if the lRequestID does not wrap (32-bit value). If the value wraps around, then it is not possible to clearly assign a given lRequestID to a previous allocation, because it is possible that this ID was used twice (or even more). But this happens only with VC7, because VC6 has a bug in the C-runtime which will call _DbgBreak if the lRequestID wraps (if no _CrtBreakAlloc is used).
    • If you compile with "Detect 64-bit portability issues (/Wp64)" option on VC7, it will generate a warning.
    • If you use this tool in managed C++ it will not correctly display the callstack for managed code.
    • For some reason, the COM-alloc-callstack cannot display the stack-entry which really calls the CoTaskMemAlloc function. Only the upper stack entry can be shown.

    References

    History

    • 4th Nov, 2002
      • Initial revision.
    • 5th Nov, 2002
      • Updated to work with MFC, "Temporarily disable logging", "MFC usage" and "References" added.
    • 6th Nov, 2002
      • "Explanation" for leak-file, "A word on leaks" and "How it works: In detail" added.
    • 7th Nov, 2002
      • Simple leak output implemented.
      • Explaining the simple leak output.
      • "Common mistakes" added.
    • 8th Nov, 2002
      • Explanation of the InitAllocCheck parameters added.
      • XML-output added, "Soon to come" and "History" added.
    • 13th Nov, 2002
      • Updated the source to compile again under VC6 (SymDIA undefined, will be corrected later).
    • 21st Nov, 2002
      • Updated the source to compile again with UNICODE-builds.
      • #include "stdafx.h" instead of #include <stdafx.h> in MFC-demo.
    • 6th Dec, 2002
      • Updated to work correctly with UNICODE.
      • Added MemLeakAnalyse tool; "Soon to come" removed.
    • 19th Dec, 2002
      • Now using only the dbghelp.dll. NT users have to install the dbghelp.dll redistributable for NT (see references above).
      • Added comments on how to use it from VS7 on NT/W2K...
    • 8th Jan, 2003
      • Major update: Added support for COM-leaks.
      • Small updates to MemLeakAnalyse tool; removed a few small bugs.
    • 9th Jan, 2003
      • Removed the handle-leaks inside the IMallocSpy interface.
    • 23rd Aug, 2003
      • Updated a few links.
    • 28th Aug, 2003
      • Updated to the newer version of dbghelp.dll (StackWalk64).
      • Added OnlyInstallUnhandeldExceptionFilter function; License clarification: LGPL.
    • 3rd Sep, 2003
      • Updated the source to catch "stack-overflows".
      • Removed some "memory leak inside the memory leak finder"; Hashtable-size is now a prime number.
    • 12th Sep, 2003
      • Fixed a bug in PreRealloc; thanks to Christoph Weber.
      • License changed to "zlib/libpng license".
      • AnalyseTool: added command line support (you can specify the XML file in the command line).
      • AnalyseTool: support for additional search paths for looking up the source-file.
    • 19th Oct, 2005
      • Changed GetThreadContext to my own function, because of changes in XP-SP2.
      • Changed the license to LGPL.
    • 21st Nov, 2005
      • Working around a bug in the newest dbghelp.dll (6.5.3.7/8).

    License

    This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

    About the Author

    Jochen Kalmbach [MVP VC++]
    Software Developer (Senior)
    Germany Germany
    Member
    1982: My first computer (VC20)
    1984: Finished to build my first own computer (Z80)
    1993: Mission-Volunteer in Papua New Guinea
    1998: Dipl. Inform. (FH)
    ... working, working, working....

    Sign Up to vote   Poor Excellent
    Add a reason or comment to your vote: x
    Votes of 3 or less require a comment

    Comments and Discussions

     
    You must Sign In to use this message board.
    Search this forum  
        Spacing  Noise  Layout  Per page   
    QuestionMy toolmemberMast Avalons13 Jan '12 - 8:35 
    I usually use deleaker for search memory and GDI leaks. Smile | :)
    AnswerRe: My toolmemberJohnDepth6 Jun '12 - 11:34 
    Hmmm... Interesting solution Roll eyes | :rolleyes:
    GeneralMy vote of 1memberJoe Woodbury29 Oct '10 - 8:12 
    The code is outdated and doesn't compile cleanly at warning level 4. I've tried the latest build (RC11) with Visual Studio 2008 and there are many errors.
     
    Since you aren't updating the code or article here, I believe you should remove this article.
    SuggestionRe: My vote of 1memberinfal24 Nov '11 - 22:13 
    Dear Mr Woodbury,
     
    as I can assume, you has already removed your brain!
     
    Nobody is engaged to maintain the articles written many years ago, just because the code would not compile with newest compiler and your warning level preferences.
     
    You are definitively not a corporate thinking guy - instead of swich on your brain, learn something, invest a little bit of your time, improve the code to the new compiler requirements and share it here, you attack the autor, which made and share this great article with community!
     
    I assume, you think, this is your life right to criticize other people, do nothing for other people and think, other people works only for your pleasure.
     
    Such people as you have definitively no business being on this community.
     
    Please, please, please leave this community today!
    GeneralRe: My vote of 1memberJochen Kalmbach [MVP VC++]25 Nov '11 - 2:48 
    The stackwalker part is now maintained on:
    http://stackwalker.codeplex.com/[^]
     
    The latest version of the leakfinder can be found here:
    http://blog.kalmbachnet.de/files/LeakFinder-RC11.zip[^]
     
    The problem is, that it is not easy to maintain this page! The workflow to update this page is very complicated; and I have not that much time...
    GeneralRe: My vote of 1memberAndrew Padalka22 Aug '12 - 22:09 
    Good answer!!!
    I was in the same situation, and can put my signature under every your word.
    My opinion - authors of such "critics" must be restricted from evaluating.
    with best regards
    Andrey Padalka
    Hello to all, who know me

    GeneralRe: My vote of 1membercesaov119 Mar '13 - 16:31 
    Any plans of updating the tool to support Visual Studio 2012?
    GeneralHeaps of compiler/linker errors with VC10 ExpressmemberRasmus Kaae27 Oct '10 - 19:54 
    I tried including the RC11 files in my project and get the following errors ... Any hints on what might be wrong?
     
    1>Stackwalker.obj : error LNK2005: "public: virtual long __stdcall CMallocSpy::QueryInterface(struct _GUID const &,void * *)" (?QueryInterface@CMallocSpy@@UAGJABU_GUID@@PAPAX@Z) already defined in LeakFinder.obj
    1>Stackwalker.obj : error LNK2005: "public: virtual unsigned long __stdcall CMallocSpy::AddRef(void)" (?AddRef@CMallocSpy@@UAGKXZ) already defined in LeakFinder.obj
    1>Stackwalker.obj : error LNK2005: "public: virtual unsigned long __stdcall CMallocSpy::Release(void)" (?Release@CMallocSpy@@UAGKXZ) already defined in LeakFinder.obj
    1>Stackwalker.obj : error LNK2005: "public: virtual unsigned long __stdcall CMallocSpy::PreAlloc(unsigned long)" (?PreAlloc@CMallocSpy@@UAGKK@Z) already defined in LeakFinder.obj
    1>Stackwalker.obj : error LNK2005: "public: virtual void * __stdcall CMallocSpy::PostAlloc(void *)" (?PostAlloc@CMallocSpy@@UAGPAXPAX@Z) already defined in LeakFinder.obj
    1>Stackwalker.obj : error LNK2005: "public: virtual void * __stdcall CMallocSpy::PreFree(void *,int)" (?PreFree@CMallocSpy@@UAGPAXPAXH@Z) already defined in LeakFinder.obj
    1>Stackwalker.obj : error LNK2005: "public: virtual unsigned long __stdcall CMallocSpy::PreRealloc(void *,unsigned long,void * *,int)" (?PreRealloc@CMallocSpy@@UAGKPAXKPAPAXH@Z) already defined in LeakFinder.obj
    1>Stackwalker.obj : error LNK2005: "public: virtual void * __stdcall CMallocSpy::PostRealloc(void *,int)" (?PostRealloc@CMallocSpy@@UAGPAXPAXH@Z) already defined in LeakFinder.obj
    1>MSVCRTD.lib(cinitexe.obj) : warning LNK4098: defaultlib 'msvcrt.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
    1>LeakFinder.obj : error LNK2019: unresolved external symbol "public: __thiscall StackWalker::StackWalker(int,char const *,unsigned long,void *)" (??0StackWalker@@QAE@HPBDKPAX@Z) referenced in function "public: __thiscall LeakFinderOutput::LeakFinderOutput(int,char const *)" (??0LeakFinderOutput@@QAE@HPBD@Z)
    1>LeakFinder.obj : error LNK2001: unresolved external symbol "protected: virtual void __thiscall StackWalker::OnSymInit(char const *,unsigned long,char const *)" (?OnSymInit@StackWalker@@MAEXPBDK0@Z)
    1>LeakFinder.obj : error LNK2001: unresolved external symbol "protected: virtual void __thiscall StackWalker::OnLoadModule(char const *,char const *,unsigned __int64,unsigned long,unsigned long,char const *,char const *,unsigned __int64)" (?OnLoadModule@StackWalker@@MAEXPBD0_KKK001@Z)
    1>LeakFinder.obj : error LNK2019: unresolved external symbol "protected: virtual void __thiscall StackWalker::OnOutput(char const *)" (?OnOutput@StackWalker@@MAEXPBD@Z) referenced in function "protected: virtual void __thiscall LeakFinderOutput::OnOutput(char const *)" (?OnOutput@LeakFinderOutput@@MAEXPBD@Z)
    1>LeakFinder.obj : error LNK2019: unresolved external symbol "protected: virtual void __thiscall StackWalker::OnDbgHelpErr(char const *,unsigned long,unsigned __int64)" (?OnDbgHelpErr@StackWalker@@MAEXPBDK_K@Z) referenced in function "protected: virtual void __thiscall LeakFinderOutput::OnDbgHelpErr(char const *,unsigned long,unsigned __int64)" (?OnDbgHelpErr@LeakFinderOutput@@MAEXPBDK_K@Z)
    1>LeakFinder.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall StackWalker::~StackWalker(void)" (??1StackWalker@@UAE@XZ) referenced in function "public: virtual __thiscall LeakFinderOutput::~LeakFinderOutput(void)" (??1LeakFinderOutput@@UAE@XZ)
    1>LeakFinder.obj : error LNK2019: unresolved external symbol "protected: virtual void __thiscall StackWalker::OnCallstackEntry(enum StackWalker::CallstackEntryType,struct StackWalker::CallstackEntry &)" (?OnCallstackEntry@StackWalker@@MAEXW4CallstackEntryType@1@AAUCallstackEntry@1@@Z) referenced in function "protected: virtual void __thiscall LeakFinderOutput::OnCallstackEntry(enum StackWalker::CallstackEntryType,struct StackWalker::CallstackEntry &)" (?OnCallstackEntry@LeakFinderOutput@@MAEXW4CallstackEntryType@StackWalker@@AAUCallstackEntry@3@@Z)
    1>LeakFinder.obj : error LNK2019: unresolved external symbol "public: int __thiscall StackWalker::LoadModules(void)" (?LoadModules@StackWalker@@QAEHXZ) referenced in function "void __cdecl DeinitLeakFinder(class LeakFinderOutput *)" (?DeinitLeakFinder@@YAXPAVLeakFinderOutput@@@Z)
    1>LeakFinder.obj : error LNK2019: unresolved external symbol "public: int __thiscall StackWalker::ShowCallstack(void *,struct _CONTEXT const *,int (__stdcall*)(void *,unsigned __int64,void *,unsigned long,unsigned long *,void *),void *)" (?ShowCallstack@StackWalker@@QAEHPAXPBU_CONTEXT@@P6GH0_K0KPAK0@Z0@Z) referenced in function "public: void __thiscall ContextHashtableBase<long>::ShowLeaks(class LeakFinderOutput &)" (?ShowLeaks@?$ContextHashtableBase@J@@QAEXAAVLeakFinderOutput@@@Z)
    ---
    Rasmus Kaae
    http://kodepage.blogspot.com/
    http://www.3kings.dk
    http://www.hestebasen.com

    GeneralRe: Heaps of compiler/linker errors with VC10 ExpressmemberJochen Kalmbach [MVP VC++]27 Oct '10 - 20:56 
    Be sure that you only have one version of the leakfinder added to your project!
    GeneralAfter DeInitAllocCheck(), InitAllocCheck() doesn't report tracesmemberRam Vemireddy21 Oct '10 - 9:34 
    Hello,
    Its a great tool and working perfect.
     
    I wanted to capture the memory leaks when I run operation/task.
    I was able to call InitAllocCheck() before operation/task and DeInitAllocCheck() after operation/task. XML file generated and worked fine.
     
    After that for another operation/task without restarting the process/application, I call InitAllocCheck() before task and DeInitAllocCheck() after the task. It doesn't capture the traces properly.
    Do you know why?
     
    thanks in advance for your help ..!
    -Ram
    GeneralRe: After DeInitAllocCheck(), InitAllocCheck() doesn't report tracesmemberJochen Kalmbach [MVP VC++]21 Oct '10 - 9:41 
    Have you tried the latest version from:
    http://blog.kalmbachnet.de/files/Leakfinder_RC11.zip[^]
     
    Also be aware that the leakfinder is a *prcess-wide* feature. It makes not many sense to just enable it for a certain time, because you do not know which threas also have allocated memory...
    GeneralRe: After DeInitAllocCheck(), InitAllocCheck() doesn't report tracesmemberRam Vemireddy21 Oct '10 - 10:39 
    Thank you for your spontaneous response.
    I actually have more than 500 DLLs in my process and I wanted to capture memory leaks happening in all DLLs per operation/task.
    Could you please point me to LeakFinder_RC11 help, if you have one already?
     
    Does the tool work for release build as well (CRT & COM)?
     
    Thank you,
    Ram
    GeneralRe: After DeInitAllocCheck(), InitAllocCheck() doesn't report tracesmemberJochen Kalmbach [MVP VC++]21 Oct '10 - 10:40 
    It works only for debug builds.
    And I only have this article as "helpfile"... sorry...
    QuestionIs this exception tied to using LeakFinder ?memberhandsinmypocket1 Jul '10 - 3:11 
    I'm using LeakFinder RC11, to figure out a memory leak in a SMTP Event Sink DLL of my own, loaded by the Windows SMTP Service on Windows 2003.
    I have an exception when stopping the iisadmin service. My custom DLL is alredy unloaded, so is the leakfinder hook ?
    Here is the exception stack trace:
     
    	ole32.dll!CSpyMalloc_Free()  + 0x4b bytes	
     	oleaut32.dll!_MemFree@4()  + 0x2b bytes	
     	oleaut32.dll!OLE_TYPEMGR::Release()  - 0x18e bytes	
     	oleaut32.dll!ReleaseAppData()  + 0x1d bytes	
     	oleaut32.dll!CReleaseAppData::Release()  + 0x5 bytes	
     	ole32.dll!_CoSetState@4()  - 0x1ec18 bytes	
     	ole32.dll!wCoUninitialize()  - 0x6e bytes	
     	ole32.dll!_CoUninitialize@0()  + 0x149 bytes	
     	iisadmin.dll!ServiceEntry()  + 0x39b bytes	
     	inetinfo.exe!InetinfoStartService()  + 0x2cc bytes	
     	advapi32.dll!ScSvcctrlThreadW()  + 0x21 bytes	
     	kernel32.dll!_BaseThreadStart@8()  + 0x34 bytes	
     
    First-chance exception at 0x7771c37c (ole32.dll) in inetinfo.exe: 0xC0000005: Access violation reading location 0x01462288.
    Unhandled exception at 0x7771c37c (ole32.dll) in inetinfo.exe: 0xC0000005: Access violation reading location 0x01462288.
     
    Is it trying to call the leakfinder hook ?
     
    TIA.
    AnswerRe: Is this exception tied to using LeakFinder ?memberJochen Kalmbach [MVP VC++]1 Jul '10 - 3:22 
    You must not unload your DLL if you use the COM-LeakFinder... I might remember that COM has some limitations with Malloc-Hooks and unloading...
    I suggest to disable the COM-Leak detection! It almost makes no sence, because COM internaly uses some "garbage collector" (see article).
    GeneralRe: Is this exception tied to using LeakFinder ?memberhandsinmypocket1 Jul '10 - 3:31 
    How would I disable COM-Leak detection ?
    GeneralRe: Is this exception tied to using LeakFinder ?memberJochen Kalmbach [MVP VC++]1 Jul '10 - 7:40 
    Replace the line 838 in LeakFinder.cpp from
        m_pMallocSpy = new CMallocSpy(); // wird später durch Release freigegeben
    into
        m_pMallocSpy = NULL; disable leak finder for COM leaks
     
    And also check for NULL of m_pMallocSpy in Disable and Enable:
      virtual LONG Disable()
      {
        if (m_pMallocSpy == NULL) return 0;
        return InterlockedIncrement(&(m_pMallocSpy->m_disableCount));
      }
      virtual LONG Enable()
      {
        if (m_pMallocSpy == NULL) return 0;
        return InterlockedDecrement(&(m_pMallocSpy->m_disableCount));
      }

    GeneralRe: Is this exception tied to using LeakFinder ?memberhandsinmypocket2 Jul '10 - 2:20 
    Thanks for that.
    I have another problem, which is that file name and line number are empty in the output of leakfinder for my own modules compiled in debug mode.
    I think this is because LeakFinder is enabled in a DLL, not in an executable.
    What do you think ?
    GeneralRe: Is this exception tied to using LeakFinder ?memberhandsinmypocket2 Jul '10 - 3:23 
    Found the problem.
    Because I'm using LeakFinder in a DLL, I must copy the symbols files to the directory of the running app, not the DLL itself.
    For more information : SymGetSymFromAddr64 Function[^]
    Generalproblem with exception tracingmemberkjayalakshmi21 Jun '10 - 1:03 
    i have used stackwalker.cpp, stackwalker.h files for exception tracing. it works fine in debug mode of vs6.0.
     
    but when i copied the executable file of sample application to some other folder with additional dlls, exception tracing does not works. log file is generated without stack tracing.
     
    dbghelp.dll version is 5.1.2600.5512 window xp sp3
     
    please solve this problem
    GeneralRe: problem with exception tracingmemberJochen Kalmbach [MVP VC++]21 Jun '10 - 1:05 
    Stackwalking only works if you have debug-symbols!
     
    For logging Exception you should use "MiniDumpWriteDump"... then you can offline analyse this file with vs or WinDBG1
    GeneralRe: problem with exception tracingmemberJochen Kalmbach [MVP VC++]21 Jun '10 - 1:06 
    FYI: The latest version of the StackWalker can be found here:
    http://stackwalker.codeplex.com/[^]
    Generalmissing stack framesmemberluke.simon19 May '10 - 14:32 
    After using LeakFinder-RC10 in a large project and inspecting the stack traces using MemLeakAnalyse, I've noticed that some some stack traces are missing the bottom stack frames. For example, a call to new may be 20 calls deep, but when I expand the stack trace, the stack entry for main and the function called by main are missing. Any ideas why this is happening?
    GeneralRe: missing stack framesmemberJochen Kalmbach [MVP VC++]19 May '10 - 20:43 
    The leakfinder is capturing the stack frames at runtime. And I restricted the size of the collected stackframes to 0x2000 bytes. If you need more infos, you can increase this value in
    LeakFinder.cpp:1076
    #define MAX_CALLSTACK_LEN_BUF 0x2000
    Generalcrash due to use of strcpy_s as opposed to strncpy_smemberluke.simon19 May '10 - 14:29 
    I used the latest LeakFinder-RC10 in an application that uses template classes and functions, which results in extremely long function names. To make a long story short, LeakFinder crashed in a call to strcpy_s, because the destination buffer wasn't large enough. The quick fix is to replace each call to strcpy_s with a call to strncpy_s in StackWalker.cpp, and also #define strncpy_s strncpy.
    GeneralRe: crash due to use of strcpy_s as opposed to strncpy_smemberJochen Kalmbach [MVP VC++]19 May '10 - 20:40 
    Thanks for this hint. I changed to version to do a "secure copy"...
    See:
    http://blog.kalmbachnet.de/files/LeakFinder-RC11.zip[^]
    GeneralLeakFinder RC9 & MS Application Verifiermemberhandsinmypocket13 Apr '10 - 23:07 
    Fantastic tool.
    Ive noticed that a program using LeakFinder running under the control of MS Application Verifier is stopped with the folowing log:
     
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <avrf:logfile xmlns:avrf="Application Verifier">
    	<avrf:logSession TimeStarted="2010-04-14 : 10:27:34" PID="7968" Version="2">
    		<avrf:logEntry Time="2010-04-14 : 10:27:43" LayerName="Heaps" StopCode="0x2" Severity="Error">
    			<avrf:message>Access violation exception.</avrf:message>
    			<avrf:parameter1>c0c0c0c8 - Invalid address causing the exception</avrf:parameter1>
    			<avrf:parameter2>510825 - Code address executing the invalid access</avrf:parameter2>
    			<avrf:parameter3>12ec80 - Exception record</avrf:parameter3>
    			<avrf:parameter4>12ec9c - Context record</avrf:parameter4>
    			<avrf:stackTrace>
    				<avrf:trace>vrfcore!VfCoreRedirectedStopMessage+81 (d:\avrf\source\base\avrf\avrf30\vrfcore\stopredirect.cpp @ 103)</avrf:trace>
    				<avrf:trace>verifier!+5a618d72 ( @ 0)</avrf:trace>
    				<avrf:trace>verifier!+5a617f91 ( @ 0)</avrf:trace>
    				<avrf:trace>ntdll!RtlIpv4StringToAddressExW+c15d ( @ 0)</avrf:trace>
    				<avrf:trace>ntdll!RtlSubtreePredecessor+2e7 ( @ 0)</avrf:trace>
    				<avrf:trace>ntdll!RtlSubtreePredecessor+1a6 ( @ 0)</avrf:trace>
    				<avrf:trace>ntdll!KiUserExceptionDispatcher+e ( @ 0)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!MyAllocHook+336 (d:\devvss\rteoledbsv\leakfinder.cpp @ 782)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!_heap_alloc_dbg_impl+f3 (f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c @ 390)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!_nh_malloc_dbg_impl+1f (f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c @ 239)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!_nh_malloc_dbg+2c (f:\dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c @ 296)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!malloc+1b (f:\dd\vctools\crt_bld\self_x86\crt\src\dbgmalloc.c @ 56)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!CAfxStringMgr::Allocate+66 (f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp @ 141)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!ATL::CSimpleStringT&lt;char,0&gt;::Fork+73 (c:\program files (x86)\microsoft visual studio 9.0\vc\atlmfc\include\atlsimpstr.h @ 774)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!ATL::CSimpleStringT&lt;char,0&gt;::PrepareWrite2+5d (c:\program files (x86)\microsoft visual studio 9.0\vc\atlmfc\include\atlsimpstr.h @ 811)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!ATL::CSimpleStringT&lt;char,0&gt;::PrepareWrite+5c (c:\program files (x86)\microsoft visual studio 9.0\vc\atlmfc\include\atlsimpstr.h @ 800)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!ATL::CSimpleStringT&lt;char,0&gt;::GetBuffer+2f (c:\program files (x86)\microsoft visual studio 9.0\vc\atlmfc\include\atlsimpstr.h @ 523)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!CRTENTService::CreateLog+7d (d:\devvss\rteoledbsv\rtentservice.cpp @ 174)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!CRTENTService::CRTENTService+cf (d:\devvss\rteoledbsv\rtentservice.cpp @ 61)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!CRTENTServiceEx::CRTENTServiceEx+5a (d:\devvss\rteoledbsv\rtentserviceex.cpp @ 39)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!CRTENTServiceOLEDB::CRTENTServiceOLEDB+5d (d:\devvss\rteoledbsv\rtentserviceoledb.cpp @ 40)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!main+90 (d:\devvss\rteoledbsv\rteoledbsv.cpp @ 33)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!__tmainCRTStartup+117 (f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c @ 266)</avrf:trace>
    				<avrf:trace>RTEOLEDBSv!mainCRTStartup+f (f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c @ 182)</avrf:trace>
    				<avrf:trace>kernel32!ProcessIdToSessionId+209 ( @ 0)</avrf:trace>
    			</avrf:stackTrace>
    		</avrf:logEntry>
    	</avrf:logSession>
    </avrf:logfile>
     
    Hope that helps.
    GeneralRe: LeakFinder RC9 & MS Application VerifiermemberJochen Kalmbach [MVP VC++]14 Apr '10 - 20:57 
    Hi
     
    Thanks for the report... but it does not help, because you have changed the leakfinder.cpp Wink | ;) The line 782 is a comment-line...
    GeneralRe: LeakFinder RC9 & MS Application Verifiermemberhandsinmypocket14 Apr '10 - 21:37 
    That's right.
    I've changed the code block of the file starting line 84 to become :
    #include "stdafx.h"
    
    #ifdef _AFX
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    #endif
     
    #include <windows.h>
    I'm now able to find out that a leak is not mine Wink | ;-) :
    d:\devvss\rteoledbsv\leakfinder.cpp(844) : {74} normal block at 0x00F56AA8, 20 bytes long.
     Data: <L m             > 4C 95 6D 00 01 00 00 00 14 00 00 00 00 00 00 00 
    Confirmed by your comment in the file at the specified line:
        m_pMallocSpy = new CMallocSpy(); // wird später durch Release freigegeben
     
    I'm afraid that any report from application verifier would be helpfull because with an attached debugger it stops at another line...
    VOID Insert(HASHTABLE_KEY &key, CONTEXT &context, SIZE_T nDataSize)
      {
        SIZE_T HashIdx;
        AllocHashEntryType *pHashEntry;
     
        // generate hash-value
        HashIdx = HashFunction(key);
     
        pHashEntry = &pAllocHashTable[HashIdx];
        if (IsKeyEmpty(pHashEntry->key) != FALSE) {
          // Entry is empty...
        }
        else {
          // Entry is not empy! make a list of entries for this hash value...
          while(pHashEntry->Next != NULL) { <------ STOPS HERE.
     
    Exception Information :
     
    First-chance exception at 0x0050f6bc in RTEOLEDBSv.EXE: 0xC0000005: Access violation reading location 0xc0c0c0c8.
     
    
    =======================================
    VERIFIER STOP 00000002: pid 0x1F10: Access violation exception. 
     
    	C0C0C0C8 : Invalid address causing the exception
    	0050F6BC : Code address executing the invalid access
    	0012EC80 : Exception record
    	0012EC9C : Context record
     
    0xc0c0c0c8 is the value of the pointer pHashEntry.
     
    HTH.
    TIA.
    Olivier.
    GeneralRe: LeakFinder RC9 & MS Application VerifiermemberJochen Kalmbach [MVP VC++]14 Apr '10 - 22:53 
    Hi!
    Thanks for this report! Can you try to change the method "own_malloc" to:
     
    __inline LPVOID own_malloc(SIZE_T size)
    {
      return HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY, size);
    }
     
    ?
    GeneralRe: LeakFinder RC9 & MS Application Verifiermemberhandsinmypocket14 Apr '10 - 23:16 
    Thanks.
    Now it's working fine Smile | :)
    GeneralLeakFinder and Gtestmemberjimp0220 Mar '10 - 7:31 
    I am trying to use leakfinder with Google Test (gtest) available at http://code.google.com/p/googletest/. Gtest has a statically initialized singleton that requires allocations on the heap. When I run leakfinder, every allocation is reported as a leak, even though it is properly deleted.
     
    I can work around this by making the source module containing the leakfinder defines and includes the first program to be compiled. Then it only reports the two leaks allocated by gtest and not the allocations by my program. Is there something I can do so leakfinder does not have to be the first program compiled? Do you know why this problem occurs?
    GeneralRe: LeakFinder and GtestmemberJochen Kalmbach [MVP VC++]20 Mar '10 - 8:07 
    The C-Runtime initializes static objects in a "mystic" may...
     
    If you want to have a little bit "control" over the order of initialization, you can force the static object to be created in a special segment... for example with "#pragma segment(...)".
     
    If you initialize the Leakfind "by hand", then you can overcome the problems, but also cannot find all leaks (for static initialized objects).
     
    PS: The latest version can be found here:
    http://blog.kalmbachnet.de/files/LeakFinder_RC9.zip[^]
    GeneralRC9 and windows 7memberumeca7411 Jan '10 - 23:24 
    Hi Jochen
     
    I've just tried your RC9 on windows 7 with VS6 (odd combination I know). The sample code you supply with it, unmodified, compiles ok but won't run. I imagine it gets stuck trying to calculate the leaks -- the XML report file remains empty
     
    On windows XP things work but the COM leak isn't reported where it occurs but within _your_ code (leakfinder.cpp line 940). Is this what you mean in the common problems above?
     
    For some reason, the COM-alloc-callstack cannot display the stack-entry which really calls the CoTaskMemAlloc function. Only the upper stack entry can be shown.
     
    is there any way to find the actual code that causes the leak? Knowing about leaks without being able to fix them isn't much use!
     
    thanks
    nikos
    GeneralRe: RC9 and windows 7memberJochen Kalmbach [MVP VC++]11 Jan '10 - 23:35 
    I have not tried Win7 and VC6 Wink | ;)
     
    COM leaks should be reported, it just *starts* in my code... you need to look at the callstack a little bit up! The comment has nothing to do with this...
     
    Of course, you need debug-symbols in order to get (correct) results! Also, starting with Vista you also need to get symbols for MS DLLs from the MS Symbols Server... most DLLs are now compiled with FPO, which makes it almost impossible to walk the callstack without (PDB) symbols.
    GeneralRe: RC9 and windows 7memberumeca7411 Jan '10 - 23:57 
    see the attached pic, there's no mention of the actual leak anywhere (or i can't find it)
     
    click for image[^]
     
    i know how to connect to the symbol server from windbg but how do i tell your leakchecker to get system symbols from it?
    GeneralRe: RC9 and windows 7memberJochen Kalmbach [MVP VC++]12 Jan '10 - 0:03 
    Hmm.. by default, the smbol server will be used...
     
    Can you show me the output in the console/debugger-output window? There should be a list of loaded modules/symbols...
    GeneralRe: RC9 and windows 7memberumeca7413 Jan '10 - 22:50 
    the problem is that VS6 cannot read the 'new' symbol files for XP/SP2, so that's out. In the end I used VS2003 which links to the symbol server and your tool performs well in there too!
     
    now if i could only locate reference count leaks for COM objects allocated outside my code...
    GeneralRe: RC9 and windows 7memberJochen Kalmbach [MVP VC++]13 Jan '10 - 23:10 
    No... VS6 has nothing to do with my leakfinder... even if you compiler your code with VS6...
    You must be sure, that you use a recent/new version od dbghelp.dll! Therefor please install DebuggingToolsForWindows which contains the latest dbghelp.dll. And plase this file in the same folder as the exe.
    Generalirritation with stackwalker [modified]memberBreuerM11 Jan '10 - 22:21 
    in an other topic (Walking the callstack , Walking the callstack[^]) you offer a StackWalker.cpp, which I included in my App.
    The Stackwalker.cpp here seems to be different.
    Can I use this stackwalker, the stackwalker from here, too to show the callstack and have the new opportunity to search for memoryleaks ?
    Will there be a problem when I change the stackwalker.h/.cpp against the files from here ?
     
    modified on Tuesday, January 12, 2010 8:52 AM

    GeneralRe: irritation with stackwalkermemberJochen Kalmbach [MVP VC++]11 Jan '10 - 22:24 
    You can use the new Stackwalker.cpp/h from the LeakFinder_RC9; it combines the StackWalker with the LeakFinder Wink | ;)
    http://blog.kalmbachnet.de/files/LeakFinder_RC9.zip[^]
    GeneralRe: irritation with stackwalkermemberBreuerM12 Jan '10 - 3:47 
    thank you it works, after including the leakfinder.
    GeneralRe: irritation with stackwalkermemberBreuerM20 Jan '10 - 6:37 
    Hi Jochen,
    when I make a small application with your hints
    #define INIT_LEAK_FINDER
    #define XML_LEAK_FINDER
    #include "..\dot_h\leakfinder.h"
    
    int main( int argc, char **argv)
    {
    	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    	// Lines with Memoryleaks
            //_CrtSetBreakAlloc( 139 ); //139  138  137  133  132 (### uncomment to break, break does not work)
    	_CrtDumpMemoryLeaks();
    	return 0;
    }
    
     
    the Application ends in the following output
     
    Detected memory leaks!
    Dumping objects ->
    {139} normal block at 0x00397B60, 36 bytes long.
    Data: <p}s > 70 7D 73 00 20 00 A4 02 FD 03 00 00 00 00 18 02
    {138} normal block at 0x00397B10, 20 bytes long.
    Data: < ~s z9 > F4 7E 73 00 01 00 00 00 00 00 00 00 B8 7A 39 00
    {137} normal block at 0x00397AB8, 28 bytes long.
    Data: < ~s ^ > BC 7E 73 00 20 00 5E 01 FD 03 00 00 00 00 D2 00
    {133} normal block at 0x00396948, 68 bytes long.
    Data: < h9 > E8 68 39 00 00 00 00 00 FF FF FF FF 00 00 00 00
    {132} normal block at 0x003968E8, 36 bytes long.
    Data: <h|s Hi9 > 68 7C 73 00 48 69 39 00 FF FF FF FF DC 08 00 00
    Object dump complete.
    "TcmsUnitTest.exe": "C:\WINDOWS\system32\dbghelp.dll" wurde geladen
    "TcmsUnitTest.exe": "C:\WINDOWS\system32\dbghelp.dll" entladen.
     
    I use Microsoft Visual C++ 2008,
    and I can not get a program-break by activating the marked line.
    Is this real leaks ?
    These leaks are not reported by your tool.
    GeneralWorks OK with VS 2010memberjimp0221 Dec '09 - 10:04 
    Your LeakFinder works with Visual Studio 2010. The _CrtMemBlockHeader has not changed. There was a problem converting the Visual Studio project files however. It said it could not convert the .vcproj file. I had to create a new project and changed the preprocessor statements (_MSC_VER 1600). Once that was done it worked fine.
     
    I noticed you moved StackWalker moved to CodePlex. Why don’t you move LeakFinder also?
    GeneralRe: Works OK with VS 2010memberJochen Kalmbach [MVP VC++]21 Dec '09 - 10:05 
    Thanks for your reply!
    The reason that I did not move leakfinder is "time"...
     
    Maybe I will find some during the holidays...
    QuestionUnresolved external symbolmembermath's2 Oct '09 - 5:08 
    Hello,
     
    I got last version of Memory-Leak (RC9). I was able to build your project with MS VC8, no problem.
    After, in my project, I made the following :
    - added LeakFinder.h and .cpp to my project
    - added StackWalker.h and .cpp to my project
    - added #define INIT_LEAK_FINDER, #define XML_LEAK_FINDER and #include <leakfinder.h> in my main.cpp file
     
    But I've these messages when i build my program :
    LeakFinder.obj : error LNK2019: symbole externe non résolu __imp___CrtSetAllocHook référencé dans la fonction "public: __thiscall CRTTable::CRTTable(void)" (??0CRTTable@@QAE@XZ)
    1>LeakFinder.obj : error LNK2019: symbole externe non résolu __imp___CrtIsValidHeapPointer référencé dans la fonction "int __cdecl MyAllocHook(int,void *,unsigned int,int,long,unsigned char const *,int)" (?MyAllocHook@@YAHHPAXIHJPBEH@Z)
    1>LeakFinder.obj : error LNK2019: symbole externe non résolu __imp___CrtDbgReportW référencé dans la fonction "int __cdecl MyAllocHook(int,void *,unsigned int,int,long,unsigned char const *,int)" (?MyAllocHook@@YAHHPAXIHJPBEH@Z)
    1>LeakFinder.obj : error LNK2001: symbole externe non résolu __imp___crtDbgFlag
     
    Can somebody help me ?
    Thanks.
    AnswerRe: Unresolved external symbolmemberJochen Kalmbach [MVP VC++]2 Oct '09 - 6:21 
    My project only works for debug-builds... I assume that you have removed the "DEBUG" switches in my code...
    GeneralRe: Unresolved external symbolmembermath's2 Oct '09 - 6:37 
    Hello Jochen,
     
    thank you for your fast reply !
     
    Your project works fine, I can build it, but when I try to use LinkFinder into one of my project, I get link errors ! My project's properties are exactly the same than yours...
     
    Sure, something is wrong in my program but I cannot find what !!!
     
    Best regards.
    GeneralRe: Unresolved external symbolmemberJochen Kalmbach [MVP VC++]2 Oct '09 - 6:39 
    Are you building release or debug?
    In the configuration which has this problem, are you lining against the release-CRT or Debug-CRT? Have you defined _DEBUG in this configuration?
    GeneralRe: Unresolved external symbolmembermath's2 Oct '09 - 6:41 
    I build debug mode and i've _DEBUG in my preprocessor's defines.

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Permalink | Advertise | Privacy | Mobile
    Web01 | 2.6.130516.1 | Last Updated 1 Dec 2005
    Article Copyright 2002 by Jochen Kalmbach [MVP VC++]
    Everything else Copyright © CodeProject, 1999-2013
    Terms of Use
    Layout: fixed | fluid