Devel::Plumber - memory leak finder for C programs
use Devel::Plumber; my $mario = new Devel::Plumber(binfile => 'myprogram', pid => 12345); $mario = new Devel::Plumber(binfile => 'myprogram', corefile => 'core.12345'); $mario->find_leaks(); $mario->report_leaks();
Devel::Plumber is a memory leak finder for C programs, implemented in Perl. It uses GDB to walk internal glibc heap structures, so it can work on either a live process or a core file.
Devel::Plumber treats the C heap of the program under test as a collection of non-overlapping blocks, and classifies them into one of four states.
The block is not allocated.
The block is allocated but there are no pointers to any address in it, so the program cannot reach it.
The block is allocated and there are pointers to addresses within it, but no pointers to the start of it. The program might be able to reach it in some unobvious way via those pointers (e.g. using pointer arithmetic), or the pointers may be dangling pointers to earlier generations of blocks. Devel::Plumber cannot tell the difference between these possibilities.
The block is allocated and there are pointers to the start of the block.
Devel::Plumber proceeds in two main phases. In the first phase, the glibc internal heap structures are walked to discover all the blocks. Unallocated blocks are set to Free state at this time and allocated blocks are initially set to Leaked state. In the second phase, reachable blocks are marked. All the .data and .bss sections in the program (and all loaded shared libraries) are scanned for pointers. If a pointer points to the start of a block, the block is set to Reached state; if it points into a Leaked block, the block is set to Maybe Leaked state. In either case, the block's contents are also scanned for pointers. After the second phase is complete, any blocks still in Leaked state are definitely leaked.
Create a new Devel::Plumber object. Devel::Plumber uses an entirely object-oriented interface. The object can be created empty and set up later by calling the setup method, or the parameters to setup may be passed directly. See the description of setup.
Shut down the Devel::Plumber object and it's captive GDB. It's usually not necessary to call this, dropping the last reference has the same effect.
Initialise the Devel::Plumber object, and start a captive GDB session. Errors are handled using die. The available parameters are
The filename of the program's executable image, e.g. /usr/cyrus/bin/imapd. Used with GDB's file command. Required.
The filename of a core file dumped by the program. Used with GDB's core-file command. One of corefile or pid is required.
The process id of the running program. Used with GDB's attach command. One of corefile or pid is required.
Non-zero values cause a progress indicator to be emitted to stderr. Optional.
Non-zero values cause debugging messages to be emitted to stderr. Optional.
Perform the leak finding algorithm. Errors are handled using die. This can be quite slow, use the progress optional parameter to setup to give a progress indicator.
Emits a detailed human-readable leak report to stdout. The report comprises two sections, LEAKS and SUMMARY.
The LEAKS section shows each leaked or maybe-leaked block, including it's address, size, and contents. Block contents are shown as hex words, ASCII octets, and an annotation indicating whether the word is a pointer to symbol in the .data .bss or .text sections, or to a block. These annotations are often useful in working out what code allocated the block.
The SUMMARY section summarises the total number of blocks and bytes in each of the states: Free, Leaked, Maybe Leaked, and Reached.
Emits a text report showing all the heap blocks, to stdout. Useful for testing Devel::Plumber.
Get all the leaked blocks found by find_leaks(). Returns a reference to an array of hashes containing
X86 and x86-64 Linux with glibc. Devel::Plumber potentially could be ported to any platform that supports GDB, but only if the C library's heap structures could be discovered.
For GDB to be able to access internal glibc data structures, it needs debugging symbols. Most Linux distributions ship a stripped glibc but also provide a separate package containing just the debugging information, in a directory where GDB knows how to find it. That package is usually not installed by default; for Devel::Plumber to work you need to install that package. For example, on Ubuntu
ubuntu% sudo apt-get install libc6-dbg
Note that in this case you do not need to restart the program, the debug package contains no information that is used at runtime.
Greg Banks <email@example.com>
Copyright (C) 2011 by Opera Software Australia Pty Ltd
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.