On Thu, Nov 25, 2021 at 5:52 PM Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> wrote: > From: Eric Sunshine <sunshine@xxxxxxxxxxxxxx> > > add_worktree() reuses a `child_process` for three run_command() > invocations, but to do so, it has overly-intimate knowledge of > run-command.c internals. In particular, it knows that it must reset > child_process::argv to NULL for each subsequent invocation[*] in order > for start_command() to latch the newly-populated child_process::args for > each invocation, even though this behavior is not a part of the > documented API. Beyond having overly-intimate knowledge of run-command.c > internals, the reuse of one `child_process` for three run_command() > invocations smells like an unnecessary micro-optimization. Therefore, > stop sharing one `child_process` and instead use a new one for each > run_command() call. If people feel uncomfortable with the way this patch shadows `cp` in nested blocks, an alternative would be to call child_process_init(&cp) to reuse the existing `cp`, similar to the fix[1] applied to pager.c when reusing a `child_process`. I don't feel strongly about it either way. [1]: https://lore.kernel.org/git/20211125000239.2336-1-ematsumiya@xxxxxxx/ > [*] If child_process::argv is not reset to NULL, then subsequent > run_command() invocations will instead incorrectly access a dangling > pointer to freed memory which had been allocated by child_process::args > on the previous run. This is due to the following code in > start_command(): > > if (!cmd->argv) > cmd->argv = cmd->args.v; > > Signed-off-by: Eric Sunshine <sunshine@xxxxxxxxxxxxxx> > Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> > --- > builtin/worktree.c | 7 +++---- > 1 file changed, 3 insertions(+), 4 deletions(-) > > diff --git a/builtin/worktree.c b/builtin/worktree.c > index d22ece93e1a..9edd3e2829b 100644 > --- a/builtin/worktree.c > +++ b/builtin/worktree.c > @@ -355,8 +355,8 @@ static int add_worktree(const char *path, const char *refname, > goto done; > > if (opts->checkout) { > - cp.argv = NULL; > - strvec_clear(&cp.args); > + struct child_process cp = CHILD_PROCESS_INIT; > + cp.git_cmd = 1; > strvec_pushl(&cp.args, "reset", "--hard", "--no-recurse-submodules", NULL); > if (opts->quiet) > strvec_push(&cp.args, "--quiet"); > @@ -385,12 +385,11 @@ static int add_worktree(const char *path, const char *refname, > const char *hook = find_hook("post-checkout"); > if (hook) { > const char *env[] = { "GIT_DIR", "GIT_WORK_TREE", NULL }; > - cp.git_cmd = 0; > + struct child_process cp = CHILD_PROCESS_INIT; > cp.no_stdin = 1; > cp.stdout_to_stderr = 1; > cp.dir = path; > cp.env = env; > - cp.argv = NULL; > cp.trace2_hook_name = "post-checkout"; > strvec_pushl(&cp.args, absolute_path(hook), > oid_to_hex(null_oid()), > -- > 2.34.1.838.g779e9098efb