Detecting memory leaks in Qt applications with Visual Studio

[ad name=”breit”]

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.

24 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 🙂

  16. DCKelley says:

    > That’s not garbage. That’s actually a memory leak of 20 bytes size
    But without the key data of the __FILE__, __LINE__ its somewhat close to it.
    That is the point I have reached (working on Qt 5.9.1 with MSVC2015, 32bit, Creator 4.3.1)

    Before a pile of these objects, I am getting more data, lines like below:
    misc\Console.cpp(66) : {4305} normal block at 0x065C02B0, 4 bytes long.
    mainwindow.cpp(208) : {4303} normal block at 0x05FA6590, 280 bytes long.
    mainwindow.cpp(207) : {4302} normal block at 0x065BF9F0, 1176 bytes long.
    Detected memory leaks!
    Dumping objects ->
    {1136025} normal block at 0x08EC6A50, 123 bytes long.
    Data: CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
    {1127567} normal block at 0x0990F488, 44 bytes long.
    Data: F0 5E E9 08 00 00 00 00 1B 68 EE 5D 00 00 00 00

    And I have the impression that the ones at the top are all Qt DLLs yet to unload, as the code is just call to new objects in the normal Qt way of things. The first block (123 bytes) was the one I purposefully created in my deconstruct to make a leak.

    I have the impression I have called it twice and that the DLLs are still loaded, I call _CrtDumpMemoryLeaks after the Qt return as below. Does anything stupid suggest itself here?

  17. Andreas Schmidt says:

    I think you only have to care about the leaks reported after “Dumping objects ->”. Anything before that is just framework stuff. It might even be memory leaks created by 3rd party libraries. It may be false reports, because the libraries will release the memory after the debug handler reported the leaks. I wouldn’t worry about it.

  18. Wes says:

    Ok, I’m having issues with this again. I’ve had this working for 2 years now on one project. Said project is now in Creator 4.8.1 and running Qt 5.11.1, still shows “Detected memory leaks!” and “Dumping objects ->” every time at the end of a debug run.
    So, I have a new project. Same Creator, same Qt version. I copied over the same files for this purpose, copy/pasted all the same blocks at the beginning of files, the same stuff in main.cpp…. Double checked, all the same.
    However, in my new project, debug run, I get nothing at the end. Just exits. I’ve gone through project settings, everything to make sure they are the same yet one works and one does not.

  19. Andreas Schmidt says:

    Hi, did you switch from Visual Studio to QtCreator? I’m pretty confident the leak detection only works in Visual Studio. Look at setDebugNew.h

    #if defined(VSTUDIO) && defined(_DEBUG)
    #include
    #define new DEBUG_NEW
    #endif

  20. Wes says:

    I’ve been using the leak detection in Creator for 2 years on the other project, it does work. I have VS installed as the debugger/compiler is needed from it but always use Creator.

  21. Wes says:

    So mine actually looks like this and has worked fine, in Creator, not sure why it’s not in the new project.

    //setdebugnew.h
    #define _CRTDBG_MAP_ALLOC
    #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )

    //Beginning of cpp files
    //Leak detection
    #ifdef Q_OS_WIN32
    #ifdef QT_DEBUG
    #include “debugtools/reportinghook.h”
    #include “debugtools/setdebugnew.h”
    #define new DEBUG_NEW
    #endif
    #endif

  22. Wes says:

    Haha, got it! For anyone else struggling in Qt Creator, I was using exit(0) in my new project on close button click, whereas in my old project I used close(). You must apparently use the latter and leak detection works!

  23. Andreas Schmidt says:

    That makes sense. exit() terminates the process and probably bypasses the cleanup code that does the memory reporting.

    good that you found that. Perhaps it helps somebody who stumbles over this discussion.

  24. Pingback: Deleaker Review | WinFIG Home Page

Leave a Reply

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