views:

810

answers:

4

I am attempting to get Memory leak detection working with the help of these two articles: http://msdn.microsoft.com/en-us/library/e5ewb1h3%28VS.80%29.aspx http://support.microsoft.com/kb/q140858/

So in my stdafx.h I now have:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)

The only problem is, I have a class which overrides the new function:

class Dummy
{    
  //overloaded new operator
  void FAR* operator new(size_t cb);
}

Now when I compile this code, I get: error C2059: syntax error : 'constant' error C2091: function returns function

Any idea how I can fix this?

+1  A: 

Try #undef new before class definition and then #define new new... again after.

EFraim
+3  A: 

You can use pragma directives to save and restore the new macro when undefing for overloads. See MSDN for the exact syntax.

E.g.

#pragma push_macro("new")
#undef new
void FAR* operator new(size_t cb);
#pragma pop_macro("new")

You can put these in headers, e.g.

begin_new_override.h:

#ifdef new
#define NEW_WAS_DEFINED
#pragma push_macro("new")
#undef new
#endif

end_new_override.h:

#ifdef NEW_WAS_DEFINED
#undef NEW_WAS_DEFINED
#pragma pop_macro("new")
#endif

And then

#include "begin_new_override.h"
void FAR* operator new(size_t cb);
#include "end_new_override.h"
Logan Capaldo
+1  A: 

Instead of defining new to be something different, why not overload operator new?

Add these function definitions somewhere in the global namespace:

// operator new overloads
void* operator new( const size_t size, const char* file, const char* line) throw();
void* operator new( const size_t size, const size_t align, const char* file, const char* line) throw();
void* operator new[]( const size_t size, const char* file, const char* line) throw();
void* operator new[]( const size_t size, const size_t align, const char* file, const char* line) throw();

// can't easily overload operator delete
void operator delete( void* ptr ) throw();
void operator delete[]( void* ptr ) throw();

// matched to the operator new overload above in case of exceptions thrown during allocation
void operator delete( void* ptr, const char* file, const char* line) throw();
void operator delete[]( void* ptr, const char* file, const char* line) throw();
void operator delete( void* ptr, const size_t align, const char* file, const char* line) throw();
void operator delete[]( void* ptr, const size_t align, const char* file, const char* line) throw();

// global new/delete
void* operator new( size_t size ) throw();
void* operator new( size_t size, const std::nothrow_t& ) throw();
void* operator new( size_t size, size_t align ) throw();
void* operator new( size_t size, size_t align, const std::nothrow_t& ) throw();

void* operator new[]( size_t size ) throw();
void* operator new[]( size_t size, const std::nothrow_t& ) throw();

void operator delete( void* ptr, const std::nothrow_t&) throw();
void operator delete[]( void* ptr, const std::nothrow_t&) throw();

Then you can define your own new macro which calls through to the non-global versions and implement the global versions to assert or warn if they're called (to catch anything slipping through).

#define MY_NEW(s)    new(s, __FILE__, __LINE__)

Your class-level overloads will work as expected if you call 'new' directly on the class. If you want to call MY_NEW on the class, you can but you'll have to redefine the overload in the class to match your new.

dominic hamon
+2  A: 

Redefining new via #define at the preprocessor level is a bad idea in my experience -- you not only break operator new overloads, but also placement new, and probably a few other things.

Having all those FILE and LINE macros expanding everywhere causes your .rodata and .data sections to bloat with file strings and line numbers, and generates much more code per call.

Much better (if more effort up-front) to take advantage of the existence of debug information (e.g. .pdb file) and use something like the DbgHelp library's StackWalk64 to gather stack info.

Overload the various combinations of global operator new and operator delete (array, nothrow, etc), have them store and release stack information as memory is allocated and freed.

You can even store this information in a structure like a std::map<void *, StackInfo>, just be careful to not record the allocs caused by the map inserts (a global lock may be sufficient for a single-threaded app, multi-threaded is left as an exercise to the reader).

Since you're recording the entire stack for any given alloc, you can do some nifty tree analysis, grouping allocations (leaks or otherwise) by "function and descendants"... And it is sometimes easier to trace complicated leaks if you know the entire stack from their allocation time.

leander
Incidentally, if someone already knows of a library/toolkit to do this sort of thing (store alloc info with stack traces) under windows -- barring commercial solutions -- I'd love to hear about it, and will happily update the answer. No reason to reinvent the wheel. The version of this I used was on an embedded platform...
leander