From 86ed00640cb2c390e1a49e16342635cd621ae4df Mon Sep 17 00:00:00 2001 From: Ignas Mikalajunas Date: Wed, 6 Mar 2019 17:42:33 +0200 Subject: [PATCH] Set FD_CLOEXEC on stdin/out/err pipe fds in start_command This makes it possible to run more than one command started using start_command at the same time. When invoked start_command would create a set of pipes that it uses to communicate with the subprocess that was spawned, the git process that invoked start_command would own the file descriptors corresponding to the ends of the pipes pointing at stdout, stdin and stderr respectivelly. Which meant that if another process is spawned via fork + exec it would inherit all of those file descriptors from the git process, file descriptors that whatever process just got spawned by exec has no idea what to do with, which in some cases would cause the process that got spawned first to hang. For example, if git spawns two subprocesses A and B, and tries to shut down process A first, git closes the corresponding file descriptors, but as process B still has those same file descriptors pointing at the same pipes open, process A is still trying to read from those two pipes and not getting an EOF. Once this fix is applied - the process B does not inherit pipe descriptions, because this flag specifies that the file descriptor should be closed when an exec function is invoked. This makes running multiple commands safe. Signed-off-by: Ignas Mikalajunas --- run-command.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/run-command.c b/run-command.c index 3449db319b95d1..67149d61d8f30b 100644 --- a/run-command.c +++ b/run-command.c @@ -966,18 +966,24 @@ int start_command(struct child_process *cmd) return -1; } - if (need_in) + if (need_in) { close(fdin[0]); + set_cloexec(fdin[1]); + } else if (cmd->in) close(cmd->in); - if (need_out) + if (need_out) { close(fdout[1]); + set_cloexec(fdout[0]); + } else if (cmd->out) close(cmd->out); - if (need_err) + if (need_err) { close(fderr[1]); + set_cloexec(fderr[0]); + } else if (cmd->err) close(cmd->err);