]> git.ipfire.org Git - thirdparty/git.git/commitdiff
builtin/fast-export: plug leaking tag names
authorPatrick Steinhardt <ps@pks.im>
Wed, 14 Aug 2024 06:52:31 +0000 (08:52 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 14 Aug 2024 17:07:59 +0000 (10:07 -0700)
When resolving revisions in `get_tags_and_duplicates()`, we only
partially manage the lifetime of `full_name`. In fact, managing its
lifetime properly is almost impossible because we put direct pointers to
that variable into multiple lists without duplicating the string. The
consequence is that these strings will ultimately leak.

Refactor the code to make the lists we put those names into duplicate
the memory. This allows us to properly free the string as required and
thus plugs the memory leak.

While this requires us to allocate more data overall, it shouldn't be
all that bad given that the number of allocations corresponds with the
number of command line parameters, which typically aren't all that many.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/fast-export.c
t/t9351-fast-export-anonymize.sh

index fe92d2436cf1b1b7ce470b3409f0e958d388ae00..f253b79322a4d8f3ecaf2b6fd695a10bdbcc5e7b 100644 (file)
@@ -42,8 +42,8 @@ static int full_tree;
 static int reference_excluded_commits;
 static int show_original_ids;
 static int mark_tags;
-static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
-static struct string_list tag_refs = STRING_LIST_INIT_NODUP;
+static struct string_list extra_refs = STRING_LIST_INIT_DUP;
+static struct string_list tag_refs = STRING_LIST_INIT_DUP;
 static struct refspec refspecs = REFSPEC_INIT_FETCH;
 static int anonymize;
 static struct hashmap anonymized_seeds;
@@ -901,7 +901,7 @@ static void handle_tag(const char *name, struct tag *tag)
        free(buf);
 }
 
-static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
+static struct commit *get_commit(struct rev_cmdline_entry *e, const char *full_name)
 {
        switch (e->item->type) {
        case OBJ_COMMIT:
@@ -932,14 +932,16 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
                struct rev_cmdline_entry *e = info->rev + i;
                struct object_id oid;
                struct commit *commit;
-               char *full_name;
+               char *full_name = NULL;
 
                if (e->flags & UNINTERESTING)
                        continue;
 
                if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
-                                 &oid, &full_name, 0) != 1)
+                                 &oid, &full_name, 0) != 1) {
+                       free(full_name);
                        continue;
+               }
 
                if (refspecs.nr) {
                        char *private;
@@ -955,6 +957,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
                        warning("%s: Unexpected object of type %s, skipping.",
                                e->name,
                                type_name(e->item->type));
+                       free(full_name);
                        continue;
                }
 
@@ -963,10 +966,12 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
                        break;
                case OBJ_BLOB:
                        export_blob(&commit->object.oid);
+                       free(full_name);
                        continue;
                default: /* OBJ_TAG (nested tags) is already handled */
                        warning("Tag points to object of unexpected type %s, skipping.",
                                type_name(commit->object.type));
+                       free(full_name);
                        continue;
                }
 
@@ -979,6 +984,8 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
 
                if (!*revision_sources_at(&revision_sources, commit))
                        *revision_sources_at(&revision_sources, commit) = full_name;
+               else
+                       free(full_name);
        }
 
        string_list_sort(&extra_refs);
index 156a6474847cf6e5bc86df2212ce98211986e6d6..c0d9d7be754d5758f25d0f629a7c98fd37d5cdaa 100755 (executable)
@@ -4,6 +4,7 @@ test_description='basic tests for fast-export --anonymize'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 test_expect_success 'setup simple repo' '