为何自定义malloc无法拦截库函数strdup的malloc调用?
问题:strdup调用malloc未触发__wrap_malloc日志的原因?
我通过GCC的-Wl,--wrap=malloc/-Wl,--wrap=free选项包装了malloc和free函数,实现了带日志打印的__wrap_malloc与__wrap_free。根据手册说明,strdup会调用malloc,但运行代码时,直接调用malloc能触发自定义日志,而strdup调用的malloc却未触发,仅能看到一次自定义malloc日志,却能看到两次自定义free日志。环境为x86架构Ubuntu虚拟机。
代码(main.c)
#include <stdio.h> #include <stdlib.h> #include <string.h> void* __real_malloc(size_t size); void __real_free(void* ptr); void* __wrap_malloc(size_t size) { void *ptr = __real_malloc(size); printf("custom malloc size=%ld ptr=%p\n", size, ptr); return ptr; } void __wrap_free(void* ptr) { printf("custom free ptr=%p\n", ptr); __real_free(ptr); } // gcc -o mybin main.c -Wl,--wrap=malloc -Wl,--wrap=free int main() { const char *original = "Hello, World!"; char *copy; copy = strdup(original); printf("Original: %s\n", original); printf("Copy: %s\n", copy); void *ptr = malloc(100); free(ptr); free(copy); return 0; }
运行输出
Original: Hello, World! Copy: Hello, World! custom malloc size=100 ptr=0x55a845ef06d0 custom free ptr=0x55a845ef06d0 custom free ptr=0x55a845ef02a0
原因分析
核心原因是strdup属于libc内部函数,它在库内部直接调用的是私有版本的__libc_malloc,而非公开的malloc符号,而GCC的--wrap选项仅对代码中直接引用公开符号的调用生效:
--wrap=symbol的工作原理是让链接器把编译单元中所有对symbol的引用替换为__wrap_symbol,同时将__real_symbol指向原符号。但这个替换只作用于你自己编写的代码,无法修改预编译好的libc内部函数的调用逻辑。- 系统strdup是预编译的库函数,它内部直接调用libc私有malloc实现,不会触发对公开
malloc符号的引用,因此你的__wrap_malloc不会被触发。 - 而free的情况不同:当你在代码中调用
free(copy)时,是直接引用公开的free符号,链接器会将其替换为__wrap_free,不管指针来自哪里,都会走你的包装函数,因此能看到两次free日志。
解决办法
- 若要拦截所有malloc调用(包括libc内部的),可以使用
LD_PRELOAD加载自定义动态库,覆盖libc中的malloc符号。 - 手动实现自己的strdup函数,在其中调用你包装后的malloc,替代系统的strdup。
内容的提问来源于stack exchange,提问作者Catalin Demergian
相关产品推荐
相关产品推荐

