summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrandon Williams <bmwill@google.com>2017-04-19 23:13:19 (GMT)
committerJunio C Hamano <gitster@pobox.com>2017-04-21 00:55:32 (GMT)
commit3967e25be11ab96ced71f16b9f082de270a518db (patch)
treec9f8232ead9d4dfa5f6667054f1ab0decb1218f7
parentc2d3119d7bb2122a715d2adac1574514aeff7723 (diff)
downloadgit-3967e25be11ab96ced71f16b9f082de270a518db.zip
git-3967e25be11ab96ced71f16b9f082de270a518db.tar.gz
git-3967e25be11ab96ced71f16b9f082de270a518db.tar.bz2
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>
-rw-r--r--run-command.c46
1 files changed, 26 insertions, 20 deletions
diff --git a/run-command.c b/run-command.c
index 574b81d..d8d1437 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], &notify_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
{