[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.
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 ==========
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
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?
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.
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
@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 ofnew
will be substituted byDEBUG_NEW
. But where a compiler should find this symbol?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.
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
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 🙂
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;
}
@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.
Thank you very much. Really usefull! I used the setDebugNew.h from ‘monst’ in each .cpp file.
pulp
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
I didn’t change anything, and it now works! I’ll take it. 😉
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 🙂
> 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?
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.
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.
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
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.
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
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!
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.
Pingback: Deleaker Review | WinFIG Home Page