方法一:
该方法采用宏定义替换函数,函数的实现放在上面的原因很简单,如果把宏定义放在前面,会产生递归调用,产生错误,下面就是代码的实现,该方法的局限性,适用于单文件,往往一个工程有很多文件,采用这种方法,就必须在每个文件下复制一遍。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void *_malloc(size_t size, char *file, const char *func, int line)
{
void *p = malloc(size);
printf("[+mem : %s | %s | %d | %ld]\n", file, func, line, size);
return p;
}
void *_free(void *p, char *file,const char *func, int line)
{
free(p);
printf("[-mem : %s | %s | %d]\n", file, func, line);
}
#define malloc(size) _malloc(size, __FILE__, __FUNCTION__, __LINE__)
#define free(p) _free(p, __FILE__, __FUNCTION__, __LINE__)
int main()
{
void *p1 = malloc(10);
void *p2 = malloc(20);
free(p1);
}
下图即为运行结果,可以很明显的看出,该程序,调用了两次malloc,一次free,产生了内存泄漏。
方法二:
这段代码是用来获取原始的malloc
和free
函数的指针,并保存在全局变量malloc_f
和free_f
中。这是为了在hook函数中能够调用原始的malloc
和free
函数。
在这个代码中,通过使用dlsym()
函数来获取malloc
和free
函数的地址。dlsym()
函数是动态链接库(Dynamic Linking Library)中的一个函数,它可以根据函数名字获取函数的地址。RTLD_NEXT
是一个特殊的参数,它表示在下一个库中查找指定的函数。
关于hook,它是一种技术手段,用于在程序运行时修改或替换函数的行为。在这个例子中,通过hook技术来监测和记录程序中的内存分配和释放操作。通过在malloc
和free
函数中插入额外的代码,可以跟踪和记录每次内存分配和释放的调用栈信息,以便进行内存泄漏的分析和调试。
通过hook技术,可以在不修改原始代码的情况下,对程序的行为进行修改和监测。这在调试和性能分析等场景中非常有用。
需要注意的是,__builtin_return_address
函数是GCC编译器提供的扩展,不是C/C++标准库的一部分。因此,它可能在其他编译器中不可用。如果需要在其他编译器中获取返回地址,可能需要使用平台特定的方法或API。
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef void *(*malloc_t)(size_t size);
malloc_t malloc_f = NULL;
typedef void (*free_t)(void *p);
free_t free_f = NULL;
int enable_malloc_hook = 1;
int enable_free_hook = 1;
void *malloc(size_t size)
{
if (enable_malloc_hook)
{
enable_malloc_hook = 0;
void *p = malloc_f(size);
void *caller = __builtin_return_address(0);
printf("malloc[+%p]\n", caller); // 在终端输入addr2line -f -e 可执行 -a +地址可以输出在哪一行
enable_malloc_hook = 1;
return p;
}
}
void free(void *p)
{
if (enable_free_hook)
{
enable_free_hook = 0;
void *caller = __builtin_return_address(0);
printf("free[-%p]\n", caller);
free_f(p);
enable_free_hook = 1;
}
else
free_f(p);
}
void init_hook(void)
{
if (malloc_f == NULL)
malloc_f = dlsym(RTLD_NEXT, "malloc");
if (free_f == NULL)
free_f = dlsym(RTLD_NEXT, "free");
}
#define DEBUG_MEM_LEAK init_hook();
int main()
{
DEBUG_MEM_LEAK
void *p1 = malloc(10);
void *p2 = malloc(20);
free(p1);
}
方法三:
最简单好用的方法,使用工具valgrind进行内存检测:
这里的编译选项加 -g 可以为Memcheck 工具定位内存问题时可以定位到 C/C++的具体的某行。