一 、 日志记录
通过宏定义重载了 malloc
和 free
函数,以在分配和释放内存的时候记录一些信息,包括文件名和行号,并将这些信息写入到相应的文件中。然后在 main
函数中演示了使用这些宏进行内存分配和释放。
-
_malloc
函数:- 在分配内存之后,创建一个文件名,其中包含了分配的内存地址(以16进制表示)。
- 打开这个文件并写入一些信息,包括源文件名、行号、分配的内存地址和大小。
- 关闭文件并返回分配的内存地址。
-
_free
函数:- 根据释放的内存地址创建相应的文件名。
- 尝试删除这个文件,如果删除成功则表示释放成功,否则可能是发生了双重释放(double free)。
- 调用标准库的
free
函数释放内存。
-
malloc
宏和free
宏:- 利用宏定义将
malloc
和free
分别重命名为_malloc
和_free
,并且在这两个宏中传递__FILE__
和__LINE__
,使得每次分配和释放内存都可以记录相应的文件名和行号。
- 利用宏定义将
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#if 0
void *_malloc(size_t size, const char *file, int line) {
void *p = malloc(size);
char buff[128] = {0};
sprintf(buff, "./mem/%p.mem", p);
FILE *fp = fopen(buff, "w");
fprintf(fp, "[+%s:%d] --> addr:%p, size:%ld\n", file, line, p, size);
fflush(fp);
fclose(fp);
return p;
}
void _free(void *p, const char *file, int line) {
char buff[128] = {0};
sprintf(buff, "./mem/%p.mem", p);
if (unlink(buff) < 0) { // double free
printf("double free: %p\n", p);
return ;
}
free(p);
}
#define malloc(size) _malloc(size, __FILE__, __LINE__)
#define free(p) _free(p, __FILE__, __LINE__)
#endif
int main() {
// DEBUG_MEM_LEAK
void *p1 = malloc(10);
void *p2 = malloc(20);
free(p1);
}
二、 日志记录2
这段代码使用了动态链接库劫持的方法,通过重载 malloc
和 free
函数,实现了在内存分配和释放时记录信息的功能。以下是代码的解释:
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;
// main --> f --> func --> malloc();
void *malloc(size_t size) {
if (enable_malloc_hook) {
enable_malloc_hook = 0;
//
void *p = malloc_f(size);
void *caller = __builtin_return_address(0);
char buff[128] = {0};
sprintf(buff, "./mem/%p.mem", p);
FILE *fp = fopen(buff, "w");
fprintf(fp, "[+%p] --> addr:%p, size:%ld\n", caller, p, size);
fflush(fp);
enable_malloc_hook = 1;
return p;
} else {
return malloc_f(size);
}
}
void free(void *p) {
if (enable_free_hook) {
char buff[128] = {0};
sprintf(buff, "./mem/%p.mem", p);
if (unlink(buff) < 0) { // double free
printf("double free: %p\n", p);
return ;
}
free_f(p);
} else {
free_f(p);
}
}
//hook
//dlsym
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);
}
三、bpftrace
创建mem.bt文件
uprobe挂在的事件和点,然后过滤当前进程等于memleak
这个脚本的目的是监测在进程名为 "memleak" 的情况下,libc 库中的 malloc
和 free
函数的调用,并在每次调用时输出相应的信息。请确保你的系统支持 BPF 功能,并且相关的 uprobes 事件能够被监测。此外,记得在 bpftrace
执行时使用 sudo
权限,因为 uprobes 需要 root 权限。
uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc
/comm == "memleak"/
{
printf("malloc\n");
}
uprobe:/lib/x86_64-linux-gnu/libc.so.6:free
/comm == "memleak"/
{
printf("free\n");
}