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 <toon@iotcl.com> Acked-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Toon Claes committed Jul 28, 2026 at 15:00 UTC 68cce04a028cac13fa1fd7a368801fac3d8b156b
2 files changed +22 -2
builtin/merge.c
+5 -2
@@ -1372,7 +1372,7 @@ int cmd_merge(int argc,
1372 struct commit_list *common = NULL;
1373 const char *best_strategy = NULL, *wt_strategy = NULL;
1374 struct commit_list *remoteheads = NULL, *p;
1375 - void *branch_to_free;
1375 + void *branch_to_free, *argv_to_free = NULL;
1376 int orig_argc = argc;
1377 int merge_log_config = -1;
1378
@@ -1516,8 +1516,10 @@ int cmd_merge(int argc,
1516 option_commit = 1;
1517
1518 if (!argc) {
1519 - if (default_to_upstream)
1519 + if (default_to_upstream) {
1520 argc = setup_with_upstream(&argv);
1521 + argv_to_free = argv;
1522 + }
1523 else
1524 die(_("No commit specified and merge.defaultToUpstream not set."));
1525 } else if (argc == 1 && !strcmp(argv[0], "-")) {
@@ -1885,6 +1887,7 @@ done:
1887 }
1888 strbuf_release(&buf);
1889 free(branch_to_free);
1890 + free(argv_to_free);
1891 free(pull_twohead);
1892 free(pull_octopus);
1893 discard_index(the_repository->index);
t/t7600-merge.sh
+17
@@ -1165,4 +1165,21 @@ test_expect_success 'suggested names are not ambiguous' '
1165 grep remotes/origin/not-local stderr
1166 '
1167
1168 +test_expect_success 'merge with no argument defaults to upstream' '
1169 + test_when_finished "rm -rf upstream downstream" &&
1170 + git init upstream &&
1171 + (
1172 + cd upstream &&
1173 + test_commit one &&
1174 + test_commit two
1175 + ) &&
1176 + git clone upstream downstream &&
1177 + (
1178 + cd downstream &&
1179 + git reset --hard HEAD^ &&
1180 + git merge &&
1181 + test_cmp_rev origin/main HEAD
1182 + )
1183 +'
1184 +
1185 test_done