After upgrading to the latest glibc, I noticed that malloc_hooks is deprecated, so I am trying to override certain glibc functions with user-defined ones using the --wrap symbol. For instance, I'm using --wrap=malloc to override the glibc malloc function with my custom wrap_malloc.
Direct calls to malloc in my code are correctly redirected to wrap_malloc. However, when calling glibc functions like fopen(), which internally invokes malloc, the internal malloc call is not being overridden by my wrap_malloc.
Does anyone have suggestions on how I can solve this issue and ensure that internal malloc calls (e.g., from fopen()) are overridden with my custom function? Any insights would be appreciated!
I've tried using the LD_PRELOAD option, but it doesn't seem to work because my application is built statically
Update :
As suggested I attempted to implement a custom memory allocation approach by declaring malloc() and free() as weak attributes in glibc malloc.c file:
//malloc.c
void free(void *mem) __attribute__((weak));
void* malloc(size_t size) __attribute__((weak));
also in the definition ,I defined it as follows: as malloc() is aliased to __libc_malloc
void* __attribute__((weak)) __libc_malloc(size_t bytes) {
// code
}
However, I added debug prints to my custom malloc and free to test, but I don't see those prints, indicating that calls to malloc are not invoking my custom implementation.
the compilation command to build my application, looks like this:
$(CXX) -Wl,--verbose -o $@ -I$(SSL_NOTHREADS_INCDIR) -L$(SSL_NOTHREADS_LIBDIR) `sn-linktool $+` $(NPU_IXP_LIBS) $(NP4C_NLM11K_LIBS) $(BOXER_STATIC_LIBS) -lsn_memacct -lm -ldl -ltirpc -lssp -lc -Wl,--allow-multiple-definition $(STATIC_NSS_LIBS_CXX)
In this command, my custom malloc is part of libsn_memacct.a, which is linked with -lsn_memacct, while malloc.c from glibc is linked through -lc. Even though I defined glibc's malloc as a weak symbol, it seems my custom malloc is not overriding it.
For fully-static linking, your best (and likely only) choice is to replace the entire libc.a(malloc.o) with an alternate implementation.
Note that you must replace all the symbols in malloc.o, or your link will fail with multiply-defined symbols.
For example, on Fedora 40, the following "works":
#include <stdio.h>
#include <string.h>
static char buf[10000] __attribute__((aligned(16)));
static char *mptr = &buf[0];
void *malloc(size_t sz)
{
char *r = mptr;
mptr += (sz + 0xF) & ~0xF;
fprintf(stderr, "malloc(%zu) -> %p\n", sz, r);
return r;
}
void free(void *p)
{
fprintf(stderr, "free(%p)\n", p);
}
void *calloc(size_t nelem, size_t sz)
{
void *r = malloc(nelem * sz);
fprintf(stderr, "calloc(%zu, %zu) -> %p\n", nelem, sz, r);
return r;
}
void *realloc(void *p, size_t sz)
{
char *r = malloc(sz);
memcpy(r, p, sz);
fprintf(stderr, "realloc(%p, %zu) -> %p\n", p, sz, r);
return r;
}
int main(int argc, char *argv[])
{
fprintf(stderr, " main starts\n");
if (argc < 2) return 0;
fprintf(stderr, " fopen(%s)\n", argv[1]);
FILE *fp = fopen(argv[1], "w");
fprintf(stderr, " fopen(%s) -> %p\n", argv[1], fp);
if (fp == NULL) return 1;
fprintf(stderr, " fclose(%p)\n", fp);
fclose(fp);
fprintf(stderr, " main returns\n");
return 0;
}
gcc -Wall -Wextra -static t.c && ./a.out foo.txt
malloc(6) -> 0x49d1b0
malloc(1241) -> 0x49d1c0
calloc(1241, 1) -> 0x49d1c0
malloc(24) -> 0x49d6a0
malloc(160) -> 0x49d6c0
malloc(160) -> 0x49d760
malloc(256) -> 0x49d800
malloc(256) -> 0x49d900
main starts
fopen(foo.txt)
malloc(472) -> 0x49da00
fopen(foo.txt) -> 0x49da00
fclose(0x49da00)
free(0x49da00)
main returns
free(0x49d900)
free(0x49d800)
Above you can clearly see malloc being called from fopen and free being called from fclose.
Update:
In my wrap_malloc function, after handling some memory accounting, I want to call the original malloc using __real_malloc.
In that case the solution above will not work. But you can make it work by doing this:
malloc.o from libc.a: ar x /path/to/libc.a malloc.o{malloc,calloc,realloc,free} in the extracted object:cat > to-weaken <<EOF
malloc
realloc
calloc
free
EOF
objcopy --weaken-symbols=to-weaken malloc.o malloc2.o
malloc, use its __malloc alias.malloc2.o object.Here it is all together:
#include <stdio.h>
extern void *__malloc(size_t),
*__realloc(void *p, size_t),
*__calloc(size_t, size_t);
extern void __free(void*);
void *malloc(size_t sz)
{
void *r = __malloc(sz);
fprintf(stderr, "malloc(%zu) -> %p\n", sz, r);
return r;
}
void free(void *p)
{
fprintf(stderr, "free(%p)\n", p);
__free(p);
}
void *calloc(size_t nelem, size_t sz)
{
void *r = __calloc(nelem, sz);
fprintf(stderr, "calloc(%zu, %zu) -> %p\n", nelem, sz, r);
return r;
}
void *realloc(void *p, size_t sz)
{
char *r = __realloc(p, sz);
fprintf(stderr, "realloc(%p, %zu) -> %p\n", p, sz, r);
return r;
}
int main(int argc, char *argv[])
{
fprintf(stderr, " main starts\n");
if (argc < 2) return 0;
fprintf(stderr, " fopen(%s)\n", argv[1]);
FILE *fp = fopen(argv[1], "w");
fprintf(stderr, " fopen(%s) -> %p\n", argv[1], fp);
if (fp == NULL) return 1;
fprintf(stderr, " fclose(%p)\n", fp);
fclose(fp);
fprintf(stderr, " main returns\n");
return 0;
}
gcc -Wall -Wextra -static t.c malloc2.o && ./a.out foo.txt
malloc(6) -> 0x1279fa0
calloc(1241, 1) -> 0x1279fc0
malloc(24) -> 0x127a4b0
malloc(160) -> 0x127a4d0
malloc(160) -> 0x127a580
malloc(256) -> 0x127a630
malloc(256) -> 0x127a740
main starts
fopen(foo.txt)
malloc(472) -> 0x127a850
fopen(foo.txt) -> 0x127a850
fclose(0x127a850)
free(0x127a850)
main returns
free(0x127a740)
free(0x127a630)