So, I read your e-mail again and I'm wondering if you're making a logic error, or if I'm misunderstanding something:
- first you're talking about duplicate file or socket objects after
*fork()* (which is an issue I agree is quite annoying)
- the solution you're proposing doesn't close the file descriptors
after fork() but after *exec()*.
Basically the solution doesn't address the problem. Many fork() calls aren't followed by an exec() call (multiprocessing comes to mind).
Yes. In this specific case, the proper solution is to close the server socket right after fork() in the child process.
We can't do anything about file descriptors inherited upon fork() (and shouldn't do anything of course, except on an individual basis like this socket server example).
On the other hand, setting file descriptors close-on-exec has the advantage of avoiding file descriptor inheritance to spawned (fork()+exec()) child processes, which, in 99% of cases, don't need them (apart from stdin/stdout/stderr). Not only can this cause subtle bugs (socket/file not being closed when the parent closes the file descriptor, deadlocks, there are several such examples in the bug tracker), but also a security issue, because contrarily to a fork()ed process which runs code controlled by the library/user, after exec() you might be running arbitrary code.
Let's take the example of CGIHTTPServer: """ # Child try: try: os.setuid(nobody) except os.error: pass os.dup2(self.rfile.fileno(), 0) os.dup2(self.wfile.fileno(), 1) os.execve(scriptfile, args, env)
The code tries to execute a CGI script as user "nobody" to minimize privilege, but if the current process has an sensitive file opened, the file descriptor will be leaked to the CGI script, which can do anything with it.
In short, close-on-exec can solve a whole class of problems (but does not really apply to this specific case).
On the other hand, the one widespread user of exec() after fork() in the stdlib, namely subprocess, *already* closes file descriptors by default, so the exec() issue doesn't really exist anymore for us (or is at least quite exotic).
See the above example. There can be valid reasons to use fork()+exec() instead of subprocess.
Disclaimer: I'm not saying we should be changing all FDs to close-on-exec by default like Ruby did, I'm just saying that there's a real problem.