自定义fprintf()未触发调用求助:fopen/fclose可正常拦截
fprintf拦截失效问题 嘿,我看了你的代码和问题描述,很快就发现了几个导致fprintf worked!没出现的原因,咱们一步步解决:
核心问题1:fprintf被编译器优化绕开,且拦截逻辑有疏漏
首先,你的测试程序里fprintf(fr, "%s", "Papa Don't Preach")这种格式固定、参数为字符串常量的调用,会被GCC自动优化成fwrite(因为fwrite不需要解析格式字符串,效率更高),直接跳过了你的fprintf拦截函数。另外,你自定义的fprintf直接调用了vfprintf,但没有绑定标准库的真实vfprintf实现,逻辑上也存在隐患。
核心问题2:指针转整数的潜在错误
你代码里直接把FILE*强转成int(比如sprintf(fidString, "fopen %d ", fp);),在64位系统上会丢失指针的高位字节,导致输出错误的标识,得用intptr_t来安全转换。
修复步骤来啦:
1. 修改共享库的fprintf拦截逻辑
咱们直接绑定标准库的vfprintf(因为标准库的fprintf本质就是基于vfprintf实现的),确保拦截逻辑能覆盖所有场景:
首先在共享库的全局变量区添加real_vfprintf指针,并引入必要头文件:
#include <stdint.h> // 用于安全转换指针为整数 static int (*real_vfprintf)(FILE *stream, const char *format, va_list arg) = NULL;
然后在初始化函数my_lib_init里初始化这个指针:
__attribute__((constructor)) void my_lib_init(void) { // ... 其他原有初始化代码保持不变 real_vfprintf = dlsym(RTLD_NEXT, "vfprintf"); }
最后修改你的fprintf拦截函数:
int fprintf(FILE *stream, const char *format, ...) { va_list arg; int done; // 双重检查,确保真实函数指针有效 if (!real_vfprintf) { real_vfprintf = dlsym(RTLD_NEXT, "vfprintf"); } va_start(arg, format); done = real_vfprintf(stream, format, arg); // 调用标准库的真实实现 va_end(arg); printf("fprintf worked!\n"); char message[200]; // 用intptr_t安全转换FILE*为整数,避免64位系统出错 sprintf(message, "fprintf %" PRIdPTR "", (intptr_t)stream); sendMessage(message); return done; }
2. 编译测试程序时禁用fprintf优化
编译测试程序时加上-fno-builtin-fprintf参数,禁止GCC把fprintf替换成fwrite:
LD_PRELOAD=./file_io_operation_interception.so gcc -fno-builtin-fprintf -o file_operations_test file_operations_test.c
3. 修复其他指针转整数的地方
把fopen和fclose里的指针转换也改成安全的方式:
// fopen函数里的代码修改: char fidString[30]; // 扩大缓冲区避免溢出 sprintf(fidString, "fopen %" PRIdPTR " ", (intptr_t)fp); // fclose函数里的代码修改: sprintf(message, "fclose %" PRIdPTR "", (intptr_t)fp);
重新编译运行
按照以下步骤重新操作:
- 重新编译共享库:
gcc -fpic -c file_io_operation_interception.c gcc -shared -lc -ldl -o file_io_operation_interception.so file_io_operation_interception.o
(注:编译.c文件时不需要-ldl,链接共享库时添加即可)
- 编译测试程序(带禁用优化参数):
LD_PRELOAD=./file_io_operation_interception.so gcc -fno-builtin-fprintf -o file_operations_test file_operations_test.c
- 运行测试程序:
LD_PRELOAD=./file_io_operation_interception.so ./file_operations_test
这下你就能在输出里看到fprintf worked!啦!
额外小提示
以后遇到可变参数函数的拦截问题,优先拦截对应的v版函数(比如vfprintf、vprintf),因为标准库中很多可变参数函数都是基于v版实现的,这样能避免被编译器优化绕开,覆盖更多场景。
内容的提问来源于stack exchange,提问作者Bruce

