4 ms·
It is not possible to (usefully) use the former POSIX vfork correctly: > The vfork() function shall be equivalent to fork(), except that the behavior is undefi
by naniwaduni 7y ago
It is not possible to (usefully) use the former POSIX vfork correctly:
> The vfork() function shall be equivalent to fork(), except that the behavior is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(), or returns from the function in which vfork() was called, or calls any other function before successfully calling _exit() or one of the exec family of functions.
This roughly simplifies to "the only safe thing to do after a vfork is exec", and in this decade you can use posix_spawnp for that instead.
In particular, you can't do safely do anything that you'd normally want to after forking, like closing fds or moving them around (that'd be "calls any other function"). This means that unless the executable you're execing into is also under your control and knows what it's getting into, you have to mangle your fds &c. in the parent, vfork-and-exec, then undo the mess you've just made.
It is in principle _possible_ to navigate this error-prone process without observable side-effects. (The same could be said about implementing speculative execution, and look where we are now.) But I would hesitate to call it correct; the approach is clearly wrong, even if the result looks okay..
The situation is only slightly better if you're targetting some particular OS, which can provide stronger guarantees.
- quotemstr 7y agoPOSIX is frequently hyperconservative garbage. There's what POSIX allows, and there's what Linux and other real Unix systems actually allow. How do you think posix_spawnnp is implemented on systems that don't have a native system call for it? vfork(2)! close(2) in practice works fine. I don't understand how you can claim that vfork can't be used correctly when there are thousands of existence proofs showing that it works fine.
- naniwaduni 7y ago> I don't understand how you can claim that vfork can't be used correctly when there are thousands of existence proofs showing that it works fine. As libc implementer, you're inherently OS- and probably compiler-bound, and you can either fudge it to work on the system you're writing for, or have enough clout to make it so. It's an implementation detail. As the author of a program which is not strictly OS-bound, you do not have this luxury. Even if you want it, you're probably better off calling clone(2) directly so that you won't get an unintended semantic. Without counting indirect uses via libc popen/system/&c., I do not believe there are "thousands" of correct uses of vfork. If we count distinct hand-written code paths that call vfork, I'd wager closer to a few dozen, with at best a handful outside of a libc. It's a hideous interface.
- quotemstr 7y agoI'm not suggesting that people use vfork over posix_spawn --- I'm objecting specifically to the claim that it can't be used correctly. It can be. Emacs uses it, portably, and the sky doesn't come crashing down.
- tropo 7y agoThe POSIX specification for vfork() is a poor match for reality. Linux and NetBSD, and all good OSes, provide a vfork() that is actually useful. There have been some bad OSes that mapped it to fork(), just like there are bad OSes that restrict you to the portable character set (not even full ASCII) or that don't have coherency between mmap() and read(). Somewhere you must draw the line, or you'll spend forever trying to deal with obscure portability issues that are mostly theoretical. After a vfork(), the memory image is shared and the parent is prevented from running. The child is a fully separate process in all other ways. This special vfork state ends when the child does an exit or exec. This is how it works, no matter if POSIX wants to add weasel words or not. Even with the lame POSIX specification, the "executable you're execing into" is perfectly safe messing with file descriptors. Once that exec happens, the child becomes like any other. Systems with a proper vfork() are also safe before the exec. It certainly would be nice to have an interface similar to vfork that would take a function pointer and allocate a stack, optionally letting the parent continue on. Linux itself actually can support this, but glibc is uncooperative in exposing it.
- deleted 7y ago[deleted]