在C中为malloc和free创建包装函数

在C中为malloc和free创建包装函数,c,memory-management,memory-leaks,malloc,C,Memory Management,Memory Leaks,Malloc,我正在尝试为C中的free和malloc创建包装函数,以帮助通知我内存泄漏。有人知道如何声明这些函数吗?因此,当我调用malloc()和free()时,它将调用我的自定义函数,而不是标准库函数?如果您为malloc()和free()定义自己的函数并将其与应用程序显式链接,您的函数应优先于库中的函数使用 但是,名为“malloc”的函数随后不能调用库malloc函数,因为在“c”中没有单独名称空间的概念。换句话说,您必须实现malloc的内部结构并释放自己 另一种方法是编写调用标准库函数的函数my

我正在尝试为C中的
free
malloc
创建包装函数,以帮助通知我内存泄漏。有人知道如何声明这些函数吗?因此,当我调用
malloc()
free()
时,它将调用我的自定义函数,而不是标准库函数?

如果您为malloc()和free()定义自己的函数并将其与应用程序显式链接,您的函数应优先于库中的函数使用

但是,名为“malloc”的函数随后不能调用库malloc函数,因为在“c”中没有单独名称空间的概念。换句话说,您必须实现malloc的内部结构并释放自己


另一种方法是编写调用标准库函数的函数my_malloc()和my_free()。这意味着任何调用malloc的代码都必须更改为调用my_xxx函数。

您有几个选项:

  • 特定于GLIBC的解决方案(主要是Linux)。如果您的编译环境是带有
    gcc
    GLIBC
    ,首选方法是使用。它不仅允许您指定自定义
    malloc
    free
    ,还可以通过堆栈上的返回地址识别调用方

  • POSIX特定解决方案。
    malloc
    free
    定义为可执行文件中原始分配例程的包装,这将“覆盖”libc中的版本。在包装器内部,您可以调用原始的
    malloc
    实现,您可以使用
    RTLD\u NEXT
    句柄查找该实现。定义包装函数的应用程序或库需要链接到
    -ldl

    #define _GNU_SOURCE
    #include <dlfcn.h>
    #include <stdio.h>
    
    void* malloc(size_t sz)
    {
        void *(*libc_malloc)(size_t) = dlsym(RTLD_NEXT, "malloc");
        printf("malloc\n");
        return libc_malloc(sz);
    }
    
    void free(void *p)
    {
        void (*libc_free)(void*) = dlsym(RTLD_NEXT, "free");
        printf("free\n");
        libc_free(p);
    }
    
    int main()
    {
        free(malloc(10));
        return 0;
    }
    
  • 特定于Mac OSX。

    与Linux相同,只是您将使用
    DYLD\u INSERT\u库
    环境变量

  • LD_PRELOAD=mymalloc.so ./exe
    

    如果您的目标是消除内存泄漏,一种更简单、侵入性更小的方法是使用(免费)或(昂贵)之类的工具。

    如果您使用的是Linux,则可以使用malloc_hook()(与GNU glibc一起使用)。此函数允许您在调用实际malloc之前让malloc调用您的函数。手册页有一个关于如何使用它的示例。

    在C中,我使用的方法类似于:

    #define malloc(x) _my_malloc(x, __FILE__, __LINE__)
    #define free(x) _my_free(x)
    
    这使我能够毫不费力地检测分配内存的行和文件。它应该是跨平台的,但如果已经定义了宏,则会遇到问题(只有在使用另一个内存泄漏检测器时才会出现这种情况)


    如果你想在C++中实现同样的过程,程序会更多,但是使用相同的技巧。 如果你只谈论你可以控制的内存,也就是说,你可以自己控制和释放内存,你可以看看。也许这就是你要写的东西,所以你可以节省一些时间。它有一个非常自由的许可证,如果这对你很重要的话


    我个人在一个项目中使用它来查找内存泄漏,好处是它比valgrind快得多,但是它没有那么强大,所以你没有得到完整的调用堆栈。

    这里有一组包装函数,我用了很多年(当我使用C时仍然如此)来检测未释放的内存,多次释放内存,对空闲内存、缓冲区溢出/下溢和释放未分配内存的引用

    他们已经存在了25年,并证明了自己

    您可以使用宏预处理器重新定义malloc并免费使用mem包,但我建议您不要这样做,因为它不会像strdup那样将库调用重定向到malloc。

    您可以使用LD_PRELOAD执行包装和“覆盖”函数-类似于前面显示的示例

    LD_PRELOAD=/path.../lib_fake_malloc.so ./app
    
    但我建议您“稍微”聪明一点,我的意思是给dlsym打一次电话

    #define _GNU_SOURCE
    #include <stdio.h>
    #include <stdint.h>
    #include <dlfcn.h>
    
    void* malloc(size_t size)
    {
        static void* (*real_malloc)(size_t) = NULL;
        if (!real_malloc)
            real_malloc = dlsym(RTLD_NEXT, "malloc");
    
        void *p = real_malloc(size);
        fprintf(stderr, "malloc(%d) = %p\n", size, p);
        return p;
    }
    
    我同意他们的观点,这是一个“微不足道的例子”:。甚至不需要dlsym

    让我在我的“男性身份”页面中再引用一部分:


    我希望,描述是完整的,并展示了如何使用这些东西。

    在我的例子中,我需要将memalign/aligned\u malloc包装在malloc下。在尝试了其他解决方案后,我最终实现了下面列出的解决方案。它似乎工作得很好

    /*
    *使用静态的malloc和free的链接时间插入
    *链接器的(ld)“--wrap symbol”标志。
    * 
    *使用“-Wl,--wrap,malloc-Wl,--wrap,free”编译可执行文件。
    *这告诉链接器将对malloc的引用解析为
    *_uuuwrap_malloc、free as uuu wrap_free、real_umalloc as malloc,以及
    *_uuureal_u免费。
    */
    #包括
    void*\uuuu real\u malloc(尺寸大小);
    无效uu真实u自由(无效*ptr);
    /* 
    *\uuuu wrap\u malloc-malloc包装函数
    */
    无效*\uuuuuuuu包裹\uuMalloc(尺寸)
    {
    void*ptr=\uuuuureal\umalloc(大小);
    printf(“malloc(%d)=%p\n”,大小,ptr);
    返回ptr;
    }
    /* 
    *_u_wrap_free-free包装函数
    */
    无效uu包裹u自由(无效*ptr)
    {
    __不动产(ptr);
    printf(“免费(%p)\n”,ptr);
    }
    
    如果您是自定义
    malloc
    free
    的唯一客户机(即,您没有试图为其他库中的代码修补这些方法),那么您可以使用依赖项注入

    \ifndef分配器
    #定义分配器
    #包括
    结构分配器;
    类型定义结构{
    void*(*allocate)(结构分配器*Allocator,size\u t size);
    void(*free)(结构分配器*分配器,void*对象);
    }分配表;
    类型定义结构分配器{
    常量分配器vtable*vptr;
    }分配器;
    类型定义结构{
    超级分配器;
    字符*缓冲区;
    尺寸偏差;
    容量大小;
    }缓冲分配器;
    void BufferedAllocator_init(BufferedAllocator*分配器,char*缓冲区,大小\u t容量);
    typedef分配器MallocAllocator;
    void MallocAllocator_init(MallocAllocator*分配器);
    void*Allocator\u allocate(分配器*Allocator,size\u t size);
    无效分配器
    
    void *
    __wrap_malloc (size_t c)
    {
        printf ("malloc called with %zu\n", c);
        return __real_malloc (c);
    }
    
    --wrap=symbol
           Use a wrapper function for symbol.
           Any undefined reference to symbol will be resolved to "__wrap_symbol".
           Any undefined reference to "__real_symbol" will be resolved to symbol.
    
    /* 
     * Link-time interposition of malloc and free using the static
     * linker's (ld) "--wrap symbol" flag.
     * 
     * Compile the executable using "-Wl,--wrap,malloc -Wl,--wrap,free".
     * This tells the linker to resolve references to malloc as
     * __wrap_malloc, free as __wrap_free, __real_malloc as malloc, and
     * __real_free as free.
     */
    #include <stdio.h>
    
    void *__real_malloc(size_t size);
    void __real_free(void *ptr);
    
    
    /* 
     * __wrap_malloc - malloc wrapper function 
     */
    void *__wrap_malloc(size_t size)
    {
        void *ptr = __real_malloc(size);
        printf("malloc(%d) = %p\n", size, ptr);
        return ptr;
    }
    
    /* 
     * __wrap_free - free wrapper function 
     */
    void __wrap_free(void *ptr)
    {
        __real_free(ptr);
        printf("free(%p)\n", ptr);
    }