rubyists-

this is _really_ simplistic, and only works with glibc systems (includes
most/all linuxes) having an addr2line program, but here's a little memory leak
detecting scheme which works with c and c++


add this to your c sources...

  #include "leaks.h"

and recompile with '-g'	      <<-- IMPORTANT!!!

run c programs/ruby code using c extension, this will attempt to write the
file './mtrace.log' in the current directory, so be sure you have write
permissions there!

after the run do

  mtrace.rb ./a.out ./mtrace.log /usr/bin/addr2line

note that the above are the default arguments so if those values are correct
you only need do

  mtrace.rb

EXAMPLE

for this c++ program

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include "leaks.h"
 4
 5
 6 void *
 7 leak0 (void)
 8 {
 9   return malloc (1);
10 }
11
12
13 class Foo
14 {
15 public:
16   Foo ()
17   {
18   };
19   long l;
20 };
21
22
23
24 int
25 main (int argc, char **argv)
26 {
27
28   int i;
29   void *a, *b;
30   Foo *foo;
31
32   b = malloc (1);
33   free (b);
34   a = malloc (1);
35   a = malloc (1);
36
37   b = leak0 ();
38   free (b);
39   a = leak0 ();
40   a = leak0 ();
41
42   foo = new Foo ();
43   delete foo;
44   foo = new Foo ();
45
46   return 1;
47 }


the output will be

POTENTIAL LEAKS
+ [0x4005e224] 0x0804a048 -> 0x00000004
@ [0x080489a5] frame 0 a.out(backtrace_symbols+0x1d5) [0x80489a5] /home/ahoward/eg/c/leak/leaks.h:65
@ [0x401673ad] frame 1 /lib/libc.so.6(malloc+0x2d) [0x401673ad] ??:0
@ [0x4005e224] frame 2 /usr/local/lib/libstdc++.so.3(_Znwj+0x24) [0x4005e224] ??:0
@ [0x08048c72] frame 3 a.out [0x8048c72] /home/ahoward/eg/c/leak/leak_driver.cc:42
@ [0x40107336] frame 4 /lib/libc.so.6(__libc_start_main+0x8e) [0x40107336] ??:0
@ [0x08048821] frame 5 a.out(_Unwind_Resume+0x31) [0x8048821] ??:0

+ [0x08048b70] 0x0804a038 -> 0x00000001
@ [0x080489a5] frame 0 a.out(backtrace_symbols+0x1d5) [0x80489a5] /home/ahoward/eg/c/leak/leaks.h:65
@ [0x401673ad] frame 1 /lib/libc.so.6(malloc+0x2d) [0x401673ad] ??:0
@ [0x08048b70] frame 2 a.out(__gxx_personality_v0+0x420) [0x8048b70] /home/ahoward/eg/c/leak/leak_driver.cc:11
@ [0x08048be7] frame 3 a.out [0x8048be7] /home/ahoward/eg/c/leak/leak_driver.cc:38
@ [0x40107336] frame 4 /lib/libc.so.6(__libc_start_main+0x8e) [0x40107336] ??:0
@ [0x08048821] frame 5 a.out(_Unwind_Resume+0x31) [0x8048821] ??:0

+ [0x08048b70] 0x0804a028 -> 0x00000001
@ [0x080489a5] frame 0 a.out(backtrace_symbols+0x1d5) [0x80489a5] /home/ahoward/eg/c/leak/leaks.h:65
@ [0x401673ad] frame 1 /lib/libc.so.6(malloc+0x2d) [0x401673ad] ??:0
@ [0x08048b70] frame 2 a.out(__gxx_personality_v0+0x420) [0x8048b70] /home/ahoward/eg/c/leak/leak_driver.cc:11
@ [0x08048bdf] frame 3 a.out [0x8048bdf] /home/ahoward/eg/c/leak/leak_driver.cc:37
@ [0x40107336] frame 4 /lib/libc.so.6(__libc_start_main+0x8e) [0x40107336] ??:0
@ [0x08048821] frame 5 a.out(_Unwind_Resume+0x31) [0x8048821] ??:0

+ [0x08048bbe] 0x0804a018 -> 0x00000001
@ [0x080489a5] frame 0 a.out(backtrace_symbols+0x1d5) [0x80489a5] /home/ahoward/eg/c/leak/leaks.h:65
@ [0x401673ad] frame 1 /lib/libc.so.6(malloc+0x2d) [0x401673ad] ??:0
@ [0x08048bbe] frame 2 a.out [0x8048bbe] /home/ahoward/eg/c/leak/leak_driver.cc:33
@ [0x40107336] frame 3 /lib/libc.so.6(__libc_start_main+0x8e) [0x40107336] ??:0
@ [0x08048821] frame 4 a.out(_Unwind_Resume+0x31) [0x8048821] ??:0

+ [0x08048bae] 0x0804a008 -> 0x00000001
@ [0x080489a5] frame 0 a.out(backtrace_symbols+0x1d5) [0x80489a5] /home/ahoward/eg/c/leak/leaks.h:65
@ [0x401673ad] frame 1 /lib/libc.so.6(malloc+0x2d) [0x401673ad] ??:0
@ [0x08048bae] frame 2 a.out [0x8048bae] /home/ahoward/eg/c/leak/leak_driver.cc:32
@ [0x40107336] frame 3 /lib/libc.so.6(__libc_start_main+0x8e) [0x40107336] ??:0
@ [0x08048821] frame 4 a.out(_Unwind_Resume+0x31) [0x8048821] ??:0

CONFIRMED LEAKS



the '+' indicates a malloc which was never freed, note that this is not always
a leak since some resources might me mallocd once per process and freed on
exit!  however, in this program they all are, in fact, leaks.  examine the
stack trace for each leak, it shows the file name and line number for each
call on the stack, some of them cannot be resolved (system files) but the
one's in our program can, IFF you compile with -g, i included the line numbers
in the source - check it out - every leak is detected acurately.

the sources are available from

  http://eli/lib/ruby/site_ruby/leak/leak.tgz

try them out with

  tar xvfz leak.tgz
  cd leak
  make

they are ***very*** simple and have NO error detection.
however, they are simple enough to hack up yourself into a reasonable memory
leak detection scheme... have at it.


if anyone feels like improving these, please send me the improvments, i'm sure
there are MANY to be made.


-ara

-- 

 ====================================
 | Ara Howard
 | NOAA Forecast Systems Laboratory
 | Information and Technology Services
 | Data Systems Group
 | R/FST 325 Broadway
 | Boulder, CO 80305-3328
 | Email: ahoward / fsl.noaa.gov
 | Phone:  303-497-7238
 | Fax:    303-497-7259
 ====================================