Comment by duskwuff
4 years ago
Using fork() also means you end up with shared ownership of resources like file descriptors, which can have some pretty weird consequences.
4 years ago
Using fork() also means you end up with shared ownership of resources like file descriptors, which can have some pretty weird consequences.
This is true with all process creation APIs.
Windows defaults to CLOEXEC semantics and you have to opt-in to child process inheriting open file handles, and that has caused problems.
Unix defaults to not-CLOEXEC sematincs, and that too has caused problems.
The Windows default can cause problems because of simple logic bugs.
The Unix default can cause unsolvable problems because of races between threads.
You should use CLOEXEC everywhere. Except you can't because you are using libraries.
True. The main problem with the Unix default is that there wasn't a way to set O_CLOEXEC on all new FDs race-free until recently. That's a real problem. FD leaks to children can be bad, but most of the time they are not the end of the world, and often one can steal a closefrom() implementation from a BSD or Illumos as a workaround when you know exactly what you want to allow the child to inherit.
closefrom() comes in handy for this. It's missing on some platforms (notably glibc and mac iirc) but actually not too hard to implement a work-alike.
I've copied a closefrom() many a time.
A common hack I've had to add is an argument FD that is not to be closed because. e.g., an flock is held on it.
Or more importantly, IPC mechanisms like mutexes. If they're in shared memory, you now have two problems. The runtime of a very very popular scripting languages does this.