Introduction ------------ LeakTracer is a small tool I wrote when checking a C++ program for memory leaks. I couldn't get dmalloc to display what I wanted, and I just saw the __builtin_return_address gcc-extension mentioned. To use LeakTracer, you just add the LeakTracer.o object file to the objects in your Makefile and run your application. LeakTracer uses gdb to print out the exact line where the memory was allocated and not freed - this of course means you have to free all dynamically allocated data. LeakTracer also overrides the global operator new and operator delete - this will obviously give problems if you override them as well. LeakTracer traces new/new[] and delete calls - it does not look at malloc/free/realloc. Here is some example output: ~/p/arc# ea/LeakTracer/leak-analyze ./arc Gathered 8 (8 unique) points of data. (gdb) Allocations: 1 / Size: 36 0x80608e6 is in NullArcableInstance::NullArcableInstance(void) (Machine.cc:40). 39 public: 40 NullArcableInstance() : ArcableInstance(new NullArcable) {} Allocations: 1 / Size: 8 0x8055b02 is in init_types(void) (Type.cc:119). 118 void init_types() { 119 Type::Integer = new IntegerType; Allocations: 1 / Size: 132 (new[]) 0x805f4ab is in Hashtable::Hashtable(unsigned int) (ea/h/Hashtable.h:15). 14 Hashtable (uint _size = 32) : size(_size), count(0) { 15 table = new List [size]; [...] Requirements ------------ You need Perl5 and gdb installed to run the leak-analyzer. You need gcc (or egcs as C++ compiler) - I only tested with egcs-1.0.3. You also need to run this on an architecture which supports __builtin_return_address arguments that are greater than 0 - there may be some problems on MIPS there. You would have to manually inline the register_alloc function to make it work. So far this code has been tested under Linux 2.2, x86 system, Solaris and HP-UX. Installation ------------ Just type make. There is no install target; you should put LeakTracer someplace you can remember. In the Makefile of your application, add LeakTracer.o to your object files - at the very end of them! That part is important, since the destructors for objects seem to be run from left to right (looking at the order object files are specified in), so if you put LeakTracer.o at the beginning, you may observe some memory leaks which do not exist - because the write_leaks function was run before they were actually freed. Your application must also be compiled with debugging enabled (i.e. -g). Running with LeakTracer ----------------------- Then, run your application. As mentioned in the introduction, your application should clean up all its dynamically allocated memory for LeakTracer to give useful output. LeakTracer will write a leak.out file which has the following format: Memory Address Return Address Return Address 2 Size "Memory Address" is the address of the malloc'ed block. "Return Address" is where the new function was called from. "Return Address 2" is as above, but one more frame up. This is used for the new[] operator which in turn calls new. "Size" is the size of the memory block allocated If you specify the environment variable LEAKTRACE_FILE before running your program it will be used instead of just leak.out in the current directory. This can be useful if your program changes directories when running. Analyzing output ---------------- You should then run leak-analyze, since looking at the raw leak.out file will not help you much. To run leak-analyze, you need Perl as well as gdb installed (any version of gdb will probably do). For example: leak-analyze myprog leak.out You don't have to specify the leak.out filename if you just use the default one. leak-analyze will first run nm to check the address of new[], and then run gdb on the file, sending it a number of commands that will show the source lines with the memory leaks. leak-analyze should show you something like this: Gathered 8 (8 unique) points of data. This means there were 8 unfreed allocations which happened from 8 different places. Allocations: 1 / Size: 36 0x80608e6 is in NullArcableInstance::NullArcableInstance(void) (Machine.cc:40). 39 public: 40 NullArcableInstance() : ArcableInstance(new NullArcable) {} This shows each allocation in turn. There was 1 allocation from this line of code, and it was 36 bytes long. Then the address of the allocation is shown and with it two lines of which the second one is the allocation line (you can increase number of lines shown by changing the set listsize directive in the leak-analyze file). That's all there is to it - now you should find those memory leaks, destroy them and rerun leak-analyze. Shared libraries and objects ---------------------------- If you want to analyze the leaks in shared libraries in your file, it may be necessary to make leak-analyze run your program and thus load the shared libraries before searching for addresses. To do that, run leak-analyze with the program name, leak name AND another argument which is where to set the breakpoint, e.g.: leak-analyze myprog leak.out main This will cause leak-analyze to tell gdb to set a breakpoint on "main" and then run the program. After the analysis is complete, the program will be killed. If you want to load some shared libraries, you can set a brekpoint on a different location, e.g. main.cc:42 if you know that once line 42 is reached, all shared objects have been loaded. If your program needs some command line arguments, supply them after "main". Licensing --------- LeakTracer is public domain (i.e. do with it whatever you feel like). Revision history ---------------- February 21, 1999 v1.0 - only tested internally February 23, 1999 v1.1 - added operator new[] / delete[] February 23, 1999 v1.2 - Oops, forgot to free() the memory.. February 26, 1999 v1.3 - allow delete 0 March 27, 1999 v1.4 - Allow %p format without leading 0x for non-GNU libc. Option to leak-analyze to run the program. July 21, 1999 v1.5 - Fix for the above suggested by Alan Gonzalez August 21, 2000 v1.6 - use a destructor instead of __attribute__(destructor) Author: Erwin Andreasen Homepage: http://www.andreasen.org/LeakTracer/