vfork()
函数与fork(2)
具有相同的效果,除非在成功调用[...]其中一个函数之前,如果进程调用任何其他函数,则行为未定义。exec(3)
系列功能。
这表明在exec*()
之后调用任何vfork()
函数是可以接受的。但是,稍后在手册页中明确指出:
特别是,在孩子打电话给
execve(2)
[...]之前,程序员不能依赖父母被阻止。
execve(2)
在手册页中重复使用,其用法表明它是exec
之后唯一可接受的vfork()
类型函数。
那么为什么execve
被挑选出来,我可以安全地调用其他exec
类型的函数(比如execlp
)?
答案 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
。