在学习dlsym检测内存泄漏时遇到的坑。
源代码如下:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef void *(*malloc_t)(size_t size);
typedef void (*free_t)(void *p);
malloc_t malloc_f = NULL;
free_t free_f = NULL;
int enable_malloc_hook = 1;
int enable_free_hook = 1;
void *malloc(size_t size)
{
void *p = NULL;
if(enable_malloc_hook)
{
enable_malloc_hook = 0;
p = malloc_f(size);
void *caller = __builtin_return_address(0);
char buff[128] = {0};
sprintf(buff, "./checkleak/%p.mem", p);
FILE *fp = fopen(buff, "w");
fprintf(fp, "[+]%p addr:%p, size:%ld\n", caller, p, size);
fclose(fp);
enable_malloc_hook = 1;
}
else
{
p = malloc_f(size);
}
return p;
}
void free(void *p)
{
if(enable_free_hook)
{
enable_free_hook = 0;
char buff[128] = {0};
sprintf(buff, "./checkleak/%p.mem", p);
if(unlink(buff) < 0) // file not exist; double free
{
printf("double free: %p\n", p);
return ;
}
free_f(p);
enable_free_hook = 1;
}
else
{
free_f(p);
}
}
void init_hook(void)
{
if(malloc_f == NULL)
{
malloc_f = (malloc_t)dlsym(RTLD_NEXT, "malloc");
}
if(free_f == NULL)
{
free_f = (free_t)dlsym(RTLD_NEXT, "free");
}
}
int main()
{
init_hook();
void *p1 = malloc(5);
void *p2 = malloc(10);
void *p3 = malloc(15);
free(p1);
free(p3);
return 0;
}
输出结果为:
double free: (nil)
/checkleak中的.mem文件也没有删除掉。
使用gdb进行调试
Reading symbols from /root/memleak/memleak...done.
(gdb) b 93
Breakpoint 1 at 0x400972: file memleak.c, line 93.
(gdb) r
Starting program: /root/memleak/memleak
Breakpoint 1, main () at memleak.c:93
93 void *p1 = malloc(5);
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64
(gdb) s
malloc (size=5) at memleak.c:21
21 void *p = NULL;
(gdb) s
23 if(enable_malloc_hook)
(gdb) s
25 enable_malloc_hook = 0;
(gdb) s
27 p = malloc_f(size);
(gdb) s
29 void *caller = __builtin_return_address(0);
(gdb) s
31 char buff[128] = {0};
(gdb) s
32 sprintf(buff, "./checkleak/%p.mem", p);
(gdb) s
double free: (nil)
34 FILE *fp = fopen(buff, "w");
发现在sprintf()执行之后就打印了 double free: (nil), 意识到在sprintf()底层可能使用了malloc和free。
malloc函数的enable_malloc_hook = 0,所以直接进入p = malloc_f(size);,而enable_free_hook = 1,所以会进入到if(unlink(buff) < 0)的判断中,导致程序出错。
修改方法:在malloc函数中加入对free_hook函数的控制。
void *malloc(size_t size)
{
void *p = NULL;
if(enable_malloc_hook)
{
enable_malloc_hook = 0;
enable_free_hook = 0; // ++++
p = malloc_f(size);
void *caller = __builtin_return_address(0);
char buff[128] = {0};
sprintf(buff, "./checkleak/%p.mem", p);
FILE *fp = fopen(buff, "w");
fprintf(fp, "[+]%p addr:%p, size:%ld\n", caller, p, size);
fclose(fp);
enable_malloc_hook = 1;
enable_free_hook = 1; // ++++
}
else
{
p = malloc_f(size);
}
return p;
}