无需工具的内存泄漏检测程序






2.96/5 (21投票s)
无需使用任何工具,此程序将查找您程序中的内存泄漏。
引言
市场上有很多用于检测内存泄漏的工具。在这里,我编写了一个程序,需要将其包含在您的源代码文件中,它将提供所需的信息来查找内存泄漏发生的位置。
有两个文件,一个是 findLeak.c,另一个是 findLeak.h。源代码文件是 test.c,这是您想要检查内存泄漏的程序。
其原理是,当用户调用库函数“malloc 或 calloc”来分配动态内存时,我们必须调用我们自己的 malloc 或 calloc(在我的源代码中,用 'MyCalloc' 函数代替 'calloc',用 'MyMalloc' 函数代替 'malloc')。因此,您需要将 malloc 定义为您的 malloc,并在 .c 文件中取消定义 malloc 和 calloc。 这样我们就可以调用我们的 MyMalloc 或 MyCalloc 函数,并在该函数中调用另一个函数,该函数保存有关已分配多少内存的所有信息。 我们对库函数“free”进行相同的操作,以释放内存(在我的源代码中,使用“MyFree”代替 free 函数)。
使用代码
现在,为了保存信息,我创建了一个简单的单链表。它将在用户调用“malloc”或“calloc”函数时添加内存信息,并在用户调用“free”函数时也保存信息。
通过程序您可以很容易地理解。
头文件:findLeak.h
#define uint unsigned int #define cchar const char #define OutFile "/home/asadulla/test/MemLeakInfo.txt" // Just Suppose #define MAX_FILENAME_LENGTH 256 #define calloc(objs, nSize) MyCalloc (objs, nSize, __FILE__, __LINE__) #define malloc(nSize) MyMalloc (nSize, __FILE__, __LINE__) #define free(rMem) MyFree(rMem) // This structure is keeping info about memory leak struct InfoMem { void *addr; uint nSize; char fileName[MAX_FILENAME_LENGTH]; uint lineNumber; }; typedef struct InfoMem infoMem; //This is link list of InfoMem which keeps a List of memory Leak in a source file struct LeakMem { infoMem memData; struct LeakMem *nxt; }; typedef struct LeakMem leakMem; void WriteMemLeak(void); void SubAddMemInfo(void *rMem, uint nSize, cchar *file, uint lno); void SubAdd(infoMem alloc_info); void ResetInfo(uint pos); //erase void DeleteAll(void); //clear(void); void *MyMalloc(uint size, cchar *file, uint line); void *MyCalloc(uint elements, uint size, cchar * file, uint lno); void MyFree(void * mem_ref);
源文件:findLeak.c
#include <stdio.h> #include <malloc.h> #include <string.h> #include "findLeak.h" #undef malloc #undef calloc #undef free static leakMem * ptr_start = NULL; static leakMem * ptr_next = NULL; // ----------------------------------------------------------- // Name: MyMalloc // Desc: This is hidden to user. when user call malloc function then // this function will be called. void *MyMalloc (uint nSize, cchar* file, uint lineNumber) { void * ptr = malloc (nSize); if (ptr != NULL) { SubAddMemInfo(ptr, nSize, file, lineNumber); } return ptr; } // ----------------------------------------------------------- // Name: MyCalloc // Desc: This is hidden to user. when user call calloc function then // this function will be called. void * MyCalloc (uint elements, uint nSize, const char * file, uint lineNumber) { uint tSize; void * ptr = calloc(elements , nSize); if(ptr != NULL) { tSize = elements * nSize; SubAddMemInfo (ptr, tSize, file, lineNumber); } return ptr; } // ----------------------------------------------------------- // Name: SubAdd // Desc: It's actually Adding the Info. void SubAdd(infoMem alloc_info) { leakMem * mem_leak_info = NULL; mem_leak_info = (leakMem *) malloc (sizeof(leakMem)); mem_leak_info->memData.addr = alloc_info.addr; mem_leak_info->memData.nSize = alloc_info.nSize; strcpy(mem_leak_info->memData.fileName, alloc_info.fileName); mem_leak_info->memData.lineNumber = alloc_info.lineNumber; mem_leak_info->nxt = NULL; if (ptr_start == NULL) { ptr_start = mem_leak_info; ptr_next = ptr_start; } else { ptr_next->nxt = mem_leak_info; ptr_next = ptr_next->nxt; } } // ----------------------------------------------------------- // Name: ResetInfo // Desc: It erasing the memory using by List on the basis of info( pos) void ResetInfo(uint pos) { uint index = 0; leakMem * alloc_info, * temp; if(pos == 0) { leakMem * temp = ptr_start; ptr_start = ptr_start->nxt; free(temp); } else { for(index = 0, alloc_info = ptr_start; index < pos; alloc_info = alloc_info->nxt, ++index) { if(pos == index + 1) { temp = alloc_info->nxt; alloc_info->nxt = temp->nxt; free(temp); break; } } } } // ----------------------------------------------------------- // Name: DeleteAll // Desc: It deletes the all elements which resides on List void DeleteAll() { leakMem * temp = ptr_start; leakMem * alloc_info = ptr_start; while(alloc_info != NULL) { alloc_info = alloc_info->nxt; free(temp); temp = alloc_info; } } // ----------------------------------------------------------- // Name: MyFree // Desc: void MyFree(void * mem_ref) { uint loop; // if the allocated memory info is part of the list, removes it leakMem *leak_info = ptr_start; /* check if allocate memory is in our list */ for(loop = 0; leak_info != NULL; ++loop, leak_info = leak_info->nxt) { if ( leak_info->memData.addr == mem_ref ) { ResetInfo(loop); break; } } free(mem_ref); } // ----------------------------------------------------------- // Name: SubAddMemInfo // Desc: it also fill the the Info void SubAddMemInfo (void * mem_ref, uint nSize, cchar * file, uint lineNumber) { infoMem AllocInfo; /* fill up the structure with all info */ memset( &AllocInfo, 0, sizeof ( AllocInfo ) ); AllocInfo.addr = mem_ref; AllocInfo.nSize = nSize; strncpy(AllocInfo.fileName, file, MAX_FILENAME_LENGTH); AllocInfo.lineNumber = lineNumber; /* SubAdd the above info to a list */ SubAdd(AllocInfo); } // ----------------------------------------------------------- // Name: WriteMemLeak // Desc: It writes information about Memory leaks in a file // Example: File is as : "/home/asadulla/test/MemLeakInfo.txt" void WriteMemLeak(void) { uint index; leakMem *leak_info; FILE * fp_write = fopen(OutFile, "wt"); char info[1024]; if(fp_write != NULL) { sprintf(info, "%s\n", "SUMMARY ABOUT MEMORY LEAKS OF YOUR SOURCE FILE "); 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->nxt) { sprintf(info, "Name of your Source File : %s\n", leak_info->memData.fileName); fwrite(info, (strlen(info) + 1) , 1, fp_write); sprintf(info, "Starting Address : %d\n", leak_info->memData.addr); fwrite(info, (strlen(info) + 1) , 1, fp_write); sprintf(info, " Total size Of memory Leak : %d bytes\n", leak_info->memData.nSize); fwrite(info, (strlen(info) + 1) , 1, fp_write); sprintf(info, "Line Number for which no DeAllocation : %d\n", leak_info->memData.lineNumber); fwrite(info, (strlen(info) + 1) , 1, fp_write); sprintf(info, "%s\n", "-----------------------------------"); fwrite(info, (strlen(info) + 1) , 1, fp_write); fwrite(info, (strlen(info) + 1) , 1, fp_write); } } DeleteAll(); }
用户必须将这两个文件(头文件和源文件)包含在他的源代码中,以查找内存泄漏。
用于检测内存泄漏的源文件如下。您可以在这里提供您自己的源代码,并且在该源代码中,您只需要写一行来包含文件:#include"findLeak.h"
测试:test.c
代码:c
#include<malloc.h> #include"findLeak.h" int main() { int *p1 = (int *)malloc(10); int *p2 = (int *)calloc(10, sizeof(int)); char *p3 = (char *) calloc(15, sizeof(float)); float *p4 = (float*) malloc(16); free(p2); WriteMemLeak(); return 0; }
现在用户可以在控制台中编译这些程序,如下所示:
> g++ test.c findLeak.c
并给出运行命令
> ./a.out
然后转到您定义了宏“OutFile”的目录,并打开该定义的 文件,您将看到结果。
以上源代码的输出如下:
代码:output
SUMMARY ABOUT MEMORY LEAKS OF YOUR SOURCE FILE ----------------------------------- Name of your Source File : test.c Starting Address : 184960 Total size Of memory Leak : 10 bytes Line Number for which no DeAllocation : 7 ----------------------------------- ----------------------------------- Name of your Source File : test.c Starting Address : 187104 Total size Of memory Leak : 60 bytes Line Number for which no DeAllocation : 9 ----------------------------------- ----------------------------------- Name of your Source File : test.c Starting Address : 184984 Total size Of memory Leak : 16 bytes Line Number for which no DeAllocation : 10 ----------------------------------- -----------------------------------现在您可以尝试创建您自己的测试用例,就像 test.c 一样。