commit 06c458e859081625bc5618a44eed4a167508eec2 Author: aixiao Date: Wed Apr 23 16:07:47 2025 +0800 init diff --git a/a.out b/a.out new file mode 100644 index 0000000..d75b7cf Binary files /dev/null and b/a.out differ diff --git a/leak_detector_c.c b/leak_detector_c.c new file mode 100644 index 0000000..a87bce6 --- /dev/null +++ b/leak_detector_c.c @@ -0,0 +1,194 @@ +#include +#include +#include +#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"); + } +} diff --git a/leak_detector_c.h b/leak_detector_c.h new file mode 100644 index 0000000..6ad3d65 --- /dev/null +++ b/leak_detector_c.h @@ -0,0 +1,61 @@ +#ifndef LEAK_DETECTOR_C_H +#define LEAK_DETECTOR_C_H + +// 文件名最大长度 +#define FILE_NAME_LENGTH 256 + +// 内存泄漏信息输出文件 +#define OUTPUT_FILE "leak_info.txt" + +// 用宏重定义 malloc、calloc 和 free,为其添加文件名和行号信息 +#define malloc(size) xmalloc (size, __FILE__, __LINE__) +#define calloc(elements, size) xcalloc (elements, size, __FILE__, __LINE__) +#define free(mem_ref) xfree(mem_ref) + +// 用于记录每一次内存分配的信息结构体 +struct _MEM_INFO { + void *address; // 分配的内存地址 + unsigned int size; // 分配的大小 + char file_name[FILE_NAME_LENGTH]; // 分配发生的文件名 + unsigned int line; // 分配发生的代码行号 +}; +typedef struct _MEM_INFO MEM_INFO; + +// 内存泄漏记录结构体,使用链表形式组织 +struct _MEM_LEAK { + MEM_INFO mem_info; // 内存信息 + struct _MEM_LEAK *next; // 指向下一个节点的指针 +}; + +typedef struct _MEM_LEAK MEM_LEAK; + +// 添加一条内存分配信息记录 +void add(MEM_INFO alloc_info); + +// 删除某个位置的内存记录 +void erase(unsigned pos); + +// 清空所有内存记录 +void clear(void); + +// 自定义 malloc:记录内存分配位置 +void *xmalloc(unsigned int size, const char *file, unsigned int line); + +// 自定义 calloc:记录内存分配位置 +void *xcalloc(unsigned int elements, unsigned int size, const char *file, unsigned int line); + +// 自定义 free:在释放内存时移除记录 +void xfree(void *mem_ref); + +// 添加一条内存分配记录 +void add_mem_info(void *mem_ref, unsigned int size, const char *file, unsigned int line); + +// 移除某个内存记录(在调用 free 时使用) +void remove_mem_info(void *mem_ref); + +// 生成内存泄漏报告 +extern void report_mem_leak(void); + +extern void dump_mem_leak(void); + +#endif diff --git a/leak_info.txt b/leak_info.txt new file mode 100644 index 0000000..2196468 --- /dev/null +++ b/leak_info.txt @@ -0,0 +1,12 @@ +Memory Leak Summary +----------------------------------- +address : 0x7fffe6d502a0 +size : 1 bytes +file : test.c +line : 8 +----------------------------------- +address : 0x7fffe6d50520 +size : 60 bytes +file : test.c +line : 14 +----------------------------------- diff --git a/test.c b/test.c new file mode 100644 index 0000000..007d893 --- /dev/null +++ b/test.c @@ -0,0 +1,20 @@ +#include +#include +#include "leak_detector_c.h" +int main() +{ + atexit(report_mem_leak); + + char *ptr1 = (char *)malloc(1); + + + + + int *ptr2 = (int *)calloc(1, sizeof(int)); + float * ptr3 = (float *) calloc(15, sizeof(float)); + free(ptr2); + + dump_mem_leak(); + + return 0; +}