Tracing Memory Leak in C/C++ Using Mtrace

Aim
The aim of this tutorial is to show how you how to trace a memory leak in a C/C++ program using mcheck. This allows you to match your malloc, realloc, calloc etc to your frees. Mtrace functionality is available with the gnu C/C++ dev packages.

Let us take a look at the sample program below. Let's call this file leaker.c
 1. #include <stdlib.h>
 2. 
 3. #include <mcheck.h>
 4. 
 5. 
 6. int main(int argv, char** argc){
 7.         mtrace();
 8.         char * c1 = malloc(10*sizeof(char));
 9.         char * c2 = malloc(10*sizeof(char));
10. 
11.         c1[2]='a';
12.         c2[2]='b';
13. 
14.         free(c2);
15. 
16.         muntrace();
17. }
Hide line numbers

Line 3 You need to include the mcheck.h header file

Line 7 call mtrace() to start the tracing.

Line 16 call muntrace to stop the tracing.

As you can see this program has a blatant memory leak, in that we are not freeing pointer C2. Next we have to compile the program with the -g switch so that we can find out at which line the leak is occurring.


gcc -g leaker.c

This will create the default a.out executable. Before we run the program we need to set an environment variable called MALLOC_TRACE. This will contain the location of the tracefile to be created by mtrace/mcheck. The example below is for the bash shell.


>MALLOC_TRACE=/home/righteous/mt.txt

Now we run the program. Once the program has run it's course you can take a look at the trace file that it has created.

>./a.out
>
>cat mt.txt
= Start
@ ./a.out:[0x8048456] + 0x8968378 0xa
@ ./a.out:[0x8048465] + 0x8968388 0xa
@ ./a.out:[0x8048485] - 0x8968388
= End

To make sense of this file we need another command called mtrace. This is a perl script. This may or may not be available in your environment. You can search for the script and download it.
Now we run the script and you will see details of the memory leak below.

>mtrace a.out mt.txt

Memory not freed:
-----------------
Address Size Caller
0x08968378 0xa at /home/test.c:8 ??:0


Things get a lot trickier in an environment where you are forking process. For instance if you allocate memory, fork and then delete the memory in the child process, this will be flagged as an error as the child never actually allocated the memory. Also if you start mtrace after you have allocated memory or call muntrace before you have freed all your memory, mtrace will highlight these as errors.

No comments: