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-20 10:15:26 +0100 |
commit | 3e4567dbb4249d83f7231009031196224a9d3187 (patch) | |
tree | 1ff53191d2524a361846c8b4b42049021f1525d9 /otherlibs/unix | |
parent | a6d77053692017224565d48fe62bdeff291d0781 (diff) | |
download | ocaml-3e4567dbb4249d83f7231009031196224a9d3187.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/unix')
-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 f60b6fbe74..de379c9639 100644 --- a/otherlibs/unix/unix.ml +++ b/otherlibs/unix/unix.ml @@ -884,36 +884,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 |