Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a wrapper function for malloc and free in C

People also ask

How malloc and free is implemented in C?

Simplistically malloc and free work like this: malloc provides access to a process's heap. The heap is a construct in the C core library (commonly libc) that allows objects to obtain exclusive access to some space on the process's heap. Each allocation on the heap is called a heap cell.

What is a wrapper function in C?

A wrapper function is a subroutine (another word for a function) in a software library or a computer program whose main purpose is to call a second subroutine or a system call with little or no additional computation.

What is malloc () calloc () and free ()? Explain?

Deallocate memory previously allocated by functions malloc(), calloc() or realloc() and returns memory to operating system, so, other program can use free memory. free() function receives the pointer of previously allocated memory for memory deallocation.


You have a few options:

  1. GLIBC-specific solution (mostly Linux). If your compilation environment is glibc with gcc, the preferred way is to use malloc hooks. Not only it lets you specify custom malloc and free, but will also identify the caller by the return address on the stack.

  2. POSIX-specific solution. Define malloc and free as wrappers to the original allocation routines in your executable, which will "override" the version from libc. Inside the wrapper you can call into the original malloc implementation, which you can look up using dlsym with RTLD_NEXT handle. Your application or library that defines wrapper functions needs to link with -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;
    }
    
  3. Linux specific. You can override functions from dynamic libraries non-invasively by specifying them in the LD_PRELOAD environment variable.

    LD_PRELOAD=mymalloc.so ./exe
    
  4. Mac OSX specific.

    Same as Linux, except you will be using DYLD_INSERT_LIBRARIES environment variable.


You can do wrapper and "overwrite" function with LD_PRELOAD - similarly to example shown earlier.

LD_PRELOAD=/path.../lib_fake_malloc.so ./app

But I recommend to do this "slightly" smarter, I mean calling dlsym once.

#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;
}

example I've found here: http://www.jayconrod.com/cgi/view_post.py?23 post by Jay Conrod.

But what I've found really cool at this page is that: GNU linker provides a useful option, --wrap . When I check "man ld" there is following example:

void *
__wrap_malloc (size_t c)
{
    printf ("malloc called with %zu\n", c);
    return __real_malloc (c);
}

I agree with them that's "trivial example" :). Even dlsym is not needed.

Let, me cite one more part of my "man ld" page:

--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.

I hope, description is complete and shows how to use those things.


In my case I needed to wrap memalign/aligned_malloc under malloc. After trying other solutions I ended up implementing the one listed below. It seems to be working fine.

mymalloc.c.

/* 
 * 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);
}
 

In C, the method I used was similar to:

#define malloc(x) _my_malloc(x, __FILE__, __LINE__)
#define free(x) _my_free(x)

This allowed me to detect the line and file of where the memory was allocated without too much difficulty. It should be cross-platform, but will encounter problems if the macro is already defined (which should only be the case if you are using another memory leak detector.)

If you want to implement the same in C++, the procedure is a bit more complex but uses the same trick.