From: Toon Claes Date: Tue, 28 Jul 2026 13:00:04 +0000 (+0200) Subject: merge: fix leak with merge.defaultToUpstream X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=68cce04a028cac13fa1fd7a368801fac3d8b156b;p=thirdparty%2Fgit.git merge: fix leak with merge.defaultToUpstream By default the setting 'merge.defaultToUpstream' for git-merge(1) is set to 'true', which means when `git merge` is invoked with no arguments it merges the upstream branch configured for the current branch. With this configuration set to 'true', setup_with_upstream() is called. That function allocates an array of arguments and hands it back to cmd_merge() via its `argv` parameter. This array is never freed, so cmd_merge() leaks it on every invocation. Track the allocated array in a separate variable and free it at the end. The leak has been present since 93e535a5b7 (merge: merge with the default upstream branch without argument, 2011-03-24). Although the leak sanitizer was enabled for tests in fc1ddf42af (t: remove TEST_PASSES_SANITIZE_LEAK annotations, 2024-11-21), it went unnoticed because no test calls `git merge` without arguments, exercising the default-to-upstream path. Add such a test in t7600, which fails under the leak sanitizer without this fix. Signed-off-by: Toon Claes Acked-by: Jeff King Signed-off-by: Junio C Hamano --- diff --git a/builtin/merge.c b/builtin/merge.c index 2cbce56f8d..ecd7a897d0 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -1372,7 +1372,7 @@ int cmd_merge(int argc, struct commit_list *common = NULL; const char *best_strategy = NULL, *wt_strategy = NULL; struct commit_list *remoteheads = NULL, *p; - void *branch_to_free; + void *branch_to_free, *argv_to_free = NULL; int orig_argc = argc; int merge_log_config = -1; @@ -1516,8 +1516,10 @@ int cmd_merge(int argc, option_commit = 1; if (!argc) { - if (default_to_upstream) + if (default_to_upstream) { argc = setup_with_upstream(&argv); + argv_to_free = argv; + } else die(_("No commit specified and merge.defaultToUpstream not set.")); } else if (argc == 1 && !strcmp(argv[0], "-")) { @@ -1885,6 +1887,7 @@ done: } strbuf_release(&buf); free(branch_to_free); + free(argv_to_free); free(pull_twohead); free(pull_octopus); discard_index(the_repository->index); diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index 9838094b66..b3a2164e08 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -1165,4 +1165,21 @@ test_expect_success 'suggested names are not ambiguous' ' grep remotes/origin/not-local stderr ' +test_expect_success 'merge with no argument defaults to upstream' ' + test_when_finished "rm -rf upstream downstream" && + git init upstream && + ( + cd upstream && + test_commit one && + test_commit two + ) && + git clone upstream downstream && + ( + cd downstream && + git reset --hard HEAD^ && + git merge && + test_cmp_rev origin/main HEAD + ) +' + test_done