拦截malloc、free等库函数(malloc钩子)

注意,以下方法对于多线程来说不管用。如,A线程调用到malloc_hook 函数,把malloc_hook函数还原为libc malloc函数,此时B线程调用到malloc函数便是libc malloc函数,根本不会进入到我们的malloc_hook设定的my_malloc函数。因此,多线程下是不能使用此方法,需要用__wrap_malloc方式解决。


__malloc_hook是一组glibc提供的malloc调试变量中的一个,这组变量包括:

void *(*__malloc_hook)(size_t size, const void *caller);

void *(*__realloc_hook)(void *ptr, size_t size, const void *caller);

void *(*__memalign_hook)(size_t alignment, size_t size, const void *caller);

void (*__free_hook)(void *ptr, const void *caller);

void (*__malloc_initialize_hook)(void);

void (*__after_morecore_hook)(void);

何谓钩子函数,当一个函数挂载了钩子函数后,你执行这个函数时,实际执行的是钩子函数

只要你在程序中写上”__malloc_hook= my_malloc_hook;”,之后的malloc调用都会使用my_malloc_hook函数,方便易行。但是这组调试变量不是线程安全的,当你想用系统malloc的时候不得不把他们改回来,多线程调用就得上锁。

#include <stdio.h>
#include <malloc.h>

#define THREAD_AUTOLOCK

static void (*old_free)(void *ptr, const void *caller);
static void *(*old_malloc)(size_t size, const void *caller);

static void my_free(void *ptr, const void *caller);
static void *my_malloc(size_t size, const void *caller);

static void hook_back()
{
    old_malloc = __malloc_hook;
    old_free = __free_hook;
}

static void hook_init()
{
    __malloc_hook = my_malloc;
    __free_hook = my_free;
}

static void hook_restore()
{
    __malloc_hook = old_malloc;
    __free_hook = old_free;
}

static void my_free(void *ptr, const void *caller)
{
    THREAD_AUTOLOCK;
    hook_restore();// 这里必须,不然会死循环
    printf("free address: %x\n", ptr);
    free(ptr);
    hook_init();
    return;
}

static void *my_malloc(size_t size, const void *caller)
{
    THREAD_AUTOLOCK;
    void *p = NULL;
    hook_restore();// 这里必须,不然会死循环
    printf("malloc size: %d\n", size);
    p = malloc(size);
    hook_init();
    return p;
}

static void my_mempool_destroy()
{
    hook_restore();
}

static void my_mempool_init()
{
    hook_back();
    hook_init();
    atexit(my_mempool_destroy);
}

void (*__MALLOC_HOOK_VOLATILE __malloc_initialize_hook) (void) = my_mempool_init;
int main(int argc, char **argv)
{
    void *p = malloc(12);
    if (p != NULL)
        free(p);
    return 0;
}

int atexit(void(*func)(void));

    其中,atexit的参数是一个函数地址,当调用此函数时无须传递任何参数,该函数也不能返回值,atexit函数称为终止处理程序注册程序,注册完成以后,当函数终止是exit()函数会主动的调用前面注册的各个函数,但是exit函数调用这些函数的顺序于这些函数登记的顺序是相反的,我认为这实质上是参数压栈造成的,参数由于压栈顺序而先入后出。同时如果一个函数被多次登记,那么该函数也将多次的执行。
    #include<stdio.h>
    #include<stdlib.h>

    void func1(void)
    {
            printf("in func1\n");
    }

    void func2(void)
    {
            printf("in func2\n");
    }

    void func3(void)
    {
            printf("in func3\n");
    }

    int main()
    {
            atexit(func3);
            atexit(func2);
            atexit(func1);

            printf("In main\n");

            return 0;
    }

exit()和_exit()以及_Exit()函数的本质区别是是否立即进入内核,_exit()以及_Exit()函数都是在调用后立即进入内核,而不会执行一些清理处理,但是exit()则会执行一些清理处理,这也是为什么会存在atexit()函数的原因,因为exit()函数需要执行清理处理,需要执行一系列的操作,这些终止处理函数实际上就是完成各种所谓的清除操作的实际执行体。atexit函数的定义也给了程序员一种运用exit执行一些清除操作的方法,比如有一些程序需要额外的操作,具体的清除操作可以采用这种方法对特殊操作进行清除等。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章