如何重写fopen/ofstream等全局文件操作函数实现文件打开信息监控
实现无侵入监控文件打开的可行方案
注意事项
你示例中写的自定义fopen存在无限递归调用问题:自定义函数内直接调用fopen会再次触发你自己的实现,导致栈溢出,以下方案均已规避该问题。
方案1:宏替换(全平台通用,修改成本极低)
只要在项目全局引入的公共头文件(如预编译头)中加入以下定义即可,无需修改任何现有fopen调用代码:
#include <stdio.h> // 自定义fopen包装实现 static FILE* wrapped_fopen(const char* filename, const char* mode) { printf("%s-%s\n", filename, mode); // 加括号避免宏展开,直接调用原生fopen return (fopen)(filename, mode); } // 预编译阶段将所有fopen调用替换为自定义实现 #define fopen(filename, mode) wrapped_fopen(filename, mode)
- 优点:跨平台兼容,逻辑简单可控,可覆盖项目内所有显式fopen调用
- 注意:如果有代码取fopen的函数指针,需写成
&(fopen)才能获取原生函数地址
方案2:动态链接Hook(Linux平台,零代码修改)
如果连项目代码都不想改动,可以通过LD_PRELOAD运行时注入自定义实现,甚至可以监控第三方依赖库的fopen调用:
- 编写Hook代码
hook_fopen.c:
#define _GNU_SOURCE #include <stdio.h> #include <dlfcn.h> static FILE* (*original_fopen)(const char*, const char*) = NULL; FILE* fopen(const char* filename, const char* mode) { // 首次调用时动态获取原生fopen地址 if (!original_fopen) { original_fopen = dlsym(RTLD_NEXT, "fopen"); } printf("%s-%s\n", filename, mode); return original_fopen(filename, mode); }
- 编译为动态库:
gcc -shared -fPIC hook_fopen.c -o libhookfopen.so -ldl - 运行程序时注入即可:
LD_PRELOAD=./libhookfopen.so ./你的可执行程序
Windows平台可以通过IAT Hook实现相同效果,原理为修改进程导入表中fopen的函数地址指向自定义实现。
方案3:C++ std::ofstream 等流类的监控
和fopen类似,用宏替换即可无侵入实现监控:
#include <fstream> #include <cstdio> class MonitoredOfstream : public std::ofstream { public: MonitoredOfstream(const char* filename, std::ios_base::openmode mode = std::ios::out) : std::ofstream(filename, mode) { // 可自行将openmode转换为字符串输出 printf("%s-%u\n", filename, (unsigned int)mode); } }; #define ofstream MonitoredOfstream
所有现有ofstream对象创建代码无需修改,会自动触发自定义的监控逻辑。
内容的提问来源于stack exchange,提问作者Karthik K M
相关产品推荐
相关产品推荐

