|
As a matter of course, I use that...
#ifndef MYHEADERFILE
#define MYHEADERFILE
... all the code in your header1.h file
#endif
...trick.
I don't like giving huge code dumps, but it's a tiny program...
#if !defined(_HEADER1_H_)<br />
#define _HEADER1_H_<br />
<br />
#include "header1.h"<br />
#include <debug_crt.h><br />
<br />
#ifdef _DEBUG<br />
#define new DEBUG_NEW<br />
#undef THIS_FILE<br />
<br />
static char THIS_FILE[] = __FILE__;<br />
#endif<br />
<br />
int main ()<br />
{<br />
SetMemoryLeakFlag ();<br />
<br />
GenerateMemoryLeak ();<br />
<br />
int *l = new int;<br />
<br />
return 0;<br />
}<br />
<br />
#endif // _HEADER1_H_
<br />
#include <debug_crt.h><br />
<br />
#ifdef _DEBUG<br />
#define new DEBUG_NEW<br />
#undef THIS_FILE<br />
<br />
static char THIS_FILE[] = __FILE__;<br />
#endif<br />
<br />
void GenerateMemoryLeak ()<br />
{<br />
int *l = new int;<br />
}
#if !defined(_DEBUG_CRT_H_)<br />
#define _DEBUG_CRT_H_<br />
<br />
#include <cstdlib><br />
#include <crtdbg.h><br />
<br />
#ifdef _DEBUG<br />
<br />
inline void* operator new(size_t nSize, const char * lpszFileName, int nLine)<br />
{<br />
return ::operator new(nSize, 1, lpszFileName, nLine);<br />
}<br />
<br />
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine) <br />
{ <br />
::operator delete(_P, _NORMAL_BLOCK, lpszFileName, nLine); <br />
}<br />
<br />
#define DEBUG_NEW new(THIS_FILE, __LINE__)<br />
#define MALLOC_DBG(x) _malloc_dbg(x, 1, THIS_FILE, __LINE__);<br />
#define malloc(x) MALLOC_DBG(x)<br />
<br />
#endif // _DEBUG<br />
<br />
void SetMemoryLeakFlag ();<br />
<br />
#endif // _DEBUG_CRT_H_
#include <debug_crt.h><br />
<br />
void SetMemoryLeakFlag ()<br />
{<br />
#ifdef _DEBUG<br />
int tmpDbgFlag;<br />
<br />
tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);<br />
tmpDbgFlag |= _CRTDBG_DELAY_FREE_MEM_DF;<br />
tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;<br />
<br />
_CrtSetDbgFlag (tmpDbgFlag);<br />
#endif<br />
}
That's the whole project. Main.cpp includes header1.h, and debug_crt.h. Also, header1.h and debug.cpp include debug_crt.h. If I have the _THIS_FILE_DEFINED_ lines commented out like above, it complains of THIS_FILE in header.h being redifined in main.cpp. Uncommenting that means it compiles, but there will only ever be one THIS_FILE. Meaning the first file the compiler finds it in will be blamed for any and all memory leaks! In this case, the memory leak in main.cpp gets pinned on header1.h.
P.S. I still don't understand that #undef THIS_FILE...
Cheers
|
|
|
|
|
Same Anonymous poster here. A correction to the previous post:
One may have noticed that the
#if !defined(_HEADER1_H_)<br />
#define _HEADER1_H_<br />
...<br />
#endif // _HEADER1_H_
was around the main.cpp code instead of header1.h code.
It makes no difference fixing it.
I know why I'm getting the errors I'm getting, I need a way around them. I've tried this method of catching memory leaks using a .cpp file instead of a .h and it works fine, because one never has a .cpp file include another (or a good reason for doing so, at least).
As I've said before, I need to have everything in the .h file because I'm using template classes and VC++ 6.0 SP5. I could have the definitions in a separate a .cpp file, and #include it at the end of the .h file, but that's effectively the same thing, and won't solve the problems I'm having.
Thanks for any help with this problem!
|
|
|
|
|
take all that THIS_FILE stuff out of your header. it's a variable declaration, and you shouldn't declare variables in header files (for just this reason).
header files aren't expanded like macros, they're read and stuffed into the .cpp file whole, at the plaec of the #include. so, when you have this in and #included header:
<br />
#ifdef _DEBUG<br />
#define new DEBUG_NEW<br />
#undef THIS_FILE<br />
static char THIS_FILE[] = __FILE__;<br />
#endif<br />
and the same thing in the .cpp that #includes the header, you end up with:
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
...
<br />
#ifdef _DEBUG<br />
#define new DEBUG_NEW<br />
#undef THIS_FILE<br />
static char THIS_FILE[] = __FILE__;<br />
#endif<br />
and then when the preprocessor gets done with the #ifdefs, you end up with:
<br />
#define new DEBUG_NEW<br />
#undef THIS_FILE<br />
static char THIS_FILE[] = __FILE__;<br />
<br />
...<br />
<br />
#define new DEBUG_NEW<br />
#undef THIS_FILE<br />
static char THIS_FILE[] = __FILE__;<br />
which is equivalent (in terms of error) to this:
<br />
int foo;<br />
int foo;<br />
you've declared the same variable twice.
Anonymous wrote:
I still don't understand that #undef THIS_FILE
it's just something that the normal new/malloc stuff used. i just copied it into my stuff. i didn't bother to figure out what it does. but, i'm 99.44% sure it's not the problem here.
ClickPic | ImgSource | CheeseWeasle
|
|
|
|
|
"...you've declared the same variable twice"
Yup. I understand all of that completely. And I'm not just saying that! The end result is that you can't use this method of getting memory leaks and their origin, in header files. You can only use it in source (.cpp) files because of the problem you have just above described.
I was asking for any way around the problem, i.e. how to get this working for header files. I guess there just isn't one!
class MyClass<br />
{<br />
public:<br />
MyClass () {}<br />
~MyClass () {}<br />
<br />
void GenerateMemoryLeak ()<br />
{<br />
int *l = new int;
}<br />
};
In other words, you can't spot the above memory leak using this method as is, because the leaking code is in a .h file with no .cpp file. Why would I have code like that? Because template classes need it so. A quick google found me this: www.chesapeake.edu/malone/CSC220/VisC++Problem.PDF[^] talks about it just in case some need a reminder...
Thanks for your assistance, regardless!
|
|
|
|
|
this works for me, in simple tests:
header:
<br />
#ifndef IMWATCHINGYOULEAK<br />
#define IMWATCHINGYOULEAK<br />
<br />
#include < crtdbg.h ><br />
<br />
#ifdef _DEBUG<br />
void* operator new(size_t nSize, const char * lpszFileName, int nLine)<br />
{<br />
return ::operator new(nSize, 1, lpszFileName, nLine);<br />
}<br />
#define DEBUG_NEW new(THIS_FILE, __LINE__)<br />
<br />
#define MALLOC_DBG(x) _malloc_dbg(x, 1, THIS_FILE, __LINE__);<br />
#define malloc(x) MALLOC_DBG(x)<br />
<br />
#endif // _DEBUG<br />
<br />
<br />
#ifdef _DEBUG<br />
#define new DEBUG_NEW<br />
#define THIS_FILE __FILE__<br />
#endif<br />
<br />
template < class T > class leaky<br />
{<br />
public:<br />
void leakbytes(int i) <br />
{<br />
char * p = new char[i];
}<br />
};<br />
#endif // #include guard<br />
and then this is my .cpp file:
<br />
#include "stdafx.h"<br />
#include "lw.h"<br />
<br />
#ifdef _DEBUG<br />
#define new DEBUG_NEW<br />
#undef THIS_FILE<br />
static char THIS_FILE[] = __FILE__;<br />
#endif<br />
<br />
int main(int argc, char* argv[])<br />
{<br />
printf("Hello World!\n");<br />
<br />
leaky < int > bob;<br />
bob.leakbytes(100); <br />
<br />
int *foo = new int[1000];
<br />
_CrtDumpMemoryLeaks(); <br />
return 0;<br />
} <br />
ClickPic | ImgSource | CheeseWeasle
|
|
|
|
|
Aha! All problems solved!
At first I wasn't using an ultra simple project to test it on, merly a simple one. Note in my first post I said:
"...I tried substituting #define THIS_FILE __FILE__. ..."
In the post immediatly after that, dated 23:23 5 Jan '04 as far as I can see, I list a whole host of errors that I got when I tried it. They didn't make a whole lot of sense to me (and I've using VC++ for a long while now), so I assumed it was some macro complication.
I've found out now that they cropped up not because they were caused by the #define THIS_FILE __FILE__, but rather they were just 'revealed' because the #define fix succeeded, and allowed compilation to get to them...
I've been tinkering with an ultra simple project since, and because your suggested use of the #define fix worked in the ultra simple project and not in the simple project, I wanted to know why...
Long storey slightly shorter, those errors in the 'new' file cropped up because the order of the includes in main.cpp was:
#include "header1.h"<br />
#include <iostream><br />
#include <debug_crt.h>
I remember you advising in the article to place the debug_crt.h (in my case) after all previous #includes. Well that #include < iostream > (which wasn't in the ultra simple project) effectively isn't before it, because header1.h contains debug_crt.h and of course it is before debug_crt.h.
I'm not quite sure of the whys, or the exact causes for the errors, all I know is:
#include < iostream ><br />
#include "header1.h"<br />
#include < debug_crt.h >
Fixes 'em!
P.S. sometimes one needs to do a 'rebuild all', VC++ sometimes doesn't do a build normally. I'm getting 'operator DEBUG_NEW not recognized' errors, for example. I'm not sure if it's the .h files with declarations and definitions, or not...
Many thanks for the assist!
|
|
|
|
|
Curses! Just a typo fix in my previous post:
#include "header1.h"
#include
#include
should be
#include "header1.h"
#include < iostream >
#include < debug_crt.h >
At first, I thought those spaces between < and > were just odd coding style... : \
|
|
|
|
|
The specialized "void* operator new(size_t nSize, const char * lpszFileName, int nLine)" is never called--the global operator "new (size_t)" is always called.
|
|
|
|
|
I have tried to add the code and compile, but I get linker errors. It appears that I get one for each source file in which new is used.
Any help would be appreciated.
Frame.obj : error LNK2005: "void * __cdecl operator new(unsigned int,char const *,int)" (??2@YAPAXIPBDH@Z) already defined in FMDB.obj
Offsets.obj : error LNK2005: "void * __cdecl operator new(unsigned int,char const *,int)" (??2@YAPAXIPBDH@Z) already defined in FMDB.obj
RMDCView.obj : error LNK2005: "void * __cdecl operator new(unsigned int,char const *,int)" (??2@YAPAXIPBDH@Z) already defined in FMDB.obj
RtmsView.obj : error LNK2005: "void * __cdecl operator new(unsigned int,char const *,int)" (??2@YAPAXIPBDH@Z) already defined in FMDB.obj
StdAfx.obj : error LNK2005: "void * __cdecl operator new(unsigned int,char const *,int)" (??2@YAPAXIPBDH@Z) already defined in FMDB.obj
Str.obj : error LNK2005: "void * __cdecl operator new(unsigned int,char const *,int)" (??2@YAPAXIPBDH@Z) already defined in FMDB.obj
TraficonView.obj : error LNK2005: "void * __cdecl operator new(unsigned int,char const *,int)" (??2@YAPAXIPBDH@Z) already defined in FMDB.obj
..\OlympicMapAux\EXE\OlympicMap_Debug.exe : fatal error LNK1169: one or more multiply defined symbols found
|
|
|
|
|
does this app use MFC?
-c
A conclusion is simply the place where someone got tired of thinking.
|
|
|
|
|
"Not Using MFC" in project settings
|
|
|
|
|
does fmdb.cpp define it's own version of "new" ?
-c
A conclusion is simply the place where someone got tired of thinking.
|
|
|
|
|
|
I solved my problem using Mac's code from the "Excellent!" thread in place of the article code in LeakWatcher.h. It works well.
Thank you to Chris for producing the article and helping me out, and also to Mac for posting his variation.
|
|
|
|
|
I have the same situation with link errors - can you post a link to the posting from Mac
cheers Dave
|
|
|
|
|
I think the answer is to modify the header so the new operator is inlined. This avoids the multiple definition problems. This seems to work for me:
inline void* operator new(size_t nSize, const char * lpszFileName, int nLine)
{
return ::operator new(nSize, 1, lpszFileName, nLine);
}
I do still get warnings that there is no matching delete and there might be a problem if an exception is thrown during initialization, but it seems to work.
|
|
|
|
|
The reason is that the definition of the "new" operator
is beeing added to every .cpp file by including LeakWatcher.h
Modify LeakWatcher.h to contain the declaration only:
void* operator new(size_t nSize, const char * lpszFileName, int nLine);
and insert the definition directly into your main .cpp file (only one place):
#ifdef _DEBUG
void* operator new(size_t nSize, const char * lpszFileName, int nLine)
{
return ::operator new(nSize, 1, lpszFileName, nLine);
}
#endif
Dalibor
|
|
|
|
|
I have been trying to nail some memory leaks for a while, the only leak I saw is my patience was dripping until I read through the threads. With you guys' great codes I now can see the file, the line # and the paradise. Thanks Chris, thanks Rick, thanks anonymous...whoever you are
p.s. I'm programming wxWindows app using VC6 on Windows XP.
|
|
|
|
|
Hi,
In step 2, it's says:
Call _CrtDumpMemoryLeaks(); at the end of your program.
I have put it at the end of my WinMain function, but my global variables are deallocated after that. So, I always get a "fake" memory leak in my debug window. Did someone know how to fix that???
Thank in advance!!!
|
|
|
|
|
Create a class, and declare an object of the class global before the app object (I'm not quite sure where to declare it to make it the first constructed... you may want to create two classes, declaring one as a static object of the other. You could set up a test project to determine what types of objects are constructed first). Put the following in the constructor of the class.
int tmpDbgFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
tmpDbgFlag |= _CRTDBG_CHECK_ALWAYS_DF;
tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag(tmpDbgFlag);
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_DEBUG );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_DEBUG );
HTH
|
|
|
|
|
Ignore the 'tmpDbgFlag |= _CRTDBG_CHECK_ALWAYS_DF;' line in the previous email. For some reason, it is causing my program to go into an infinite loop. Note also, that instead of including the above code in the constructor of your class, you could include _CrtDumpMemoryLeaks(); in the destructor.
|
|
|
|
|
First of all, thanks for the tips. They are very helpful.
I recently tried to use this code and it almost works but there are a few things I did to get it to work right for me with VC6.0. First, I had to add a delete operator. I get compiler errors without it. Here is the one I used :
<br />
<br />
__inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine)<br />
{<br />
::operator delete(_P, lpszFileName, nLine);<br />
}<br />
<br />
The rest of these are not necessarily required but they work nicely for me.
First, I did not need to use the MALLOC_DBG definition. The built-in one worked correctly as did the one for calloc.
Second, I use strdup frequently and there is no version of it that tracks allocations that I could find. Here is my version that will :
<br />
<br />
__inline char *StrDup( const char * string, const char * file, int line )<br />
{<br />
int length = strlen( string ) + 1;<br />
char *newstr = (char *)_malloc_dbg( length, _NORMAL_BLOCK, file, line );<br />
if( newstr )<br />
memcpy( newstr, string, length );<br />
return newstr;<br />
}<br />
<br />
#define strdup(string) StrDup(string,__FILE__,__LINE__)<br />
<br />
Thirdly, I use this little function as the first call in my programs :
<br />
<br />
__inline void SetMemDbgFlag( void )<br />
{<br />
#ifdef _DEBUG<br />
<br />
int tmp = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );<br />
tmp |= _CRTDBG_LEAK_CHECK_DF;
tmp &= ~_CRTDBG_CHECK_CRT_DF;
_CrtSetDbgFlag( tmp );<br />
<br />
#endif // _DEBUG<br />
}<br />
<br />
When the program terminates the CRTlib automatically checks for leaks and reports them correctly. I don't use any other Crt* calls.
Once again, thanks for the info. I found it very helpful.
|
|
|
|
|
I mean it really, but your code did not work at first for me (some errors and warnings C2491). So here is the code I am using now, greatly inspired by yours.
#ifdef _CRTDBG_MAP_ALLOC
#undef _CRTDBG_MAP_ALLOC
#endif
#include <crtdbg.h>
#ifdef _DEBUG
#define THIS_FILE __FILE__
inline void* operator new(size_t nSize, const char * lpszFileName, int nLine)
{
return ::operator new(nSize, _NORMAL_BLOCK, lpszFileName, nLine);
}
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine)
{
::operator delete(_P, lpszFileName, nLine);
}
#define DEBUG_NEW new(THIS_FILE, __LINE__)
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define calloc(c, s) _calloc_dbg(c, s, _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define realloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define _expand(p, s) _expand_dbg(p, s, _NORMAL_BLOCK, THIS_FILE, __LINE__)
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
#define _msize(p) _msize_dbg(p, _NORMAL_BLOCK)
#endif
I hope it helps.
Mac
|
|
|
|
|
Hi,
Using the code in the original posting gives me some linkage errors and the 4291 warning. Using the code shown in the 'Excellent' posting gives me the following:
warning C4717: 'operator delete' : recursive on all control paths, function will cause runtime stack overflow
PGAdoConnection.cpp
The file above is a wrapper to ADO that we use here.
Also, when I run my app through debug mode is shows some info, but no file names and line numbers.
Does anyone have any idea's why this might happen?
Thanks in advance.
|
|
|
|
|
gunnware wrote:
Using the code shown in the 'Excellent' posting gives me the following:
warning C4717: 'operator delete' : recursive on all control paths, function will cause runtime stack overflow
PGAdoConnection.cpp
Change :
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine)
{
::operator delete(_P, lpszFileName, nLine);
}
To :
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine)
{
::operator delete(_P, _NORMAL_BLOCK, lpszFileName, nLine);
}
|
|
|
|
|