open() 上的挂钩导致的分段错误
Segmentation fault from hook on open()
我正在尝试在系统函数 open()
上创建一个挂钩。我按照以下几行完成了此操作。
我使用以下内容创建了一个包装器库:
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
是一个简单的字符串("test_device"),希望别处用不到。
在 运行 测试期间,可执行文件因分段错误而崩溃。我已经将其追溯到 GCC 分析功能,它想要 open/create 一堆 .gcda
文件并为此调用 open()
。
在使用 strace 进行一些调试后(根据下面的建议),我发现 r = my_open(fn, flags, va_arg(args, mode_t));
行确实是罪魁祸首。它被递归调用,或者看起来是这样:我看到很多对这一行的调用,但函数没有返回。然后是段错误。正在打开的文件是相应的 .gcda 文件(用于分析)。事实上,段错误仅在启用分析时发生。
试试这个
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);
当您在启用 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()
调用 - 这就是导致递归(以及最终的段错误)的原因,一旦堆栈耗尽)。
我正在尝试在系统函数 open()
上创建一个挂钩。我按照以下几行完成了此操作。
我使用以下内容创建了一个包装器库:
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
是一个简单的字符串("test_device"),希望别处用不到。
在 运行 测试期间,可执行文件因分段错误而崩溃。我已经将其追溯到 GCC 分析功能,它想要 open/create 一堆 .gcda
文件并为此调用 open()
。
在使用 strace 进行一些调试后(根据下面的建议),我发现 r = my_open(fn, flags, va_arg(args, mode_t));
行确实是罪魁祸首。它被递归调用,或者看起来是这样:我看到很多对这一行的调用,但函数没有返回。然后是段错误。正在打开的文件是相应的 .gcda 文件(用于分析)。事实上,段错误仅在启用分析时发生。
试试这个
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);
当您在启用 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()
调用 - 这就是导致递归(以及最终的段错误)的原因,一旦堆栈耗尽)。