Switch to full style
For C/C++ coders discussions and solutions
Post a reply

Memory leak detection in C++

Sat Nov 08, 2008 11:34 pm

Memory leakage has always been a part of bugs in C code where a programmer allocates memory in run time (in heap) and fails to deallocate it. Most programmers use some third party software to detect memory leakage in their code, but we can also write very simple code to detect memory leakage in our program ourselves. Usually we allocate memory in C using malloc() and calloc() in run time and then we deallocate the reserved memory using free(). Sometimes we do not free the reserved memory, though, which causes memory leakage. The method below is a very simple one that helps to detect memory leakage in your program.
Using the code

Let's assume that you have allocated some memory in your code using malloc() and calloc() and haven't deallocated it. Let's say your code looks something like below:

cpp code
test.c

#include<malloc.h>

int main()
{
char * ptr1 = (char *) malloc (10);
// allocating 10 bytes


int * ptr2 = (int *) calloc (10, sizeof(int));
// allocating 40 bytes let sizeof int = 4 bytes)


float * ptr3 = (float *) calloc (15, sizeof(float));
// allocating 60 bytes


............
............
............

free(ptr2);
return 0;
}

Steps for detecting memory leakage:

I have tested the code in a Linux machine using GCC. You can test the same code in Windows, as well.
Step 1

To test for a memory leak, just add the leak_detector_c.h file to the test file and then add one line to the start of main function. Now the test code should look like below:

cpp code
test.c

#include<malloc.h>

#include "leak_detector_c.h"


int main()
{
char * ptr1;
int * ptr2;
float * ptr3;

atexit(report_mem_leak);

ptr1 = (char *) malloc (10);
// allocating 10 bytes


ptr2 = (int *) calloc (10, sizeof(int));
// allocating 40 bytes let sizeof int = 4 bytes)


ptr3 = (float *) calloc (15, sizeof(float));
// allocating 60 bytes


............
............
............

free(ptr2);
return 0;
}


Step 2

Now compile the code and run the program:
Code:

# gcc -c leak_detector_.c
# gcc -c test.c
# gcc -o memtest leak_detctor_c.o test.o
# ./memtest
# cat /home/leak_info.txt


You will get output like below:


Memory Leak Summary
Code:
-----------------------------------
address : 140668936
size    : 10 bytes
file    : test.c
line    : 5
-----------------------------------
address : 140669560
size    : 60 bytes
file    : test.c
line    : 7
-----------------------------------

The output shows the file name and line number that causes the memory leak. Now you can free the unallocated memory. If you have multiple source files, you can add the header file in all of the files where you want to detect possible memory leaks. Compile the program as above. Next, let's have a look into the code and see how it works.

The leak_detctor_c.h file contains some macros. The preprocessor replaces the call of malloc(), calloc() and free() functions with xmalloc(), xcalloc() and xfree() respectively. While calling malloc(), our xmalloc() is called. We keep all information of the allocated memory -- such as the address, size, file name and line number -- in a linked list. When the code calls the free() function, it actually calls our xfree() and we manage to do the cleanup task. That is, we remove the entry of the allocated memory from the list and free up the allocated memory.

At the end of the program, we can get the unallocated memory references from the list. The line atexit(report_mem_leak) registers the report_mem_leak() function to be called at the end of the program. This function writes the memory leak summary into the leak_info.txt file. You can also use #pragma exit directive instead of atexit().

Code sample
cpp code
//leak_detector_c.c
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "leak_detector_c.h"

#undef malloc
#undef calloc
#undef free


static MEM_LEAK * ptr_start = NULL;
static MEM_LEAK * ptr_next = NULL;

/*
* adds allocated memory info. into the list
*
*/
void add(MEM_INFO alloc_info)
{

MEM_LEAK * mem_leak_info = NULL;
mem_leak_info = (MEM_LEAK *) malloc (sizeof(MEM_LEAK));
mem_leak_info->mem_info.address = alloc_info.address;
mem_leak_info->mem_info.size = alloc_info.size;
strcpy(mem_leak_info->mem_info.file_name, alloc_info.file_name);
mem_leak_info->mem_info.line = alloc_info.line;
mem_leak_info->next = NULL;

if (ptr_start == NULL)
{
ptr_start = mem_leak_info;
ptr_next = ptr_start;
}
else {
ptr_next->next = mem_leak_info;
ptr_next = ptr_next->next;
}

}

/*
* erases memory info. from the list
*
*/
void erase(unsigned pos)
{

unsigned index = 0;
MEM_LEAK * alloc_info, * temp;

if(pos == 0)
{
MEM_LEAK * temp = ptr_start;
ptr_start = ptr_start->next;
free(temp);
}
else
{
for(index = 0, alloc_info = ptr_start; index < pos;
alloc_info = alloc_info->next, ++index)
{
if(pos == index + 1)
{
temp = alloc_info->next;
alloc_info->next = temp->next;
free(temp);
break;
}
}
}
}

/*
* deletes all the elements from the list
*/
void clear()
{
MEM_LEAK * temp = ptr_start;
MEM_LEAK * alloc_info = ptr_start;

while(alloc_info != NULL)
{
alloc_info = alloc_info->next;
free(temp);
temp = alloc_info;
}
}

/*
* replacement of malloc
*/
void * xmalloc (unsigned int size, const char * file, unsigned int line)
{
void * ptr = malloc (size);
if (ptr != NULL)
{
add_mem_info(ptr, size, file, line);
}
return ptr;
}

/*
* replacement of calloc
*/
void * xcalloc (unsigned int elements, unsigned int size, const char * file, unsigned int line)
{
unsigned total_size;
void * ptr = calloc(elements , size);
if(ptr != NULL)
{
total_size = elements * size;
add_mem_info (ptr, total_size, file, line);
}
return ptr;
}


/*
* replacement of free
*/
void xfree(void * mem_ref)
{
remove_mem_info(mem_ref);
free(mem_ref);
}

/*
* gets the allocated memory info and adds it to a list
*
*/
void add_mem_info (void * mem_ref, unsigned int size, const char * file, unsigned int line)
{
MEM_INFO mem_alloc_info;

/* fill up the structure with all info */
memset( &mem_alloc_info, 0, sizeof ( mem_alloc_info ) );
mem_alloc_info.address = mem_ref;
mem_alloc_info.size = size;
strncpy(mem_alloc_info.file_name, file, FILE_NAME_LENGTH);
mem_alloc_info.line = line;

/* add the above info to a list */
add(mem_alloc_info);
}

/*
* if the allocated memory info is part of the list, removes it
*
*/
void remove_mem_info (void * mem_ref)
{
unsigned short index;
MEM_LEAK * leak_info = ptr_start;

/* check if allocate memory is in our list */
for(index = 0; leak_info != NULL; ++index, leak_info = leak_info->next)
{
if ( leak_info->mem_info.address == mem_ref )
{
erase ( index );
break;
}
}
}

/*
* writes all info of the unallocated memory into a file
*/
void report_mem_leak(void)
{
unsigned short index;
MEM_LEAK * leak_info;

FILE * fp_write = fopen (OUTPUT_FILE, "wt");
char info[1024];

if(fp_write != NULL)
{
sprintf(info, "%s\n", "Memory Leak Summary");
fwrite(info, (strlen(info) + 1) , 1, fp_write);
sprintf(info, "%s\n", "-----------------------------------");
fwrite(info, (strlen(info) + 1) , 1, fp_write);

for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next)
{
sprintf(info, "address : %d\n", leak_info->mem_info.address);
fwrite(info, (strlen(info) + 1) , 1, fp_write);
sprintf(info, "size : %d bytes\n", leak_info->mem_info.size);
fwrite(info, (strlen(info) + 1) , 1, fp_write);
sprintf(info, "file : %s\n", leak_info->mem_info.file_name);
fwrite(info, (strlen(info) + 1) , 1, fp_write);
sprintf(info, "line : %d\n", leak_info->mem_info.line);
fwrite(info, (strlen(info) + 1) , 1, fp_write);
sprintf(info, "%s\n", "-----------------------------------");
fwrite(info, (strlen(info) + 1) , 1, fp_write);
}
}
clear();
}



Attachments
leak_detector_c_src.zip
(2.27 KiB) Downloaded 1682 times

Re: Memory leak detection in C++

Fri Jan 29, 2010 10:48 am

I want to add certain point.Any suggestions are welcomed.
If our program can exit from multiple locations, instead of putting a call to _CrtDumpMemoryLeaks at each possible exit,include the following call at the beginning of program:
Code:
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);


This statement automatically calls _CrtDumpMemoryLeaks when program exits.

2 . The macro _CRTDBG_MAP_ALLOC applies to c library functions malloc, realloc.With a little bit of extra code, we can get it to work with new/delete:

cpp code
#define _CRTDBG_MAP_ALLOC

#include <iostream>
#include <crtdbg.h>

#ifdef _DEBUG
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif

These macros should be added after including all other header files.

3. By default, _CrtDumpMemoryLeaks dumps memory leak information to the Output window,we can reset this to a file using _CrtSetReportMode. For doing this add the following lines of code at the starting of your program.
cpp code
HANDLE hLogFile;
hLogFile = CreateFileA("c:\\memoryLeaksDump.rtf", GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL);

_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, hLogFile);
_CrtSetReportFile(_CRT_ERROR, hLogFile);
_CrtSetReportFile(_CRT_ASSERT, hLogFile);

_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF)


Post a reply
  Related Posts  to : Memory leak detection in C++
 GDI memory leaks detection     -  
 C++ & Java memory management!!     -  
 MATLAB clear memory     -  
 problem with memory alocation     -  
 subtract number from memory locations     -  
 Latest XML parsing/memory usage benchmark     -  
 object detection     -  
 edge detection     -  
 need help about object detection using haarTraining     -  
 Edge Detection In Java     -  

Topic Tags

C++ Basics