When I call vfork(), can I call any exec*() function, or must I call execve()?

1.2k Views Asked by At

From the Linux man page:

The vfork() function has the same effect as fork(2), except that the behavior is undefined if the process [...] calls any other function before successfully calling [...] one of the exec(3) family of functions.

This suggests that calling any exec*() function after vfork() is acceptable. However, later in the man page it says specifically:

In particular, the programmer cannot rely on the parent remaining blocked until the child [...] calls execve(2) [...].

execve(2) is used repeatedly in the man page, and its usage suggests that it's the only exec-type function that is acceptable after vfork().

So why is execve being singled out here, and am I safe to call other exec-type functions (like execlp)?

3

There are 3 best solutions below

7
On

On Linux all exec* functions are actually wrapper library functions on top of execve syscall. So by calling execlp you are actually also calling execve.

5
On

You must call execve. There is no guarantee that any of the other exec-family functions do not perform actions which would be unsafe after vfork. For example:

  • execl may allocate memory for the argument list. It's required to be async-signal-safe, which means it's unlikely to use malloc, but even if it doesn't, there's no way it could free the allocated memory (which exists in the parent's memory space) after the underlying execve takes place, so it would (at best) leak memory in the parent unless it manages to construct the argument list on the stack.

  • execvp needs to access the environment to perform a path search, and also needs to construct concatenated pathnames to pass to execve. The latter may require allocation and the former may do all sorts of unsafe-after-vfork things (note: execvp is not even async-signal-safe).

etc.

Really you should simply not use vfork. It's almost impossible to make its use safe. In particular it's unsafe in any program that's using signal handlers since the signal handler could run in the child while it's sharing the parent's memory unless you block all signals (and in that case the child would inherit a fully-blocked signal mask after exec, which is almost surely not what you want).

If you're looking for a more-efficient alternative to fork, use posix_spawn.

0
On

After reading over the manual again, it becomes clear that there are two descriptions of vfork:

The POSIX Standard Description says that after vfork, one of the exec(3) functions must be called.

The Linux Description says that after vfork, execve(2) (and only execve) must be called.

It's not clear to me whether the POSIX Standard Description requires a conforming implementation to allow any one of the exec functions to be called. One possible reading of the Standard Description is that the implementation may decide which exec functions are allowed (and only requires that at least one of them be allowed after a vfork).

Either way, it's clear that Linux allows execve (and only execve*) to be called after a vfork. The POSIX standard might allow other exec functions, but Linux does not.

*Well, sure, it can call _exit too, but I'm ignoring _exit in this Q&A.