Create a wrapper function for malloc and free in C
Solution 1
You have a few options:
GLIBC-specific solution (mostly Linux). If your compilation environment is
glibc
withgcc
, the preferred way is to use malloc hooks. Not only it lets you specify custommalloc
andfree
, but will also identify the caller by the return address on the stack.-
POSIX-specific solution. Define
malloc
andfree
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 originalmalloc
implementation, which you can look up usingdlsym
withRTLD_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; }
-
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
-
Mac OSX specific.
Same as Linux, except you will be using
DYLD_INSERT_LIBRARIES
environment variable.
Solution 2
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.
Solution 3
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.
/*
* 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);
}
Solution 4
Here's a set of wrapper functions I used for years (and still do when I dip into C) to detect unfree'd memory, memory free'd multiple times, references to free'd memory, buffer overflows/underflows, and freeing memory that was not allocated.
ftp://ftp.digitalmars.com/ctools.zip
They've been around for 25 years and have proven themselves.
You could use the macro preprocessor to redefine malloc and free to use the mem package ones, but I recommend against it, because it won't redirect library calls to malloc like what strdup does.
Solution 5
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.
Related videos on Youtube
Guy Avraham
I'm a software engineer experienced with mainly C++ and Python 3. Always eager to learn and expend my knowledge mainly in low-level programming topics such as: C/C++, Linux kernel, OS, etc... while also expanding my knowledge to the areas of automation, CI/CD, DevOps and networking.
Updated on April 08, 2021Comments
-
Guy Avraham about 3 years
I am trying to create wrapper functions for
free
andmalloc
in C to help notify me of memory leaks. Does anyone know how to declare these functions so when I callmalloc()
andfree()
it will call my custom functions and not the standards lib functions?-
sudo almost 7 yearsSide note, this is what tools like Valgrind do. If you'd rather use something out of the box on Unix or Linux, Valgrind is a good option.
-
Gabriel Staples almost 3 yearsRelated: What is the LD_PRELOAD trick?
-
-
Jonathan Leffler over 15 yearsBest not to use leading underscores in names - they're mainly reserved to the implementation.
-
bradtgmurray over 15 yearsRight, he's using those values as defined in the implementation. gcc.gnu.org/onlinedocs/gcc-3.2.3/cpp/…
-
Thangaraj over 12 yearsHi I am getting error, how to resolve? ERROR: ld.so: object '/home/tmp/libjmalloc.so' from LD_PRELOAD cannot be preloaded: ignored.
-
Thangaraj over 12 yearsHi I am getting error, how to resolve? ERROR: ld.so: object '/home/tmp/libjmalloc.so' from LD_PRELOAD cannot be preloaded: ignored.
-
Alex B over 12 years@Thangaraj, I can't tell, this is a very generic error. It can be that the file isn't found, or compiled for the wrong architecture (x86 vs x86_64), or the lib isn't owned by the user owning the executable, if it has SUID bit set and the lib isn't owned by the owner of the executable (otherwise you could run your lib's code as other user).
-
Grzegorz Wierzowiecki over 12 yearsStrange. In past it worked, currently I got the same error as you. As I google it, there are many many similar cases. Please, let us know, when you find solution. I tried and couldn't - 'file' shows that binaries are same arch, so it should work. It needs more attention.
-
Matt Joiner over 12 yearsParagraphs 2 and 3 are misleading.
-
Thangaraj over 12 yearsLet me check this Alex. I have one doubt, this method will hold good for small programs. suppose if I have a large program, then how can I find out from where (which function) the malloc function is called.
-
Thangaraj over 12 yearsI had problem in two systems, in one system I corrected by replacing relative path with absolute path and in other system still digging :). I have one doubt, this method will hold good for small programs. suppose if I have a large program, then how can I find out from where (which function) the malloc function is called.
-
Grzegorz Wierzowiecki over 12 yearsGood you've wrote, that full path works in one of your two configurations. I've checked out. In my configuration it does not work, when path contains white-spaces or is too long. So simply, copy libjmalloc.so into /tmp , and run
LD_PRELOAD=/tmp/libjmalloc.so ./a.out
. It solves problem in my case. Does it help in yours? -
Thangaraj over 12 yearsDo you have any inputs for; I have one doubt, this method will hold good for small programs. suppose if I have a large program, then how can I find out from where (which function) the malloc function is called.
-
Grzegorz Wierzowiecki over 12 years@thangaraj If you want to know who is caller inside of callee, I would recommend changing or combining method with one of following: binary instrumentation like here or tracing/debugging like gdb, or ptrace based like sydbox or pinktrace - here are similar ideas about tracking memory allocations. Making breakpoints with gdb in malloc and checking backtrace sounds reasonable.
-
Roddy over 12 years@Matt Joiner - can you elaborate, please?
-
Matt Joiner over 12 yearsP2: If there were namespaces it still wouldn't change the situation. Also you can subsequently call the real malloc function. This has nothing to do with C. P3: Yes you could, and this wouldn't be hooking calls to malloc/free properly in code you didn't have control over. You can instruct the linker to redirect references to different names. Without modifying the C code. Summary: None of the limitations you claim really exist, and none of the workarounds you have given are necessary.
-
Roddy over 12 years@Matt - Thanks: I wasn't aware of malloc hooks and --wrap, BUT they are highly toolchain and os specific. Only gcc supports them, AFAICT - and the OP didn't specify OS or tools. C++ namespaces could provide a similar hack to the #define approach, but I'd agree it's far from ideal and suffers the problem you mentioned. In general, I'm still happy with my answer.
-
eric.frederich about 12 yearsAgree. Valgrind is awesome. I like how it works with compiled binaries. You don't need to compile it special or anything although you'll get the best results if you compile with -O0 and -g flags.
-
Shahbaz about 11 years@JonathanLeffler, leading
__
and names starting with_
and a capital letter are reserved by the standard. Names starting with a single underscore are not reserved, but they should be contained within the file, i.e. the linker shouldn't see them. So as long as_my_malloc
and_my_free
are static functions, it's ok. On the other hand, redefining library functions is undefined behavior. -
Jonathan Leffler about 11 years@Shahbaz: ISO/IEC 9899:2011, §7.1.3 Reserved identifiers says: — All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use. — All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces. I believe that
_my_malloc()
as a static function falls foul of the second restriction. -
Shahbaz about 11 years@JonathanLeffler, how so?
static void *_my_malloc(size_t)
is defined only in file scope in the ordinary name space (and it's not a struct/union/enum, so it doesn't even enter the tag name space). -
Jonathan Leffler about 11 years@Shahbaz: Doesn't your comment that '
static void *_my_malloc(size_t)
is defined in file scope in the ordinary name space' collide head-to-head with the standard saying 'all identifiers that begin with underscore are always reserved for use as identifiers with file scope in the ordinary name space'. What am I missing? -
Shahbaz about 11 years@JonathanLeffler, I had interpreted the reserved for use in file scope as possible to use so long as it is in the file scope, i.e. reserved for the programmers use (so long as it's in the file scope). Perhaps you are right, but if you look at GNU's description of reserved names, where it says (emphasis mine): reserved names include all external identifiers (global functions and variables) that begin with an underscore (‘’) and ..._ seems more compatible with my understanding (they could be wrong though)
-
davidA about 8 yearsOption 2 works well, until the application is run by valgrind, and then all sorts of odd problems happen. Is this due to valgrind doing a similar override and causing some sort of conflict? Which option is best suited for malloc wrapping with valgrind?
-
stephen over 6 yearsIf you want to call malloc from my_malloc, you'll want to #undef malloc, in the source file that defines my_malloc (and friends)
-
phip1611 about 5 yearsYou are using printf() inside the custom malloc but printf() itself uses malloc. I'm getting segfaults with for example
LD_PRELOAD=./malloc.so ls
. Isn't this creating an infinite recursion? How to tell the functions inside our custom malloc to use the libc-malloc? -
peterh over 4 yearsYour posix example gives a big segfault now.
-
Christoffer Bubach over 4 yearsAuth protected link
-
Artur Mustafin over 3 yearslike you solid approach, will implement using i_p_c naming convention
-
Gabriel Staples almost 3 yearsSee also this tutorial for how to build the
*.so
shared object: cprogramming.com/tutorial/shared-libraries-linux-gcc.html. -
Gabriel Staples almost 3 yearsIf you override
malloc()
andfree()
, rather than simply wrapping them, you must take into account some special considerations, such as you may be creating infinite recursion if you callprintf()
from withinmalloc()
, asprintf()
may callmalloc()
, which now callsprintf()
...forever until stack overflow. See my answer here on this: “Segmentation fault (core dumped)” for: “No such file or directory” for libioP.h, printf-parse.h, vfprintf-internal.c, etc -
Gabriel Staples almost 3 yearsAdditionally, here are some more tools you may need in your quest to override
malloc()
. Also my answer: How to dynamically inject function calls before and after another executable'smain()
function. -
Dan M. about 2 yearsIs 1) really a preferred way? It seems to be not thread safe, so it'll probably break for any modern program using threads.
-
Dan M. about 2 yearsHow does --wrap linker flag work with malloc calls inside glibc? I.e. will it also somehow rename malloc inside
strdup
to the wrapper? -
Bruce Adams about 2 yearsmalloc hooks are no longer an appropriate mechanism see for example - developers.redhat.com/articles/2021/08/25/… - interposition is still a valid alternative - gnu.org/software/libc/manual/html_node/…