Dmalloc Logo


Search this site:

If dmalloc has saved you or your company time or money, please use your credit-card or PayPal account to donate to the cause.

Dmalloc Tutorial: 3.9 Using Dmalloc With a Debugger
[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.9 Using Dmalloc With a Debugger

Here are a number of possible scenarios for using the dmalloc library to track down problems with your program.

You should first enable a logfile filename and turn on a set of debug features. You can use dmalloc -l logfile low to accomplish this. If you are interested in having the error messages printed to your terminal as well, enable the print-messages token by typing dmalloc -p print-messages afterwards. See section Dmalloc Utility Program.

Now you can enter your debugger (I use the excellent GNU debugger gdb), and put a break-point in dmalloc_error() which is the internal error routine for the library. When your program is run, it will stop there if a memory problem is detected.

If you are using GDB, I would recommend adding the contents of `dmalloc.gdb' in the `contrib' subdirectory to your `.gdbinit' file in your home directory. This enables the dmalloc command which will prompt you for the arguments to the dmalloc command and will set a break point in dmalloc_error() automatically.

If you are using shared libraries, you may want to execute the following commands initially to load in dmalloc and other library symbols:

(gdb) sharedlibrary
(gdb) add-shared-symbol-files

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.9.1 Diagnosing General Problems with a Debugger

If your program stops at the dmalloc_error() routine then one of a number of problems could be happening. Incorrect arguments could have been passed to a malloc call: asking for negative number of bytes, trying to realloc a non-heap pointer, etc.. There also could be a problem with the system's allocations: you've run out of memory, some other function in your program is using the heap allocation functions mmap or sbrk, etc.. However, it is most likely that some code that has been executed was naughty.

To get more information about the problem, first print via the debugger the dmalloc_errno variable to get the library's internal error code. You can suspend your debugger and run dmalloc -e value-returned-from-print to get an English translation of the error. A number of the error messages are designed to indicate specific problems with the library administrative structures and may not be user-friendly.

If the problem was due to the arguments or system allocations then the source of the problem has been found. However, if some code did something wrong, you may have some more work to do to locate the actual problem. The check-heap token should be enabled and the interval setting disabled or set to a low value so that the library can find the problem as close as possible to its source. The code that was execute right before the library halted, can then be examined closely for irregularities. See section Description of the Debugging Tokens, See section Dmalloc Utility Program.

You may also want to put calls to dmalloc_verify(0) in your code before the section which generated the error. This should locate the problem faster by checking the library's structures at that point. See section Additional Non-standard Routines.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.9.2 Tracking Down Non-Freed Memory

So you've run your program, examined the log-file and discovered (to your horror) some un-freed memory. Memory leaks can become large problems since even the smallest and most insignificant leak can starve the program given the right circumstances.

not freed: '0x45008' (12 bytes) from 'ra=0x1f8f4'
not freed: '0x45028' (12 bytes) from 'unknown'
not freed: '0x45048' (10 bytes) from 'argv.c:1077'
  known memory not freed: 1 pointer, 10 bytes
unknown memory not freed: 2 pointers, 24 bytes

Above you will see a sample of some non-freed memory messages from the logfile. In the first line the `0x45008' is the pointer that was not freed, the `12 bytes' is the size of the unfreed block, and the `ra=0x1f8f4' or return-address shows where the allocation originated from. See section Translating Return Addresses into Code Locations.

The systems which cannot provide return-address information show `unknown' instead, as in the 2nd line in the sample above.

The `argv.c:1077' information from the 3rd line shows the file and line number which allocated the memory which was not freed. This information comes from the calls from C files which included `dmalloc.h'. See section Macros Providing File and Line Information.

At the bottom of the sample it totals the memory for you and breaks it down to known memory (those calls which supplied the file/line information) and unknown (the rest).

Often, you may allocate memory in via strdup() or another routine, so the logfile listing where in the strdup routine the memory was allocated does not help locate the true source of the memory leak - the routine that called strdup. Without a mechanism to trace the calling stack, there is no way for the library to see who the caller of the caller (so to speak) was.

However, there is a way to track down unfreed memory in this circumstance. You need to compile the library with STORE_SEEN_COUNT defined in `conf.h'. The library will then record how many times a pointer has been allocated or freed. It will display the unfreed memory as:

not freed: '0x45008|s3' (12 bytes) from 'ra=0x1f8f4'

The STORE_SEEN_COUNT option adds a `|s#' qualifier to the address. This means that the address in question was seen `#' many times. In the above example, the address `0x45008' was seen `3' times. The last time it was allocated, it was not freed.

How can a pointer be "seen" 3 times? Let say you strdup a string of 12 characters and get address `0x45008' - this is #1 time the pointer is seen. You then free the pointer (seen #2) but later strdup another 12 character string and it gets the `0x45008' address from the free list (seen #3).

So to find out who is allocating this particular 12 bytes the 3rd time, try dmalloc -a 0x45008:3. The library will stop the program the third time it sees the `0x45008' address. You then enter a debugger and put a break point at dmalloc_error. Run the program and when the breakpoint is reached you can examine the stack frame to determine who called strdup to allocate the pointer.

To not bother with the STORE_SEEN_COUNT feature, you can also run your program with the never-reuse token enabled. This token will cause the library to never reuse memory that has been freed. Unique addresses are always generated. This should be used with caution since it may cause your program to run out of memory.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.9.3 Diagnosing Fence-Post Overwritten Memory

For a definition of fence-posts please see the "Features" section. See section General Features of the Library.

To detect fence-post overruns, you need to enable the `check-fence' token. See section Description of the Debugging Tokens. This pads your allocations with some extra bytes at the front and the end and watches the space to make sure that they don't get overwritten. NOTE: The library cannot detect if this space gets read, only written.

If you have encountered a fence-post memory error, the logfile should be able to tell you the offending address.

free: failed UNDER picket-fence magic-number checking: 
pointer '0x1d008' from 'dmalloc_t.c:427'
Dump of proper fence-bottom bytes: '\e\253\300\300\e\253\300\300'
Dump of '0x1d008'-8: '\e\253\300\300WOW!\003\001pforger\023\001\123'

The above sample shows that the pointer `0x1d008' has had its lower fence-post area overwritten. This means that the code wrote below the bottom of the address or above the address right below this one. In the sample, the string that did it was `WOW!'.

The library first shows you what the proper fence-post information should look like, and then shows what the pointer's bad information was. If it cannot print the character, it will display the value as `\ddd' where ddd are three octal digits.

By enabling the check-heap debugging token and assigning the interval setting to a low number, you should be able to locate approximately when this problem happened. See section Description of the Debugging Tokens, See section Dmalloc Utility Program.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.9.4 Translating Return Addresses into Code Locations

The following gdb commands help you translate the return-addresses (ra=) entries in the logfile into locations in your code. I've provided a `' perl script in the `contrib/' directory with the dmalloc sources which seems to work well with gdb. But, if you need to do it manually, here are the commands in gdb to use.

# you may need to add the following commands to load in shared libraries
(gdb) sharedlibrary
(gdb) add-shared-symbol-files

(gdb) x 0x10234d
0x10234d <_findbuf+132>: 0x7fffceb7

(gdb) info line *(0x82cc)
Line 1092 of argv.c starts at pc 0x7540 and ends at 0x7550.

In the above example, gdb was used to find that the two non-freed memory pointers were allocated in _findbuf() and in file argv.c line 1092 respectively. The `x address' (for examine) can always be used on the return-addresses but the `info line *(address)' will only work if that file was compiled using the -g option and has not been stripped. This limitation may not be true in later versions of gdb.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Gray Watson on May, 16 2007 using texi2html 1.76.

This work is licensed by Gray Watson under the Creative Commons Attribution-Share Alike 3.0 License.
This page should be W3C Valid XHTML and should work with most browsers.