Detecting memory leaks in Qt applications with Visual Studio

Visual Studio has the ability to report memory leaks after running an application in debugging mode. This is generelly somehow satisfactory, but raises some problems when developing a Qt application. Qt allocates memory in it’s DLLs and this memory is released when the DLLs are unloaded. Unfortunately this is after Visual Studio reports the supposed leaks.

I’m not sure if this happens always or only in applications that link against MFC libraries. I read somewhere that the MFC cleanup code triggers the check and that this is unfortunately before 3rd patry DLLs can do their cleanup. Thus, the check falsely reports memory leaks.

In case of my application (WinFIG) about 1600 leaks are reported, although none of them is real. This has two annoying implications:

  • Ending the debugger is delayed until the dump is complete
  • It gets very hard to find the real memory leaks

Ok, so far so bad, but what to do? There is a way to replace the function that actually writes the leak info to the output console. I managed to replace this by a function that filters everything out that is not originated from my own code. To sort out, which leaks are from my code and which are from somewhere else, I need to mark “my” memory allocations. I do this with the following definition.

setDebugNew.h

#if defined(WIN32) && defined(_DEBUG)
  #define new DEBUG_NEW
#endif

Add this to all your code files. I placed this in a small include file that I always include as the last one in each CPP file.

Let’s assume you produce the following memory leak in main.cpp:

int main(int argc, char *argv[])
{
  char *foo = new char[100];
  return 0;
}

Now we get the following report:

.\main.cpp(2) : {271457} normal block at 0x020D6220, 100 bytes long.

Note that we can see the source file (main.cpp) name and line number (2).

Now I replace the default reporting function with something that only reports leaks that come with source file/line number info.

This is the header file reportingHook.h:

#pragma once
 
#if defined(WIN32)
  void setFilterDebugHook(void);
#endif

This is the body file reportingHook.cpp:

#if defined(WIN32)
 
#include <string.h>
#include "crtdbg.h"
 
#define FALSE   0
#define TRUE    1
 
_CRT_REPORT_HOOK prevHook;
 
int reportingHook(int reportType, char* userMessage, int* retVal)
{
  // This function is called several times for each memory leak.
  // Each time a part of the error message is supplied.
  // This holds number of subsequent detail messages after
  // a leak was reported
  const int numFollowupDebugMsgParts = 2;
  static bool ignoreMessage = false;
  static int debugMsgPartsCount = 0;
 
  // check if the memory leak reporting starts
  if ((strncmp(userMessage,"Detected memory leaks!\n", 10) == 0)
    || ignoreMessage)
  {
    // check if the memory leak reporting ends
    if (strncmp(userMessage,"Object dump complete.\n", 10) == 0)
    {
      _CrtSetReportHook(prevHook);
      ignoreMessage = false;
    } else
      ignoreMessage = true;
 
    // something from our own code?
    if(strstr(userMessage, ".cpp") == NULL)
    {
      if(debugMsgPartsCount++ < numFollowupDebugMsgParts)
        // give it back to _CrtDbgReport() to be printed to the console
        return FALSE;
      else
        return TRUE;  // ignore it
    } else
    {
      debugMsgPartsCount = 0;
      // give it back to _CrtDbgReport() to be printed to the console
      return FALSE;
    }
  } else
    // give it back to _CrtDbgReport() to be printed to the console
    return FALSE;
};
 
void setFilterDebugHook(void)
{
  //change the report function to only report memory leaks from program code
  prevHook = _CrtSetReportHook(reportingHook);
}
 
#endif

The function setFilterDebugHook must be called at program end:

#include ...
#include "reportingHook.h"
#include "setDebugNew.h"
 
int main(int argc, char *argv[])
{
  QApplication app(argc, argv);
  int result = app.exec();
 
#if defined(WIN32) && defined(_DEBUG)
  setFilterDebugHook();
#endif
 
  return result ;
}

That’s all! Now the memory leak report will only show those occurences that originate from our own source code. But don’t forget to add the #include "setDebugNew.h" to all your files or you won’t see your own memory leaks! I tested all this with Visual Studio 2008 and Qt 4.5.

I hope this helped.

This entry was posted in MFC, Qt, Visual Studio. Bookmark the permalink.

15 Responses to Detecting memory leaks in Qt applications with Visual Studio

  1. Swarit says:

    i did whatever you ,but memory leaks are not displayed
    main.cpp
    1>.\main.cpp(13) : error C2065: ‘DEBUG_NEW’ : undeclared identifier
    1>.\main.cpp(13) : error C2144: syntax error : ‘char’ should be preceded by ‘;’
    1>.\main.cpp(13) : error C2143: syntax error : missing ‘;’ before ‘[‘
    1>.\main.cpp(13) : error C3409: empty attribute block is not allowed
    1>.\main.cpp(13) : error C2143: syntax error : missing ‘]’ before ‘constant’
    1>.\main.cpp(13) : error C2143: syntax error : missing ‘;’ before ‘constant’
    1>.\main.cpp(13) : error C2143: syntax error : missing ‘;’ before ‘]’
    1>.\main.cpp(13) : error C2143: syntax error : missing ‘;’ before ‘]’
    1>Generating Code…
    1>Build log was saved at “file://c:\Users\sudipto\Documents\Visual Studio 2008\Projects\viewLeak\viewLeak\Debug\BuildLog.htm”
    1>viewLeak – 8 error(s), 0 warning(s)
    ========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

  2. admin says:

    The compiler error you receive “error C2065: ‘DEBUG_NEW’ : undeclared identifier” tells me that you did not have the line
    #define new DEBUG_NEW
    in your header file or you did not include setDebugNew.h.

    Check again the code I posted to be put in setDebugNew.h and make sure you include that file in your main.cpp

  3. Psycho says:

    Hello,
    thanks for this great HowTo.
    But I have a problem.
    I get following errors:
    1>MainWindow.cpp
    1>.\MainWindow.cpp(27) : error C2065: ‘THIS_FILE’: nichtdeklarierter Bezeichner
    1>.\MainWindow.cpp(32) : error C2065: ‘THIS_FILE’: nichtdeklarierter Bezeichner
    1>.\MainWindow.cpp(35) : error C2065: ‘THIS_FILE’: nichtdeklarierter Bezeichner
    1>.\MainWindow.cpp(38) : error C2065: ‘THIS_FILE’: nichtdeklarierter Bezeichner
    1>.\MainWindow.cpp(41) : error C2065: ‘THIS_FILE’: nichtdeklarierter Bezeichner
    1>.\MainWindow.cpp(112) : error C2065: ‘THIS_FILE’: nichtdeklarierter Bezeichner
    1>.\MainWindow.cpp(115) : error C2065: ‘THIS_FILE’: nichtdeklarierter Bezeichner
    1>.\MainWindow.cpp(137) : error C2065: ‘THIS_FILE’: nichtdeklarierter Bezeichner

    I checked it out and this error is everywhere, where I use “new”.
    Could you please help me?

  4. Chenna says:

    Hey, I had the same problem with my Qt Application so I added the MFC dll as a “Delay Loaded Library” as suggested here: http://stackoverflow.com/questions/628021/false-memory-leaks-in-a-mfc-project
    And it works perfect for me.
    Thanks for the post.

  5. Dom says:

    Hi, i am also trying to get your example to work, but im having trouble. I was wondering if you can upload a working examples please.

    Thank you

  6. monst says:

    @Chenna:
    Did you delayed a load of MFC dll? I thought that the big idea is to make MFC dll load first (and thus to make it unload last). So it will make a sence to delay a load of Qt dlls. But it’s impossible because Qt dynamic libraries are used at the very start of a program, and a linker will return an error.

    So a problem is not solved for me by a delayed loading.

    About given solution:
    I thought an expression #define new DEBUG_NEW mean that every occurence of new will be substituted by DEBUG_NEW. But where a compiler should find this symbol?

  7. monst says:

    Given solution works for me if setDebugNew.h file will look like this:


    #if defined(WIN32) && defined(_DEBUG)
    #define _CRTDBG_MAP_ALLOC
    #include
    #include
    #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
    #define new DEBUG_NEW
    #endif

    Thanks for your solution, it’s exactly what I searched for.

  8. dj says:

    Thanks for the information.
    But, what about the memory which is allocated using malloc/calloc method?

    Is there any ways to detect leak by for them ?

    Thanks

  9. Dan says:

    It doesnt work for me unless i have:

    #if defined(_MSC_VER) && defined(_DEBUG)
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    #endif

    at the beginning of my main(). Once thats there it works perfectly 🙂

  10. Shayan Eftekhari says:

    Hello,
    Thanks for this post. I had some trouble using this solution which I solved in the following way:
    1. Just like what ‘monst’ mentioned, setDebugNew should be like the following code to prevent compiler from neglecting about ‘DEBUG_NEW’:

    #if defined(WIN32) && defined(_DEBUG)
    #define _CRTDBG_MAP_ALLOC
    #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
    #endif

    2. You should define DEBUG_NEW (#define new DEBUG_NEW) in each file separately. DO NOT PLACE IT IN A HEADER FILE AND INCLUDE IT, OTHERWISE THERE WILL BE NO FILE NAME AND LINE NUMBER AND THE FILTER HOOK WILL HOOK IT JUST LIKE OTHER MEMORY LEAKS.
    3. Call _CrtDumpMemoryLeaks() function at program exit. So, my main.cpp is like this:

    #include "QtMemLeak.h"
    #include
    #include "reportingHook.h"
    #include "setDebugNew.h"

    #define new DEBUG_NEW

    int main(int argc, char *argv[])
    {
    #if defined(WIN32) && defined(_DEBUG)
    setFilterDebugHook();
    #endif
    char *foo = new char[100];
    QApplication a(argc, argv);
    QtMemLeak w;
    w.show();
    int result = a.exec();
    _CrtDumpMemoryLeaks();
    return result;
    }

  11. admin says:

    @dj

    I guess malloc/calloc allocated memory would not be recognized, but I don’t see much reason to use that in C++. I’d rather use “new” whenever possible.

  12. pulp says:

    Thank you very much. Really usefull! I used the setDebugNew.h from ‘monst’ in each .cpp file.

    pulp

  13. Wes says:

    I’ve not been able to get this to work in the latest (QT 5.7.x). Any updates? I just get a bunch of garbage still like this:

    {154} normal block at 0x0027DB30, 20 bytes long.
    Data: 08 DD 77 66 D0 AC 8F 66 70 AC 8F 66 08 D2 8B 66
    {153} normal block at 0x00279E00, 4 bytes long.
    Data: 48 93 28 00
    {152} normal block at 0x0027D5A8, 16 bytes long.
    Data: 01 CD CD CD 00 00 00 00 00 00 00 00 00 00 00 00
    {151} normal block at 0x00279DD0, 4 bytes long.
    Data: A8 D5 27 00
    Object dump complete.

    Using Windows 7 32b, VS 2013, Qt 5.7.1 msvc2013 32b, developing in Qt Creator 4.x

  14. Wes says:

    I didn’t change anything, and it now works! I’ll take it. 😉

  15. admin says:

    Output like this:

    {154} normal block at 0x0027DB30, 20 bytes long.
    Data: 08 DD 77 66 D0 AC 8F 66 70 AC 8F 66 08 D2 8B 66

    That’s not garbage. That’s actually a memory leak of 20 bytes size 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *