diff options
author | Brandon Williams <bmwill@google.com> | 2017-04-19 16:13:19 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2017-04-20 17:55:32 -0700 |
commit | 3967e25be11ab96ced71f16b9f082de270a518db (patch) | |
tree | c9f8232ead9d4dfa5f6667054f1ab0decb1218f7 /run-command.c | |
parent | c2d3119d7bb2122a715d2adac1574514aeff7723 (diff) | |
download | git-3967e25be11ab96ced71f16b9f082de270a518db.tar.gz |
run-command: prepare command before forking
According to [1] we need to only call async-signal-safe operations between fork
and exec. Using malloc to build the argv array isn't async-signal-safe.
In order to avoid allocation between 'fork()' and 'exec()' prepare the
argv array used in the exec call prior to forking the process.
[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'run-command.c')
-rw-r--r-- | run-command.c | 46 |
1 files changed, 26 insertions, 20 deletions
diff --git a/run-command.c b/run-command.c index 574b81d3e8..d8d1437954 100644 --- a/run-command.c +++ b/run-command.c @@ -221,18 +221,6 @@ static const char **prepare_shell_cmd(struct argv_array *out, const char **argv) } #ifndef GIT_WINDOWS_NATIVE -static int execv_shell_cmd(const char **argv) -{ - struct argv_array nargv = ARGV_ARRAY_INIT; - prepare_shell_cmd(&nargv, argv); - trace_argv_printf(nargv.argv, "trace: exec:"); - sane_execvp(nargv.argv[0], (char **)nargv.argv); - argv_array_clear(&nargv); - return -1; -} -#endif - -#ifndef GIT_WINDOWS_NATIVE static int child_notifier = -1; static void notify_parent(void) @@ -244,6 +232,21 @@ static void notify_parent(void) */ xwrite(child_notifier, "", 1); } + +static void prepare_cmd(struct argv_array *out, const struct child_process *cmd) +{ + if (!cmd->argv[0]) + die("BUG: command is empty"); + + if (cmd->git_cmd) { + argv_array_push(out, "git"); + argv_array_pushv(out, cmd->argv); + } else if (cmd->use_shell) { + prepare_shell_cmd(out, cmd->argv); + } else { + argv_array_pushv(out, cmd->argv); + } +} #endif static inline void set_cloexec(int fd) @@ -372,9 +375,13 @@ fail_pipe: #ifndef GIT_WINDOWS_NATIVE { int notify_pipe[2]; + struct argv_array argv = ARGV_ARRAY_INIT; + if (pipe(notify_pipe)) notify_pipe[0] = notify_pipe[1] = -1; + prepare_cmd(&argv, cmd); + cmd->pid = fork(); failed_errno = errno; if (!cmd->pid) { @@ -437,12 +444,9 @@ fail_pipe: unsetenv(*cmd->env); } } - if (cmd->git_cmd) - execv_git_cmd(cmd->argv); - else if (cmd->use_shell) - execv_shell_cmd(cmd->argv); - else - sane_execvp(cmd->argv[0], (char *const*) cmd->argv); + + sane_execvp(argv.argv[0], (char *const *) argv.argv); + if (errno == ENOENT) { if (!cmd->silent_exec_failure) error("cannot run %s: %s", cmd->argv[0], @@ -458,7 +462,7 @@ fail_pipe: mark_child_for_cleanup(cmd->pid, cmd); /* - * Wait for child's execvp. If the execvp succeeds (or if fork() + * Wait for child's exec. If the exec succeeds (or if fork() * failed), EOF is seen immediately by the parent. Otherwise, the * child process sends a single byte. * Note that use of this infrastructure is completely advisory, @@ -467,7 +471,7 @@ fail_pipe: close(notify_pipe[1]); if (read(notify_pipe[0], ¬ify_pipe[1], 1) == 1) { /* - * At this point we know that fork() succeeded, but execvp() + * At this point we know that fork() succeeded, but exec() * failed. Errors have been reported to our stderr. */ wait_or_whine(cmd->pid, cmd->argv[0], 0); @@ -475,6 +479,8 @@ fail_pipe: cmd->pid = -1; } close(notify_pipe[0]); + + argv_array_clear(&argv); } #else { |