leak_detector_c/leak_detector_c.c
2025-04-23 16:07:47 +08:00

195 lines
5.1 KiB
C

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "leak_detector_c.h"
// 取消宏定义,使用原始 malloc/calloc/free
#undef malloc
#undef calloc
#undef free
// 全局链表起始与当前位置指针
static MEM_LEAK *ptr_start = NULL;
static MEM_LEAK *ptr_next = NULL;
/*
* 将分配的内存信息添加到链表中
*/
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;
}
}
/*
* 根据位置索引从链表中删除内存记录
*/
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;
}
}
}
}
/*
* 清空链表中所有内存记录
*/
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;
}
}
/*
* 自定义 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;
}
/*
* 自定义 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;
}
/*
* 自定义 free 函数:释放内存前先移除记录
*/
void xfree(void *mem_ref)
{
remove_mem_info(mem_ref); // 移除记录
free(mem_ref); // 实际释放
}
/*
* 创建内存分配信息并添加到链表中
*/
void add_mem_info(void *mem_ref, unsigned int size, const char *file, unsigned int line)
{
MEM_INFO mem_alloc_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(mem_alloc_info);
}
/*
* 从链表中移除某段已释放的内存记录
*/
void remove_mem_info(void *mem_ref)
{
unsigned short index;
MEM_LEAK *leak_info = ptr_start;
// 遍历链表查找目标地址
for (index = 0; leak_info != NULL; ++index, leak_info = leak_info->next) {
if (leak_info->mem_info.address == mem_ref) {
erase(index); // 找到后删除
break;
}
}
}
/*
* 将所有未释放的内存信息写入输出文件
*/
void report_mem_leak(void)
{
MEM_LEAK *leak_info;
FILE *fp_write = fopen(OUTPUT_FILE, "wt");
if (fp_write != NULL) {
fprintf(fp_write, "Memory Leak Summary\n");
fprintf(fp_write, "-----------------------------------\n");
// 遍历所有未释放的记录,写入文件
for (leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
fprintf(fp_write, "address : %p\n", leak_info->mem_info.address);
fprintf(fp_write, "size : %d bytes\n", leak_info->mem_info.size);
fprintf(fp_write, "file : %s\n", leak_info->mem_info.file_name);
fprintf(fp_write, "line : %d\n", leak_info->mem_info.line);
fprintf(fp_write, "-----------------------------------\n");
}
fclose(fp_write); // 关闭输出文件
}
clear(); // 清空链表,释放资源
}
void dump_mem_leak(void)
{
MEM_LEAK *leak_info;
fprintf(stderr, "Memory Leak Snapshot\n");
fprintf(stderr, "-----------------------------------\n");
for (leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next) {
fprintf(stderr, "address : %p\n", leak_info->mem_info.address);
fprintf(stderr, "size : %d bytes\n", leak_info->mem_info.size);
fprintf(stderr, "file : %s\n", leak_info->mem_info.file_name);
fprintf(stderr, "line : %d\n", leak_info->mem_info.line);
fprintf(stderr, "-----------------------------------\n");
}
}