]> git.ipfire.org Git - thirdparty/git.git/commitdiff
builtin/merge-recursive: fix leaking object ID bases
authorPatrick Steinhardt <ps@pks.im>
Tue, 11 Jun 2024 09:20:09 +0000 (11:20 +0200)
committerJunio C Hamano <gitster@pobox.com>
Tue, 11 Jun 2024 20:15:06 +0000 (13:15 -0700)
In `cmd_merge_recursive()` we have a static array of object ID bases
that we pass to `merge_recursive_generic()`. This interface is somewhat
weird though because the latter function accepts a pointer to a pointer
of object IDs, which requires us to allocate the object IDs on the heap.
And as we never free those object IDs, the end result is a leak.

While we can easily solve this leak by just freeing the respective
object IDs, the whole calling convention is somewhat weird. Instead,
refactor `merge_recursive_generic()` to accept a plain pointer to object
IDs so that we can avoid allocating them altogether.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/am.c
builtin/merge-recursive.c
merge-recursive.c
merge-recursive.h
t/t6432-merge-recursive-space-options.sh
t/t6434-merge-recursive-rename-options.sh

index 36839029d201c382e3bc878ace99bcd73ff17e28..4ba44e2d70619b7e017f75e50374f42b33119ffc 100644 (file)
@@ -1573,8 +1573,8 @@ static int build_fake_ancestor(const struct am_state *state, const char *index_f
  */
 static int fall_back_threeway(const struct am_state *state, const char *index_path)
 {
-       struct object_id orig_tree, their_tree, our_tree;
-       const struct object_id *bases[1] = { &orig_tree };
+       struct object_id their_tree, our_tree;
+       struct object_id bases[1] = { 0 };
        struct merge_options o;
        struct commit *result;
        char *their_tree_name;
@@ -1588,7 +1588,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
        discard_index(the_repository->index);
        read_index_from(the_repository->index, index_path, get_git_dir());
 
-       if (write_index_as_tree(&orig_tree, the_repository->index, index_path, 0, NULL))
+       if (write_index_as_tree(&bases[0], the_repository->index, index_path, 0, NULL))
                return error(_("Repository lacks necessary blobs to fall back on 3-way merge."));
 
        say(state, stdout, _("Using index info to reconstruct a base tree..."));
index c2ce044a201366d7eea11ab3d2eeed2c15113af4..82bebea15b3fd034fc590b115d92418def143040 100644 (file)
@@ -23,7 +23,7 @@ static char *better_branch_name(const char *branch)
 
 int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED)
 {
-       const struct object_id *bases[21];
+       struct object_id bases[21];
        unsigned bases_count = 0;
        int i, failed;
        struct object_id h1, h2;
@@ -49,10 +49,8 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix UNUSED)
                        continue;
                }
                if (bases_count < ARRAY_SIZE(bases)-1) {
-                       struct object_id *oid = xmalloc(sizeof(struct object_id));
-                       if (repo_get_oid(the_repository, argv[i], oid))
+                       if (repo_get_oid(the_repository, argv[i], &bases[bases_count++]))
                                die(_("could not parse object '%s'"), argv[i]);
-                       bases[bases_count++] = oid;
                }
                else
                        warning(Q_("cannot handle more than %d base. "
index 8c8e8b4868b7b11e67d8250e380c62f55b2f8a80..eff73dac02e6501b26dfc264aa6059e6f8565df0 100644 (file)
@@ -3866,7 +3866,7 @@ int merge_recursive_generic(struct merge_options *opt,
                            const struct object_id *head,
                            const struct object_id *merge,
                            int num_merge_bases,
-                           const struct object_id **merge_bases,
+                           const struct object_id *merge_bases,
                            struct commit **result)
 {
        int clean;
@@ -3879,10 +3879,10 @@ int merge_recursive_generic(struct merge_options *opt,
                int i;
                for (i = 0; i < num_merge_bases; ++i) {
                        struct commit *base;
-                       if (!(base = get_ref(opt->repo, merge_bases[i],
-                                            oid_to_hex(merge_bases[i]))))
+                       if (!(base = get_ref(opt->repo, &merge_bases[i],
+                                            oid_to_hex(&merge_bases[i]))))
                                return err(opt, _("Could not parse object '%s'"),
-                                          oid_to_hex(merge_bases[i]));
+                                          oid_to_hex(&merge_bases[i]));
                        commit_list_insert(base, &ca);
                }
                if (num_merge_bases == 1)
index e67d38c30305de9fc34b37dcdcb3f345b1cf97b4..839eb6436e48944b7df75eb82660c025ee0384e0 100644 (file)
@@ -123,7 +123,7 @@ int merge_recursive_generic(struct merge_options *opt,
                            const struct object_id *head,
                            const struct object_id *merge,
                            int num_merge_bases,
-                           const struct object_id **merge_bases,
+                           const struct object_id *merge_bases,
                            struct commit **result);
 
 #endif
index db4b77e63d23c469d8d7a012bb83df99d1600400..c93538b0c38462f18613a493c364fdff531be862 100755 (executable)
@@ -14,6 +14,7 @@ test_description='merge-recursive space options
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b
index a11707835b4abe69b200b50f01af797733cc4bdc..df1d0c156c54a3ce0f96557e882435136862b4d8 100755 (executable)
@@ -29,6 +29,7 @@ mentions this in a different context).
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 get_expected_stages () {