Table of contents
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];
[...]
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.
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).
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.
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.
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".
LeakTracer is public domain (i.e. do with it whatever you feel like).
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
Author: Erwin Andreasen
Homepage: http://www.andreasen.org/LeakTracer/