ref-filter: fix leak with %(describe) arguments

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>
maint
Jeff King 2024-09-09 19:19:02 -04:00 committed by Junio C Hamano
parent f6ba781903
commit ec007cde94
1 changed files with 6 additions and 5 deletions

View File

@ -233,7 +233,7 @@ static struct used_atom {
enum { S_BARE, S_GRADE, S_SIGNER, S_KEY, enum { S_BARE, S_GRADE, S_SIGNER, S_KEY,
S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option; S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
} signature; } signature;
const char **describe_args; struct strvec describe_args;
struct refname_atom refname; struct refname_atom refname;
char *head; char *head;
} u; } u;
@ -693,7 +693,7 @@ static int describe_atom_parser(struct ref_format *format UNUSED,
struct used_atom *atom, struct used_atom *atom,
const char *arg, struct strbuf *err) const char *arg, struct strbuf *err)
{ {
struct strvec args = STRVEC_INIT; strvec_init(&atom->u.describe_args);


for (;;) { for (;;) {
int found = 0; int found = 0;
@ -702,13 +702,12 @@ static int describe_atom_parser(struct ref_format *format UNUSED,
if (!arg || !*arg) if (!arg || !*arg)
break; break;


found = describe_atom_option_parser(&args, &arg, err); found = describe_atom_option_parser(&atom->u.describe_args, &arg, err);
if (found < 0) if (found < 0)
return found; return found;
if (!found) if (!found)
return err_bad_arg(err, "describe", bad_arg); return err_bad_arg(err, "describe", bad_arg);
} }
atom->u.describe_args = strvec_detach(&args);
return 0; return 0;
} }


@ -1941,7 +1940,7 @@ static void grab_describe_values(struct atom_value *val, int deref,


cmd.git_cmd = 1; cmd.git_cmd = 1;
strvec_push(&cmd.args, "describe"); 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)); strvec_push(&cmd.args, oid_to_hex(&commit->object.oid));
if (pipe_command(&cmd, NULL, 0, &out, 0, &err, 0) < 0) { if (pipe_command(&cmd, NULL, 0, &out, 0, &err, 0) < 0) {
error(_("failed to run 'describe'")); error(_("failed to run 'describe'"));
@ -3004,6 +3003,8 @@ void ref_array_clear(struct ref_array *array)
struct used_atom *atom = &used_atom[i]; struct used_atom *atom = &used_atom[i];
if (atom->atom_type == ATOM_HEAD) if (atom->atom_type == ATOM_HEAD)
free(atom->u.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 || else if (atom->atom_type == ATOM_TRAILERS ||
(atom->atom_type == ATOM_CONTENTS && (atom->atom_type == ATOM_CONTENTS &&
atom->u.contents.option == C_TRAILERS)) { atom->u.contents.option == C_TRAILERS)) {