菜鸟笔记
提升您的技术认知

内存泄漏检测组件 -- hook

hook malloc与free出现的问题

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
/*****************************hook******************************/
typedef void *(*malloc_t)(size_t);
malloc_t malloc_f;
typedef void (*free_t)(void *);
free_t free_f;
static int init_hook() {
    malloc_f = dlsym(RTLD_NEXT, "malloc");
    free_f = dlsym(RTLD_NEXT, "free");
}
void *malloc(size_t size) {
    printf("In malloc\n");
    return NULL;
}
void free(void *ptr) {
    printf("In free\n");
}
/***************************************************************/
int main() {
	init_hook();
    void *p1 = malloc(10);
    void *p2 = malloc(20);
    free(p1);
}

出现段错误,gdb看一看 

        printf函数底层会调用malloc函数,如果程序陷入死循环,会不停的调用malloc。我们下面就要去破坏这个递归

        让第一次进入函数的部分执行我们的流程,而递归进去的算第二次进入函数,返回即可。

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
/*****************************hook******************************/
typedef void *(*malloc_t)(size_t);
int enable_malloc_hook = 1;
malloc_t malloc_f;
typedef void (*free_t)(void *);
int enable_free_hook = 1;
free_t free_f;
static int init_hook() {
    malloc_f = dlsym(RTLD_NEXT, "malloc");
    free_f = dlsym(RTLD_NEXT, "free");
}
void *malloc(size_t size) {
    if (enable_malloc_hook) {
        enable_malloc_hook = 0;
        void *p = malloc_f(size);
        printf("malloc--->ptr:%p size:%zu\n", p, size);
        enable_malloc_hook = 1;
        return p;
    }
    else {
        return NULL;
    }
}
void free(void *ptr) {
    if (enable_free_hook) {
        enable_free_hook = 0;
        printf("free  --->ptr:%p\n", ptr);
        free_f(ptr);
        enable_free_hook = 1;
    }
    else {
        return ;
    }
}
/***************************************************************/
int main() {
	init_hook();
    void *p1 = malloc(10);
    void *p2 = malloc(20);
    free(p1);
}

builtin_return_address(N)

# 编译器提供的函数,返回第N层调用函数 

1、gcc默认不支持__builtin_return_address(LEVEL)的参数为非0。好像只支持参数为0。

2、__builtin_return_address(0)的含义是,得到当前函数返回地址,即此函数被别的函数调用,然后此函数执行完毕后,返回,所谓返回地址就是那时候的地址。

3、__builtin_return_address(1)的含义是,得到当前函数的调用者的返回地址。注意是调用者的返回地址,而不是函数起始地址。

在__builtin_return_address函数外面套了一层ConvertToVMA。目的是把返回的内存地址转换成VMA地址。

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <link.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
/*****************************hook******************************/
//
// Created by 68725 on 2022/8/13.
//
#define _GNU_SOURCE

#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <link.h>
#include <unistd.h>

typedef void *(*malloc_t)(size_t);

int enable_malloc_hook = 1;

malloc_t malloc_f;

typedef void (*free_t)(void *);

int enable_free_hook = 1;

free_t free_f;

static int init_hook() {
    malloc_f = dlsym(RTLD_NEXT, "malloc");
    free_f = dlsym(RTLD_NEXT, "free");
}

void *ConvertToVMA(void *addr) {
    Dl_info info;
    struct link_map *link_map;
    dladdr1((void *) addr, &info, (void **) &link_map, RTLD_DL_LINKMAP);
    return addr - link_map->l_addr;
}

void *malloc(size_t size) {
    if (enable_malloc_hook) {
        enable_malloc_hook = 0;
        void *p = malloc_f(size);

        void *caller = ConvertToVMA(__builtin_return_address(0));
        printf("[+%p]--->ptr:%p size:%zu\n", caller, p, size);
        char command[256];
        Dl_info info;
        dladdr(malloc, &info);
        snprintf(command, sizeof(command), "addr2line -f -e %s -a %p > ./mem/%p.mem", info.dli_fname, caller, p);
        system(command);

        enable_malloc_hook = 1;
        return p;
    }
    else {
        return malloc_f(size);
    }
}

void free(void *ptr) {
    if (enable_free_hook) {
        enable_free_hook = 0;
        void *caller = ConvertToVMA(__builtin_return_address(0));
        printf("[-%p]--->ptr:%p\n", caller, ptr);

        char buff[128] = {0};
        sprintf(buff, "./mem/%p.mem", ptr);
        if (unlink(buff) < 0) {
            printf("double kill:%p\n",ptr);
        }

        free_f(ptr);

        enable_free_hook = 1;
    }
    else {
        return free_f(ptr);
    }
}

int main() {
    init_hook();

    void *p1 = malloc(10);
    void *p2 = malloc(20);
    free(p1);
}