c-当我调用vfork()时,我可以调用任何exec*()函数吗?或者我必须调用execve()



来自Linux手册页:

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

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

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

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

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

您必须调用execve。不能保证任何其他exec家族函数在vfork之后都不会执行不安全的操作。例如:

  • CCD_ 15可以为参数列表分配存储器。它需要是异步信号安全的,这意味着它不太可能使用malloc,但即使不使用,在底层execve发生后,它也不可能释放分配的内存(存在于父级的内存空间中(,因此它(最多(会泄漏父级中的内存,除非它设法在堆栈上构造参数列表。

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

等等。

实际上,您不应该简单地使用vfork。要保证它的使用安全几乎是不可能的。特别是,在任何使用信号处理程序的程序中,这都是不安全的,因为信号处理程序可以在共享父级内存的子级中运行,除非您阻止所有信号(在这种情况下,子级将在exec之后继承一个完全阻止的信号掩码,这几乎肯定不是您想要的(。

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

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

再次阅读手册后,可以清楚地看到vfork有两个描述:

POSIX标准描述规定在vfork之后,必须调用其中一个exec(3)函数。

Linux说明指出,在vfork之后,必须调用execve(2)(并且execve(。

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

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

*当然,它也可以调用_exit,但我在这个问答中忽略了_exit;A.

相关内容

  • 没有找到相关文章