从open()钩子分割错误

我正在试图在系统函数open()上创build一个钩子。 我已经按照下面的方法做了这个。

我用下面创build了一个包装库:

 extern int mocked_open(const char* fn, int flags, va_list args); int open(const char* fn, int flags, ...) { int r = -1; va_list args; va_start(args, flags); r = mocked_open(fn, flags, args); va_end(args); return r; } 

我编译成libwrapper.so,我使用LD_PRELOAD加载。

mocked_open()的实现如下(我使用CPPUtest框架):

 int mocked_open(const char* fn, int flags, va_list args) { if (strncmp(fn, test_device_id, 11) == 0) { return mock().actualCall("open").returnValue().getIntValue(); } else { int r = -1; int (*my_open)(const char*, int, ...); void* fptr = dlsym(RTLD_NEXT, "open"); memcpy(&my_open, &fptr, sizeof(my_open)); if (flags & O_CREAT) { r = my_open(fn, flags, va_arg(args, mode_t)); } else { r = my_open(fn, flags); } return r; } } 

test_device_id是一个简单的string(“test_device”),我希望不要在其他地方使用。

在运行testing期间,可执行文件会出现分段错误。 我已经追溯到GCC分析function,它想打开/创build一堆.gcda文件,并调用open()

在用strace(根据下面的build议)进行一些debugging之后,我发现r = my_open(fn, flags, va_arg(args, mode_t)); 确实是罪魁祸首。 它被recursion调用,或者看起来如此:我看到很多调用这个行,没有函数返回。 然后是段错误。 正在打开的文件是相应的.gcda文件(用于分析)。 事实上,段错误只会在启用分析时发生

当您启用gcov分析功能进行编译时,编译器会在您的函数中插入额外的代码,以跟踪哪些代码已被执行。 在粗糙的伪代码中,插入的代码将(除其他外)做:

 if (!output_file_has_been_opened) { fd = open(output_filename, ...); check_ok(fd); output_file_has_been_opened = TRUE; track_coverage(); } 

…所以如果输出文件尚未成功打开(如在程序开始时),它将尝试打开它。 不幸的是,在这种情况下,会调用你的模拟open()函数 – 它具有相同的插入代码; 因为文件还没有被成功的打开,并且由于gcov代码没有意识到有什么不寻常的事情发生,它会再次尝试open()调用 – 这是什么导致递归(和最终的段错误,一次堆栈已经耗尽)。

尝试这个

 typedef int (*OpenFunction)(const char* fn, int flags, ...); 

然后

 OpenFunction function; void **pointer; pointer = (void **)&function; *pointer = dlsym(RTLD_NEXT, "open"); 

这是一个完整的实例

 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <dlfcn.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> typedef int (*OpenFunction)(const char* fn, int flags, ...); int main(int argc, char **argv) { OpenFunction function; void *dl; int fd; void **pointer; if (argc < 2) return -1; pointer = (void **)&function; *pointer = dlsym(RTLD_NEXT, "open"); fd = function(argv[1], O_RDONLY); if (fd != -1) { printf("file opened succesfully\n"); close(fd); } else { printf("%s: cannot open the file\n", strerror(errno)); } return 0; } 

你错误地传递了va_list。 尝试下面的希望它有帮助

  r = my_open(fn, flags, args); 

欲了解更多信息http://c-faq.com/varargs/handoff.html