]> git.ipfire.org Git - thirdparty/git.git/commitdiff
ref-filter: fix leak with %(describe) arguments
authorJeff King <peff@peff.net>
Mon, 9 Sep 2024 23:19:02 +0000 (19:19 -0400)
committerJunio C Hamano <gitster@pobox.com>
Mon, 9 Sep 2024 23:26:10 +0000 (16:26 -0700)
When we parse a %(describe) placeholder, we stuff its arguments into a
strvec, which is then detached into the used_atom struct. But later,
when ref_array_clear() frees the atom, we never free the memory.

To solve this, we just need to add the appropriate free() calls. But
it's a little awkward, since we have to free each element of the array,
in addition to the array itself. Instead, let's store the actual strvec,
which lets us do a simple strvec_clear().

This clears up one case that LSan finds in t6300, but there are more.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
ref-filter.c

index 54c5079dde103a51ea14415ff87aa55245b4f8ad..370cc5b44a68357b0a4fb1acfd37c42f51889695 100644 (file)
@@ -233,7 +233,7 @@ static struct used_atom {
                        enum { S_BARE, S_GRADE, S_SIGNER, S_KEY,
                               S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
                } signature;
-               const char **describe_args;
+               struct strvec describe_args;
                struct refname_atom refname;
                char *head;
        } u;
@@ -693,7 +693,7 @@ static int describe_atom_parser(struct ref_format *format UNUSED,
                                struct used_atom *atom,
                                const char *arg, struct strbuf *err)
 {
-       struct strvec args = STRVEC_INIT;
+       strvec_init(&atom->u.describe_args);
 
        for (;;) {
                int found = 0;
@@ -702,13 +702,12 @@ static int describe_atom_parser(struct ref_format *format UNUSED,
                if (!arg || !*arg)
                        break;
 
-               found = describe_atom_option_parser(&args, &arg, err);
+               found = describe_atom_option_parser(&atom->u.describe_args, &arg, err);
                if (found < 0)
                        return found;
                if (!found)
                        return err_bad_arg(err, "describe", bad_arg);
        }
-       atom->u.describe_args = strvec_detach(&args);
        return 0;
 }
 
@@ -1941,7 +1940,7 @@ static void grab_describe_values(struct atom_value *val, int deref,
 
                cmd.git_cmd = 1;
                strvec_push(&cmd.args, "describe");
-               strvec_pushv(&cmd.args, atom->u.describe_args);
+               strvec_pushv(&cmd.args, atom->u.describe_args.v);
                strvec_push(&cmd.args, oid_to_hex(&commit->object.oid));
                if (pipe_command(&cmd, NULL, 0, &out, 0, &err, 0) < 0) {
                        error(_("failed to run 'describe'"));
@@ -3004,6 +3003,8 @@ void ref_array_clear(struct ref_array *array)
                struct used_atom *atom = &used_atom[i];
                if (atom->atom_type == ATOM_HEAD)
                        free(atom->u.head);
+               else if (atom->atom_type == ATOM_DESCRIBE)
+                       strvec_clear(&atom->u.describe_args);
                else if (atom->atom_type == ATOM_TRAILERS ||
                         (atom->atom_type == ATOM_CONTENTS &&
                          atom->u.contents.option == C_TRAILERS)) {