diff options
| author | Xavier Leroy <xavier.leroy@inria.fr> | 2017-03-20 10:15:26 +0100 |
|---|---|---|
| committer | Xavier Leroy <xavier.leroy@inria.fr> | 2017-03-26 19:41:17 +0200 |
| commit | f6b1bae69b4849193a387ebe208c39eee2d770c7 (patch) | |
| tree | 72c420682797aca9d2cd0535b7afcc6296412099 /otherlibs | |
| parent | 3f614747886a7f25b9db91fc35bc76d57a5efa8e (diff) | |
| download | ocaml-f6b1bae69b4849193a387ebe208c39eee2d770c7.tar.gz | |
Fix Unix.create_process in the case where the same descriptor is used several times (continued)
After the revert to 4.04 implementation in commit d54f631, Damien Doligez came up with a very nice solution, see
https://github.com/ocaml/ocaml/pull/1105#issuecomment-286455646
This commit adopts Damien's solution, and adds a test for swapping stdout and stderr.
Diffstat (limited to 'otherlibs')
| -rw-r--r-- | otherlibs/unix/unix.ml | 38 |
1 files changed, 18 insertions, 20 deletions
diff --git a/otherlibs/unix/unix.ml b/otherlibs/unix/unix.ml index ba9210931e..0bf5071bc3 100644 --- a/otherlibs/unix/unix.ml +++ b/otherlibs/unix/unix.ml @@ -874,36 +874,34 @@ let system cmd = end | id -> snd(waitpid_non_intr id) -(* Duplicate [fd] and make sure that the resulting descriptor - is not one of the standard descriptors 0, 1, 2. +(* Duplicate [fd] if needed to make sure it isn't one of the + standard descriptors (stdin, stdout, stderr). + Note that this function always leaves the standard descriptors open, + the caller must take care of closing them if needed. The "cloexec" mode doesn't matter, because the descriptor returned by [dup] will be closed before the [exec], and because no other thread is running concurrently - (we are in the child process of a fork). *) - -let rec safe_dup fd = - let new_fd = dup fd in - if new_fd >= 3 then - new_fd - else begin - let res = safe_dup fd in - close new_fd; - res - end + (we are in the child process of a fork). + *) +let rec file_descr_not_standard fd = + if fd >= 3 then fd else file_descr_not_standard (dup fd) let safe_close fd = try close fd with Unix_error(_,_,_) -> () let perform_redirections new_stdin new_stdout new_stderr = - let newnewstdin = safe_dup new_stdin in - let newnewstdout = safe_dup new_stdout in - let newnewstderr = safe_dup new_stderr in + let new_stdin = file_descr_not_standard new_stdin in + let new_stdout = file_descr_not_standard new_stdout in + let new_stderr = file_descr_not_standard new_stderr in + (* The three dup2 close the original stdin, stdout, stderr, + which are the descriptors possibly left open + by file_descr_not_standard *) + dup2 ~cloexec:false new_stdin stdin; + dup2 ~cloexec:false new_stdout stdout; + dup2 ~cloexec:false new_stderr stderr; safe_close new_stdin; safe_close new_stdout; - safe_close new_stderr; - dup2 ~cloexec:false newnewstdin stdin; close newnewstdin; - dup2 ~cloexec:false newnewstdout stdout; close newnewstdout; - dup2 ~cloexec:false newnewstderr stderr; close newnewstderr + safe_close new_stderr let create_process cmd args new_stdin new_stdout new_stderr = match fork() with |
