7.5. Memory-Debugging Tools
Several open-source and commercially sold memory-debugging tools are available on the Linux platform. Some may perform only one specific memory-debugging task but do it very well. An example is Electric Fence, which was created for the purpose of detecting memory overruns and underruns. Some tools are also available to detect memory leaks. Although most of these tools can be used in a multithreaded environment, some may not support it, so be sure to check which one is more suited to your application environment. For further information about how to use these tools, refer to Linux Programming by Example (Pearson Education, 2004) and Linux Application Development, 2nd Edition (Pearson Education, 2005).
7.5.1. Electric Fence
Available from http://directory.fsf.org/devel/debug/ElectricFence.html, Electric Fence is a memory-debugging tool used in applications suspected of overrunning or underrunning the boundaries of the malloced buffer. Electric Fence arranges application malloced memory to be followed or preceded by protected memory using the mmap routine. When an application accesses the protected memory, it gets an immediate segmentation fault, stopping the application at the point where it produces a core file. If it's running within a debugger, it stops at the faulting instruction.
Example 7-5 shows how to use Electric Fence given the example program.
Example 7-5. Listing of overrun.c
Compile the program:
$ gcc overrun.c -o overrun -L. -lefence -lpthread g $ gdb overrun (gdb) run Starting program: /home/avm/book/memory/electric-fence-2.1.13/overrun [Thread debugging using libthread_db enabled] [New Thread 4160589856 (LWP 12059)] Electric Fence 2.1 Copyright (C) 1987-1998 Bruce Perens. Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 4160589856 (LWP 12059)] 0x1000089c in main () at overrun.c:11 11 p = 'x';
In the example, the program was linked to the Electric Fence static library. When an overrun was detected, the electric fence library, through its use of page-protected boundaries, forced the program to segment fault. This produces the exact place of the offending memory operation.
In addition to monitoring for memory overruns and underruns, Electric Fence detects any access to memory that has already been freed.
7.5.2. GNU/Linux mtrace, mcheck, MALLOC_CHECK
mtrace is a GNU glibc feature that can help in debugging memory-related problems such as memory leaks and freeing unallocated memory. glibc exports the APIs mtrace() and muntrace(), which can be called within the application to turn on and turn off memory checking, respectively. When the mTRace function is called, it looks for an environment variable named MALLOC_CHECK, which contains a valid filename. The filename is used to log information about calls to malloc, free, and realloc, which can later be parsed and analyzed with a Perl script named mtrace.
Example 7-6 shows how to use mTRace.
Example 7-6. Listing of leak.c
$ gcc leak.c o leak g D_DEBUG $ export MALLOC_TRACE=log.txt $ ./leak $ cat log.txt = Start @ ./leak:[0x804841b] + 0x804a378 0x4 = End $ mtrace ./leak log.txt Memory not freed: ----------------- Address Size Caller 0x0804a378 0x4 at /tmp/leak.c:15
You can find more information about how to use mtrace within an application in the glibc manual at www.gnu.org/software/libc/manual.
The source for mpatrol is available for download at http://sourceforge.net/projects/mpatrol/. mpatrol is a memory-debugging tool in the form of a link library that helps diagnose runtime application errors caused by the improper use of dynamically allocated memory. mpatrol can detect application programming errors such as memory leaks and writing to free memory. The documentation from mpatrol mentions as one of its features the ability to produce memory allocation profiling information, which can be useful to learn how memory is used by a given application.
After you link the program from Example 7-6 with the mpatrol debug library, you should set the MPATROL_OPTIONS environment variable to the desired debugging action:
$ gcc leak.c o leak g lmpatrol lbfd $ export MPATROL_OPTIONS="LOGALL USEDEBUG" $ ./leak $ cat mpatrol.log . . . ALLOC: malloc (127, 4 bytes, 4 bytes) [main|/tmp/leak.c|15] 0x0804854B main+31 at /tmp/leak.c:15 0x40102500 __libc_start_main+224 0x08048491 _start+33 at ../sysdeps/i386/elf/start.S:102 ...
In the preceding example, the options LOGALL and USEDEBUG were used to log memory allocations and display line number information where memory was allocated. Note that the test program was also linked with libbfd.so, because mpatrol requires symbols from libbfd.
Like Electric Fence and mpatrol, dmalloc is another memory-debugging tool that is freely distributed as open source. You can download the dmalloc source code from http://dmalloc.com/. You can use the dmalloc library to track memory leaks and fence-post write detections, as well as write detailed reports that contain file and line numbers of routines that use malloc, calloc, realloc, free, and other memory management routines.
dmalloc debugging features are set with an environment variable that controls the type of memory allocation to be monitored. The level of logging can also be controlled. dmalloc generates the values that can be used to set the environment variable:
$ gcc leak.c o leak g L. -ldmalloc $ ./dmalloc high -l logfile DMALLOC_OPTIONS=debug=0x4f4ed03, log=logfile export DMALLOC_OPTIONS
In the preceding example, the output from dmalloc can be placed in a shell startup script that sets the variable DMALLOC_OPTIONS. Once set, the application that was linked with the dmalloc library can then be run. The output is written to a file named logfile.
The following logfile output shows unfreed memory when the program was run with dmalloc:
$ DMALLOC_OPTIONS=debug=0x4f4ed03, log=logfile $ export DMALLOC_OPTIONS $ ./leak $ cat logfile . . . 1126108168: 1: Dumping Not-Freed Pointers Changed Since Start: 1126108168: 1: not freed: '0xf7ffeff8|s1' (4 bytes) from 'leak.c:15' ...
valgrind is a memory-debugging tool available from http://valgrind.org. valgrind is free and is open-sourced under the GNU GPL. valgrind offers one big advantage over other freely available memory-debugging tools. Whereas other memory-debugging tools require the developer to compile and link the tool library with the program application, valgrind allows debugging to happen without the need to compile and link a debug library within the application. valgrind "wraps" the application to be debugged and applies one of the error-detection tools to do its core tasks. The tool represents the type and level of debugging tasks that need to be done. valgrind can report on memory allocation usage, heap usage, race condition errors that may exist in multithreaded applications, and on L1 and L2 cache misses.
Using valgrind on the sample program in Example 7-6 yields the following results:
$ gcc leak.c o leak -g $ valgrind -v --leak-check=full ./leak . . . output . . . ==25923== ==25923== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==25923== at 0xFFB9794: malloc (vg_replace_malloc.c:130) ==25923== by 0x10000430: main (leak.c:15) ==25923== ==25923== LEAK SUMMARY: ==25923== definitely lost: 4 bytes in 1 blocks. ==25923== possibly lost: 0 bytes in 0 blocks. ==25923== still reachable: 0 bytes in 0 blocks. ... output ...
valgrind found allocated memory on line 15 of Example 7-6 that was not freed after the program exited. Note that the program was compiled with the g option to allow valgrind to get the proper symbols and addresses within the executable. Also note that there was no need to link any extra libraries with the sample program.
7.5.6. Rational Purify
Rational Purify for Linux is commercially available from IBM. Rational Purify detects memory errors such as memory leaks and invalid memory access. Whereas other memory-debugging tools work only with C and C++ programs, Rational Purify also works with applications written in Java. Rational Purify helps detect Java garbage collection issues that may result in memory being held by object references that are no longer needed or other memory issues that can come from the JDK or third-party libraries. When used together with another product called Rational Quantify, it is possible to get accurate profile data that can be used to find performance bottlenecks. Both Rational Purify and Rational Quantify use patented Object Code Insertion (OCI) technology to instrument C/C++ programs that check for logic errors as well as create profiling data. You can find more information about Rational Purify at www.ibm.com/software/awdtools/purifyplus/unix.
Insure++ is a commercially available memory-debugging tool from www.parasoft.com. It offers support for Linux running on x86 platforms as well as the POWER (ppc) platform from IBM. Insure++ achieves detailed code coverage when it is used to compile and link application source code. The tool generates instrumented object files that are then passed to the actual compiler, producing instrumented application code. Insure++ detects memory corruption, memory leaks, memory allocation errors, variable initialization errors, variable definition conflicts, pointer errors, library errors, I/O errors, and logic errors.