重载fork()函数

6
我已经重载了fork()系统调用,并使用RTLD_NEXT创建了自己的fork()版本。即dlsym(RTLD_NEXT, fork)。这将触发我的fork版本。在此之后,我想复制实际fork()系统调用的任务,即创建子进程并返回pid以及一些其他附加功能。
我无法弄清楚如何做到这一点。我检查了fork()(fork.c)的内核源代码,但没有找到很多线索。
尝试以下操作:
dlsym(RTLD_NEXT,fork);  
int fork(void) {
    int pid=_fork(); // Trying to call actual fork does not work
    return pid;
}

我该怎么做呢?这里是fork的内核源代码链接:http://lxr.linux.no/linux+v2.6.32/kernel/fork.c#L10

编辑(从评论中提取):

我正在开发一个泄漏检测工具,当子进程删除父进程分配的内存时,该工具会检测到双重释放。为了解决这个问题,我将覆盖fork(),每当有fork()时,父进程的内存分配表将被复制到子进程中。


“不起作用”是什么意思?运行时错误?编译器错误? - Simone
@Simone:_fork(); // 错误:未声明_fork。我的想法是使其命中实际的fork内核版本,而不是我的版本。希望现在清楚了。 - RajSanpui
你到底想通过这样做实现什么?你的最终目标是什么? - Omnifarious
@Omnifarious:我想给现有的fork()调用添加一些功能,这将被我的一个工具使用。 - RajSanpui
为什么不使用宏?在 .c 文件中:int my_fork(void) { /* do stuff */; return fork(); } 而在头文件中:extern int my_fork(void); #define fork my_fork - Chris Lutz
1
父进程的内存分配表将会复制到子进程。这就是fork()的工作原理:父进程和子进程有相同的内存映射副本,但是位于不同的区域。如果子进程使用free()释放了内存,父进程将不会注意到,反之亦然。 - wildplasser
3个回答

8
您不会从内核源代码中获得与fork有关的任何有用信息。无论您使用什么库技巧,您的代码都将不被允许执行内核所做的事情。这是一个严格的边界,如果没有编写内核模块,就无法突破。
所有与fork相关的库代码只是设置并执行一个特殊指令,该指令切换到内核模式,其中内核的fork代码执行。有一种方法可以将此特殊指令放入您自己的代码中。那就是使用syscall函数。由于fork不需要参数,因此使用此函数进行系统调用应该相对容易。
但我不建议您这样做。我建议您采取以下措施:
typedef int (*forkfunc_t)(void);

int fork(void)
{
     forkfunc_t sysfork = (forkfunc_t)dlsym(RTLD_DEFAULT, "fork");
     return sysfork();
}

基本上,无论你做什么共享库的技巧,你都应该找到一些方法来检索 fork 函数之前的值,然后再用自己的值替换掉它。


我正在开发一个泄漏检测工具,该工具可以在子进程删除父进程分配的内存时检测到双重释放。为了解决这个问题,我将覆盖fork()函数,并且每当有fork()调用时,父进程的内存分配表将被复制到子进程中。 - RajSanpui
@kingsmasher1:啊,所以你不需要修改内核对“fork”的操作,你只需要确保拦截它并适当地包装它。这是很可行的,你的共享库技术也不错。 - Omnifarious
@kingsmasher1,我将您的评论编辑到了您的问题中,因为这是非常重要的信息!如果您对此不满意,请随时进行编辑。 - user257111

3

在包含<sys/syscall.h>后,您应该能够使用syscall(SYS_fork)来调用实际的fork。请参阅syscall(2)


我不确定是否还存在名为“fork”的系统调用。 我认为它被翻译成了一个具有特定参数集的“clone”调用。 - Omnifarious
@larsmans:这提供了一些好的想法!太棒了。让我现在尝试一下,看看是否有效。 - RajSanpui
@kingsmasher1 - 它能工作... 可能没问题,但我不会那样做。我会找到一种方法来调用libc中的原始fork函数。我认为这个解决方案随着时间的推移更加稳健。 - Omnifarious
@Omnifarious 基本上你是对的。它们都是系统调用,它们都调用 do_fork()。Clone 通过传递参数来设置其参数,而 fork 则设置默认值。例如,请参见 http://lxr.linux.no/#linux+v2.6.37/arch/x86/kernel/process.c#L233。 - user257111
2
直接进行系统调用是一个不好的主意。需要使用fork来调用pthread_atfork函数以及执行一些内部同步操作,以防止多线程父进程中的stdio/malloc状态在子进程中被破坏,更新鲁棒互斥锁列表指针等等... - R.. GitHub STOP HELPING ICE

0

既然你的编程技巧这么糟糕,为什么不考虑使用宏呢?

#define fork() (spoon(),fork())

或者

#define fork() spoon(fork())

spoon 是一个函数,它可以完成你想要实现的功能。

预处理器保证不会进行递归,并且将 fork 保留在扩展中。


我的问题不是如何重载fork()。我已经能够使用“dlsym”系统调用来重载它。我的问题是如何复制fork()的工作,但是现在我已经通过larsman的建议实现了这一点,我的问题得到了解决。无论如何,还是要感谢大家。 - RajSanpui

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接