Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
July 25, 2022 05:47 pm GMT

A simple program to detect memory leak in our C program

Whenever we program in a language such as C/C++ we have to manage our memory ourselves, there is no way to free unused memory automatically as we get in other languages like Python, Java, etc.

Sometimes we write programs where we leave memory leaks, resulting in a crash of the program after some time and It is very difficult to find where the memory leak is left.

So to debug such an issue we can write a simple program to detect memory leaks in our program.

The idea here is to keep track of every allocation and check Whether it was freed during the run time of the program or not.

Let's start with a basic data structure to store memory allocation information during the execution of the program.

Data structure code

// We assume max 1000 allocations will take place #define MAX_ALLOCATIONS 1000/* Data Structure to keep track of memory allocationsaddress -> Memory address allocatedsize -> Size allocatedline -> Line number where allocation is done*/typedef struct {    size_t address;    size_t size;    uint32_t line;} Mem;/*mem -> store all the allocation in arraytotal_allocated_size -> Keep track total memory allocatedtotal_free_size -> Keep track total memory freed*/struct {    Mem mem[MAX_ALLOCATIONS];    size_t total_allocated_size;    size_t total_free_size;} data;

Now we will create some helper functions to find, insert and erase memory allocation in the data structure.

Helper functions code

/** * Find a memory by its address *  * @return: Pointer to memory*/Mem *find_by_address(size_t address) {    for (uint32_t i=0; i<MAX_ALLOCATIONS; i++) {        if (data.mem[i].address == address)            return &data.mem[i]; // as soon as find return    }    // otherwise return null    return NULL;}/** * insert memory allocated with size*/void insert(size_t address, size_t size, uint32_t line) {    // check for null    if (address == 0) {        WARN("Memory allocation failed", line);        return;    }    Mem *mem = find_by_address(0);    // if the return value is null we need to increase the MAX_ALLOCATIONS value    if (mem == NULL) {        WARN("Max allocations reached", line);        return;    }    // save all the allocation info    mem->address = address;    mem->size = size;    mem->line = line;    data.total_allocated_size += size;}/** * Remove the memory allocation *  * @return: -1 on failure else 0*/int erase(size_t address, uint32_t line) {    if (address == 0) {        WARN("Tried to free a null ptr", line);        return -1;    }    Mem *mem = find_by_address(address);    // if the address is not found we assume it is already deleted    if (mem == NULL) {        WARN("Double free detected", line);        return -1;    }    // set address to null and update info    mem->address = 0;    data.total_free_size += mem->size;    return 0;}

At the end of the program, we will print a detailed report of memory leaks.

Code

void print_report() {    printf("
Leak Summary
"); printf("Total Memory allocated %lu bytes
", data.total_allocated_size); printf("Total Memory freed %lu bytes
", data.total_free_size); printf("Memory Leaked %lu bytes

", data.total_allocated_size - data.total_free_size); if (data.total_free_size != data.total_allocated_size) { printf("Detailed Report
"); for (int i=0; i<MAX_ALLOCATIONS; i++) { if (data.mem[i].address != 0) { printf("Memory leak at line %d: (%lu bytes)
", data.mem[i].line, data.mem[i].size); } } }}

Now create default allocator intercepted functions to insert while memory allocation and erase while free.

Custom allocator functions

// Create allocator functionsvoid *_malloc(size_t size, uint32_t line) {    void *ptr = malloc(size);    // insert to memory data    insert((size_t)ptr, size, line);    return ptr;}void _free(void *ptr, uint32_t line) {    // erase memory data    if (erase((size_t)ptr, line) == 0)        free(ptr);}

Here we redefine the default allocator function such as malloc and free with our intercepted functions.

Redefine default allocator functions

// redefine allocator functions#define malloc(size) _malloc(size, __LINE__)#define free(ptr) _free(ptr, __LINE__)

That's it!

Complete Code

#include <stdio.h>#include <stdlib.h>#include <stdint.h>#define MAX_ALLOCATIONS 100#define WARN(msg, line) (printf("Warning %d: %s
", line, msg))
/* Data Structure to keep track of memory allocations*/typedef struct { size_t address; size_t size; uint32_t line;} Mem;struct { Mem mem[MAX_ALLOCATIONS]; size_t total_allocated_size; size_t total_free_size;} data;/** * Find a memory by its address * * @return: Pointer to memory*/Mem *find_by_address(size_t address) { for (uint32_t i=0; i<MAX_ALLOCATIONS; i++) { if (data.mem[i].address == address) return &data.mem[i]; // as soon as find return } // otherwise return null return NULL;}/** * insert memory allocated with size*/void insert(size_t address, size_t size, uint32_t line) { // check for null if (address == 0) { WARN("Memory allocation failed", line); return; } Mem *mem = find_by_address(0); // if the return value is null we need to increase the MAX_ALLOCATIONS value if (mem == NULL) { WARN("Max allocations reached", line); return; } // save all the allocation info mem->address = address; mem->size = size; mem->line = line; data.total_allocated_size += size;}/** * Remove the memory allocation * * @return: -1 on failure else 0*/int erase(size_t address, uint32_t line) { if (address == 0) { WARN("Tried to free a null ptr", line); return -1; } Mem *mem = find_by_address(address); // if the address is not found we assume it is already deleted if (mem == NULL) { WARN("Double free detected", line); return -1; } // set address to null and update info mem->address = 0; data.total_free_size += mem->size; return 0;}void print_report() { printf("
Leak Summary
"); printf("Total Memory allocated %lu bytes
", data.total_allocated_size); printf("Total Memory freed %lu bytes
", data.total_free_size); printf("Memory Leaked %lu bytes

", data.total_allocated_size - data.total_free_size); if (data.total_free_size != data.total_allocated_size) { printf("Detailed Report
"); for (int i=0; i<MAX_ALLOCATIONS; i++) { if (data.mem[i].address != 0) { printf("Memory leak at line %d: (%lu bytes)
", data.mem[i].line, data.mem[i].size); } } }}// Override allocation functionsvoid *_malloc(size_t size, uint32_t line) { void *ptr = malloc(size); // insert to memory data insert((size_t)ptr, size, line); return ptr;}void _free(void *ptr, uint32_t line) { // erase memory data if (erase((size_t)ptr, line) == 0) free(ptr);}// redefine allocator functions#define malloc(size) _malloc(size, __LINE__)#define free(ptr) _free(ptr, __LINE__)int main() { int *n1 = malloc(sizeof(int)); free(n1); int *n2 = NULL; free(n2); int *n3 = malloc(sizeof(int)); free(n3); free(n3); int *n4 = malloc(sizeof(int)); print_report(); return 0;}

Output

naman@namantam1:~/programs$ gcc main.c && ./a.outWarning 143: Tried to free a null ptrWarning 147: Double free detectedLeak SummaryTotal Memory allocated 12 bytesTotal Memory freed     8 bytesMemory Leaked          4 bytesDetailed ReportMemory leak at line 149: (4 bytes)

From the above output, It is clear that it detects all the memory leaks, double-free.

Note: This program will not be able to keep track of memory allocation done by inbuild or any third party library. So if we free memory allocated in library call, It will show double free, We can simply ignore them.


Original Link: https://dev.to/namantam1/a-simple-program-to-detect-memory-leak-in-our-c-program-5c5i

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To