当我调用vfork()时,我可以调用任何exec *()函数,还是必须调用execve()?

时间:2014-06-14 18:35:03

标签: c linux exec vfork

From the Linux man page

  

vfork()函数与fork(2)具有相同的效果,除非在成功调用[...]其中一个函数之前,如果进程调用任何其他函数,则行为未定义。 exec(3)系列功能。

这表明在exec*()之后调用任何vfork()函数是可以接受的。但是,稍后在手册页中明确指出:

  

特别是,在孩子打电话给execve(2) [...]之前,程序员不能依赖父母被阻止。

execve(2)在手册页中重复使用,其用法表明它是exec之后唯一可接受的vfork()类型函数。

那么为什么execve被挑选出来,我可以安全地调用其他exec类型的函数(比如execlp)?

3 个答案:

答案 0 :(得分:5)

您必须致电execve。无法保证任何其他exec-family函数在vfork之后不执行不安全的操作。例如:

  • execl可以为参数列表分配内存。它必须是异步信号安全的,这意味着它不太可能使用malloc,但即使它没有,也没有办法在它之后释放分配的内存(存在于父代的内存空间中)。底层execve发生,所以它会(最多)泄漏父节点中的内存,除非它设法在堆栈上构造参数列表。

  • execvp需要访问环境才能执行路径搜索,还需要构建连接的路径名以传递给execve。后者可能需要分配,而前者可能会做各种不安全的事后vfork事情(注意:execvp甚至不是异步信号安全的。)

真的你不应该使用vfork。几乎不可能安全使用它。特别是在使用信号处理程序的任何程序中都不安全,因为除非你阻塞所有信号,否则信号处理程序可以在子程序中共享父项的内存时运行(在这种情况下,子项将在exec之后继承一个完全阻塞的信号掩码,几乎肯定不是你想要的。)

如果您正在寻找效率更高的fork替代方案,请使用posix_spawn

答案 1 :(得分:1)

在Linux上,所有exec*函数实际上是execve系统调用之上的包装库函数。因此,通过致电execlp,您实际上也在调用execve

答案 2 :(得分:0)

再次阅读本手册后,很明显有两种vfork

的描述

POSIX标准说明表示在vfork之后,必须调用其中一个exec(3)函数。

Linux说明表示在vfork之后,必须调用execve(2)(和 execve)。

我不清楚POSIX标准描述是否需要一致的实现来允许调用任何一个exec函数。标准描述的一种可能的解释是,实现可以决定允许哪些exec函数(并且仅要求在vfork之后允许至少一个函数。)

无论哪种方式,很明显Linux允许在execve之后调用execve(并且只有vfork *)。 POSIX标准可能允许其他exec函数,但Linux不支持。

*当然,它也可以拨打_exit,但我在此问答语中忽略_exit