diff --git a/infer/src/base/Process.ml b/infer/src/base/Process.ml index c60f63481..e999e1566 100644 --- a/infer/src/base/Process.ml +++ b/infer/src/base/Process.ml @@ -38,28 +38,28 @@ let create_process_and_wait ~prog ~args = type action = ReadStdout | ReadStderr let create_process_and_wait_with_output ~prog ~args action = - let {Unix.Process_info.stdin; stdout; stderr; pid} = Unix.create_process ~prog ~args in - Unix.close stdin ; - (* NOTE: this simple implementation works well because we only read on *one* of stdout or - stderr. Reading on both is a lot more difficult: we would have to be careful not to block the - callee process on writing on either stdout or stderr, so issue non-blocking reads on both - stdout and stderr until the end of the program, probably using select(2). *) - let in_chan = - let redirect_read ~redirect:(dst, src) ~read = - (* redirect *) - Unix.dup2 ~src ~dst ; Unix.in_channel_of_descr read - in - match action with - | ReadStdout -> - redirect_read ~redirect:(stderr, Unix.stderr) ~read:stdout - | ReadStderr -> - redirect_read ~redirect:(stdout, Unix.stdout) ~read:stderr + let redirected_fd_name, redirect_spec = + match action with ReadStderr -> ("stderr", "2>") | ReadStdout -> ("stdout", ">") + in + let output_file = + Filename.temp_file ~in_dir:(ResultsDir.get_path Temporary) prog redirected_fd_name + in + let escaped_cmd = List.map ~f:Escape.escape_shell (prog :: args) |> String.concat ~sep:" " in + let redirected_cmd = Printf.sprintf "exec %s %s'%s'" escaped_cmd redirect_spec output_file in + let {Unix.Process_info.stdin; stdout; stderr; pid} = + Unix.create_process ~prog:"sh" ~args:["-c"; redirected_cmd] in - let res = In_channel.input_all in_chan in + let fd_to_log, redirected_fd = + match action with ReadStderr -> (stdout, stderr) | ReadStdout -> (stderr, stdout) + in + let channel_to_log = Unix.in_channel_of_descr fd_to_log in + Utils.with_channel_in channel_to_log ~f:(L.progress "%s-%s: %s@." prog redirected_fd_name) ; + In_channel.close channel_to_log ; + Unix.close redirected_fd ; + Unix.close stdin ; match Unix.waitpid pid with | Ok () -> - Unix.close (Unix.descr_of_in_channel in_chan) ; - res + Utils.with_file_in output_file ~f:In_channel.input_all | Error _ as status -> L.die ExternalError "Error executing: %a@\n%s@\n" Pp.cli_args (prog :: args) (Unix.Exit_or_signal.to_string_hum status)