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)