run-command: store an optional argv_array
authorJeff King <peff@peff.net>
Thu, 15 May 2014 08:33:26 +0000 (04:33 -0400)
committerJunio C Hamano <gitster@pobox.com>
Thu, 15 May 2014 16:49:09 +0000 (09:49 -0700)
All child_process structs need to point to an argv. For
flexibility, we do not mandate the use of a dynamic
argv_array. However, because the child_process does not own
the memory, this can make memory management with a
separate argv_array difficult.

For example, if a function calls start_command but not
finish_command, the argv memory must persist. The code needs
to arrange to clean up the argv_array separately after
finish_command runs. As a result, some of our code in this
situation just leaks the memory.

To help such cases, this patch adds a built-in argv_array to
the child_process, which gets cleaned up automatically (both
in finish_command and when start_command fails). Callers
may use it if they choose, but can continue to use the raw
argv if they wish.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/technical/api-run-command.txt
run-command.c
run-command.h
index 5d7d7f2d32f58f8682ca5efb2fd98fe7e74247dd..69510ae57afcedbe13334160c6a26c52c42e8d54 100644 (file)
@@ -109,6 +109,13 @@ terminated), of which .argv[0] is the program name to run (usually
 without a path). If the command to run is a git command, set argv[0] to
 the command name without the 'git-' prefix and set .git_cmd = 1.
 
+Note that the ownership of the memory pointed to by .argv stays with the
+caller, but it should survive until `finish_command` completes. If the
+.argv member is NULL, `start_command` will point it at the .args
+`argv_array` (so you may use one or the other, but you must use exactly
+one). The memory in .args will be cleaned up automatically during
+`finish_command` (or during `start_command` when it is unsuccessful).
+
 The members .in, .out, .err are used to redirect stdin, stdout,
 stderr as follows:
 
index 75abc478c6da75471e5fdbb55c74efdfcf3ad160..be07d4ad335ba6df4653239b7ccd6930c91c9879 100644 (file)
@@ -279,6 +279,9 @@ int start_command(struct child_process *cmd)
        int failed_errno;
        char *str;
 
+       if (!cmd->argv)
+               cmd->argv = cmd->args.argv;
+
        /*
         * In case of errors we must keep the promise to close FDs
         * that have been passed in via ->in and ->out.
@@ -328,6 +331,7 @@ int start_command(struct child_process *cmd)
 fail_pipe:
                        error("cannot create %s pipe for %s: %s",
                                str, cmd->argv[0], strerror(failed_errno));
+                       argv_array_clear(&cmd->args);
                        errno = failed_errno;
                        return -1;
                }
@@ -519,6 +523,7 @@ int start_command(struct child_process *cmd)
                        close_pair(fderr);
                else if (cmd->err)
                        close(cmd->err);
+               argv_array_clear(&cmd->args);
                errno = failed_errno;
                return -1;
        }
@@ -543,7 +548,9 @@ int start_command(struct child_process *cmd)
 
 int finish_command(struct child_process *cmd)
 {
-       return wait_or_whine(cmd->pid, cmd->argv[0]);
+       int ret = wait_or_whine(cmd->pid, cmd->argv[0]);
+       argv_array_clear(&cmd->args);
+       return ret;
 }
 
 int run_command(struct child_process *cmd)
index 3653bfa6e123ca8497571a2ca1c47200c1b544a2..ea73de309bc65c3d00bb34ad84824ba72d85cbfe 100644 (file)
@@ -5,8 +5,11 @@
 #include <pthread.h>
 #endif
 
+#include "argv-array.h"
+
 struct child_process {
        const char **argv;
+       struct argv_array args;
        pid_t pid;
        /*
         * Using .in, .out, .err: