6

从 Linux 手册页

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

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

特别是,程序员不能依赖父级保持阻塞,直到子级 [...] 调用execve(2)[...]。

execve(2)在手册页中重复使用,它的用法表明它是唯一exec可以在vfork().

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

4

3 回答 3

5

你必须打电话execve。不能保证任何其他 exec 系列函数不会执行在vfork. 例如:

  • execl可以为参数列表分配内存。它需要是异步信号安全的,这意味着它不太可能使用malloc,但即使没有,也无法在底层execve发生后释放分配的内存(存在于父内存空间中),所以除非它设法在堆栈上构造参数列表,否则它(充其量)会泄漏父级中的内存。

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

等等

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

如果您正在寻找更有效的替代方法fork,请使用posix_spawn.

于 2014-06-14T19:10:34.837 回答
1

在 Linux 上,所有函数实际上都是syscallexec*之上的包装库函数。execve所以通过调用execlp你实际上也在调用execve.

于 2014-06-14T18:37:37.723 回答
1

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

POSIX 标准描述说,在 之后vforkexec(3)必须调用其中一个函数。

Linux 描述说必须在vfork,之后execve(2)(并且只有 execve)被调用。

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

无论哪种方式,很明显 Linux 允许execve(并且只允许execve*)在vfork. POSIX 标准可能允许其他exec功能,但 Linux 不允许。

*嗯,当然,它也可以打电话_exit,但我_exit在这个问答中忽略了。

于 2014-11-07T22:58:54.007 回答