views:

1153

answers:

6

After many years of working on a general-purpose C++ library using the Microsoft MSVC compiler in Visual Studio, we are now porting it to Linux/Mac OS X (pray for us). I have become accustomed and quite fond of the simple memory leak detection mechanism in MSVC:

#ifdef DEBUG
    #define _CRTDBG_MAP_ALLOC
    #define NEW   new( _NORMAL_BLOCK, __FILE__, __LINE__)
    #include <stdlib.h>
    #include <crtdbg.h>
#else
    #define NEW   new
#endif

Every memory allocation is done using this NEW macro. Whenever a process using our library terminates, any memory leaks (blocks that have not been de-allocated) are reported on the console along with the file and line # where the memory was originally allocated.

The part about this that I like is that I don't have to actively "run with performance tool" or otherwise indicate that I am looking for leaks. Leaks are reported to me in the regular course of development, every time a process terminates.

Now that we are moving to the GCC world, I find that the memory leak detection tools, many of which are quite sophisticated, require that I explicitly indicate that I'm in leak hunting mode. My IDE is Xcode and I've looked into some of the allocation/leak detection tools (like Instruments and MallocDebug) but I admit I haven't spent the time to get my head around them fully yet. I keep getting put off by the fact that I actually have to specify that I'm looking for a leak ahead of time, instead of being alerted to it automatically.

I am using Xcode 3.2 and I hear that there's now nifty integration with a static analysis tool, but again I haven't looked into this. I'm looking for some idea of what my options are. Is there a comparable mechanism built into GCC and/or Xcode? Is there a simple third-party library or tool that performs the very basic functionality that I know and love? Or should I suck it up and learn the new way of doing things?

+3  A: 

Maybe you could use the Boehm garbage collector as a leak detection tool:

http://www.hpl.hp.com/personal/Hans_Boehm/gc/leak.html

From the site:

#include "leak_detector.h"

main() {
    int *p[10];
    int i;
    /* GC_find_leak = 1; for new collector versions not     */
    /* compiled with -DFIND_LEAK.      */
    for (i = 0; i < 10; ++i) {
    p[i] = malloc(sizeof(int)+i);
    }
    for (i = 1; i < 10; ++i) {
    free(p[i]);
    }
    for (i = 0; i < 9; ++i) {
    p[i] = malloc(sizeof(int)+i);
    }
    CHECK_LEAKS();
}

(you get notified via stderr)

akosch
Thanks for the suggestion. I haven't been able to successfully build the Boehm gc (version 6.8) under Mac OS X, and reading the documentation suggests a number of scary gotchas (questionable multithreading support, questionable C++ support) that is steering me away from this.
Gene Goykhman
+2  A: 

I'm not aware of anything "built-in" that does what you describe, but it doesn't seem like it would be very hard to "roll your own" version of this. You just want your debugging new to record the pointer, file and line in a map<void*, AllocationInfo> where the key is the allocated pointer and the value (AllocationInfo) would be some struct that holds the filename, line number, etc. You also need to define a custom delete operator that checks the map for the pointer being deleted. If found, that entry is removed from the map. Then at process shutdown time you emit the contents of the map.

I found a page where someone describes their own home-grown system that works like this.

Laurence Gonsalves
Thanks for the tip... I'm giving this a shot right now.
Gene Goykhman
+12  A: 

You have a number of options available to you.

First, and most popularly, you can run your application under tools like Valgrind. That should point you to a number of memory abuses, such as NULL pointer reads and writes and memory leaks. There are a number of tools available in the Valgrind suite, so be sure to check them out.

Second, you can always use a library that uses the LD_PRELOAD trick. Basically, the LD_PRELOAD trick allows for DLL injection, which means that tools can be created to help track your memory usage within your application without changing anything. You will find tools such as dmalloc and efence to be quite extensive in the debugging facilities that they offer.

Lastly, recent GCC releases included a tool called Mudflap. This basically uses the function instrumentation to wrap calls around the same memory functions that dmalloc, efence, and Valgrind. The program will be noticably slower, and can be tuned at runtime, though it still looks like it has much potential.

I have used all three and found Valgrind to be very useful. I have been very interested in using Mudflap as well, though I haven't been able to yet.

s1n
+1 for Valgrind. The learning curve is a little steep first, but it amazing not having to recompile.
Matthew
It looks like Mudflap is C and "very simple C++" right now, which I'm pretty sure would preclude our C++ library. Valgrind looks more promising, but would you then always run your DEBUG configuration under Valgrind, or would you typically just run it under Valgrind "once in a while" when looking for leaks and other memory errors? I realize you can do either, but what's your approach?
Gene Goykhman
I typically run Valgrind before milestones, such as demonstrations or development checkpoints. I do this because any memory issues that cropped up since the last milestone will still be there and it's good to be clean going into each milestone. Running it all the time depends on what your focus is during development (performance versus esoteric leaks). It's highly important that you develop a sense of the tool; there will be things that you have to suppress and things that must be addressed immediately.
s1n
+5  A: 

You may also find the MALLOC_CHECK_ environment variable useful.

From malloc(3) man page:

Recent versions of Linux libc (later than 5.4.23) and glibc (2.x) include a malloc() implementation which is tunable via environment variables. When MALLOC_CHECK_ is set, a special (less efficient) implementation is used which is designed to be tolerant against simple errors, such as double calls of free() with the same argument, or overruns of a single byte (off-by-one bugs). Not all such errors can be protected against, however, and memory leaks can result. If MALLOC_CHECK_ is set to 0, any detected heap corruption is silently ignored; if set to 1, a diagnostic message is printed on stderr; if set to 2, abort(3) is called immediately; if set to 3, a diagnostic message is printed on stderr and the program is aborted. Using a non-zero MALLOC_CHECK_ value can be useful because otherwise a crash may happen much later, and the true cause for the problem is then very hard to track down.

grigy
+2  A: 

I had the same problem when we started porting to the Mac. "Run with performance tool -> Leaks" was the only I found and I'm less than thrilled by it ... at least compared to CRTDEBUG. I understand there are some options (as described by others here), but eventually since we are multi platform, we're using Windows to look for the leaks.

Since you mention the static analyzer. We spent some time trying to figure out hot to get it running until we found that it only does C but not C++

Nicholaz
That's exactly my experience so far.
Gene Goykhman
+5  A: 

You should have a look at "Cross-Platform Memory Leak Detector", looks very similar to the crtdbg.h technique.

Cristian Adam
Exactly what I was looking for, thank you!
Gene Goykhman
nice find ... +1 for the question and answer.
Nicholaz