C语言实现的内存泄漏检测代码

以下是一个用C语言实现的内存泄漏检测工具的示例代码。该工具通过LD_PRELOAD机制拦截内存管理函数,并检测目标程序的内存泄漏情况。

// leak_checker.c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <pthread.h>

#define BACKTRACE_SIZE 16

typedef struct _alloc_info {
    void *ptr;
    size_t size;
    void *stack[BACKTRACE_SIZE];
    int stack_size;
    struct _alloc_info *next;
} alloc_info;

static alloc_info *alloc_list = NULL;
static pthread_mutex_t alloc_mutex = PTHREAD_MUTEX_INITIALIZER;

static void *(*real_malloc)(size_t) = NULL;
static void (*real_free)(void *) = NULL;
static void *(*real_calloc)(size_t, size_t) = NULL;
static void *(*real_realloc)(void *, size_t) = NULL;

__attribute__((constructor)) void init() {
    real_malloc = dlsym(RTLD_NEXT, "malloc");
    real_free = dlsym(RTLD_NEXT, "free");
    real_calloc = dlsym(RTLD_NEXT, "calloc");
    real_realloc = dlsym(RTLD_NEXT, "realloc");
    atexit(report_leaks);
}

void *malloc(size_t size) {
    void *ptr = real_malloc(size);
    if (ptr) {
        alloc_info *info = real_malloc(sizeof(alloc_info));
        info->ptr = ptr;
        info->size = size;
        info->stack_size = backtrace(info->stack, BACKTRACE_SIZE);
        pthread_mutex_lock(&alloc_mutex);
        info->next = alloc_list;
        alloc_list = info;
        pthread_mutex_unlock(&alloc_mutex);
    }
    return ptr;
}

void free(void *ptr) {
    if (ptr) {
        pthread_mutex_lock(&alloc_mutex);
        alloc_info **p = &alloc_list;
        while (*p) {
            if ((*p)->ptr == ptr) {
                alloc_info *found = *p;
                *p = found->next;
                real_free(found);
                break;
            }
            p = &(*p)->next;
        }
        pthread_mutex_unlock(&alloc_mutex);
        real_free(ptr);
    }
}

void *calloc(size_t nmemb, size_t size) {
    void *ptr = real_calloc(nmemb, size);
    if (ptr) {
        alloc_info *info = real_malloc(sizeof(alloc_info));
        info->ptr = ptr;
        info->size = nmemb * size;
        info->stack_size = backtrace(info->stack, BACKTRACE_SIZE);
        pthread_mutex_lock(&alloc_mutex);
        info->next = alloc_list;
        alloc_list = info;
        pthread_mutex_unlock(&alloc_mutex);
    }
    return ptr;
}

void *realloc(void *ptr, size_t size) {
    if (ptr == NULL) {
        return malloc(size);
    }

    void *new_ptr = real_realloc(ptr, size);
    if (new_ptr) {
        pthread_mutex_lock(&alloc_mutex);
        alloc_info **p = &alloc_list;
        while (*p) {
            if ((*p)->ptr == ptr) {
                alloc_info *found = *p;
                *p = found->next;
                real_free(found);
                break;
            }
            p = &(*p)->next;
        }
        pthread_mutex_unlock(&alloc_mutex);

        alloc_info *info = real_malloc(sizeof(alloc_info));
        info->ptr = new_ptr;
        info->size = size;
        info->stack_size = backtrace(info->stack, BACKTRACE_SIZE);
        pthread_mutex_lock(&alloc_mutex);
        info->next = alloc_list;
        alloc_list = info;
        pthread_mutex_unlock(&alloc_mutex);
    }
    return new_ptr;
}

void report_leaks() {
    pthread_mutex_lock(&alloc_mutex);
    alloc_info *current = alloc_list;
    if (current) {
        fprintf(stderr, "\n=== Memory leak detected ===\n");
        while (current) {
            fprintf(stderr, "Leaked %zu bytes at %p\n", current->size, current->ptr);
            char **symbols = backtrace_symbols(current->stack, current->stack_size);
            if (symbols) {
                for (int i = 0; i < current->stack_size; i++) {
                    fprintf(stderr, "%s\n", symbols[i]);
                }
                real_free(symbols);
            }
            alloc_info *next = current->next;
            real_free(current);
            current = next;
        }
        fprintf(stderr, "============================\n");
    }
    pthread_mutex_unlock(&alloc_mutex);
}

编译和使用说明:

  1. 编译共享库:

    使用以下命令将上述代码编译为共享库:

    gcc -shared -fPIC -o leak_checker.so leak_checker.c -ldl -lpthread
  2. 测试程序示例:

    创建一个有内存泄漏的测试程序 test.c

    // test.c
    #include <stdlib.h>
    
    int main() {
        malloc(100); // 未释放的内存
        return 0;
    }

    编译测试程序:

    gcc test.c -o test -g -rdynamic

    -g 选项生成调试信息,-rdynamic 选项确保能正确解析函数名。

  3. 运行检测:

    使用 LD_PRELOAD 加载共享库运行测试程序:

    LD_PRELOAD=./leak_checker.so ./test

    程序运行结束后,会输出内存泄漏信息,包括泄漏的内存大小和调用堆栈。

注意事项:

  • 该工具适用于Linux环境,并依赖glibc

  • 需要目标程序动态链接C库(大部分程序默认如此)。

  • 目标程序编译时应包含调试信息(-g)和符号导出(-rdynamic),以便正确显示堆栈信息。

  • 该工具会拦截所有内存操作,可能对程序性能有一定影响。

这个实现通过拦截内存管理函数来跟踪内存分配和释放,程序退出时报告未释放的内存块及其调用堆栈,帮助开发者定位内存泄漏问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值