From: Junio C Hamano <gitster@pobox.com>
To: "Kristoffer Haugsbakk" <kristofferhaugsbakk@fastmail.com>
Cc: "Lauri Niskanen" <ape@ape3000.com>,
git@vger.kernel.org, "Patrick Steinhardt" <ps@pks.im>
Subject: Re: [BUG] git stash show -p with invalid option aborts with double-free in show_stash() (strvec_clear)
Date: Fri, 19 Sep 2025 09:00:12 -0700 [thread overview]
Message-ID: <xmqq4isy77qr.fsf@gitster.g> (raw)
In-Reply-To: <1321ff39-6f09-426a-aa75-939ef4e1ad93@app.fastmail.com> (Kristoffer Haugsbakk's message of "Fri, 19 Sep 2025 15:11:41 +0200")
"Kristoffer Haugsbakk" <kristofferhaugsbakk@fastmail.com> writes:
>> What happened instead?
>>
>> free(): double free detected in tcache 2
>
> This bisects to 748bd094 (builtin/stash: fix leak in `show_stash()`,
> 2024-06-11) for me.
Good eyes, both of you.
This comes from the fact that the program calls setup_revisions() on
the "rest of the command line args" and have it parse as much as it
understands, while leaving the remainder that it did not understand
there, with this call.
argc = setup_revisions(revision_args.nr, revision_args.v, &rev, NULL);
if (argc > 1)
goto usage;
If you give "git stash show -p --no-such-option", revision_args
before setup_revisions() is called would have
.v = { "show", "-p", "--no-such-option", NULL }
and upon returning from the call, we would have
.v = { "show", "--no-such-option", "--no-such-option", NULL }
with argc == 2. Note that .nr is only passed by value, so across
the call to setup_revisions(), it will stay .nr == 3.
This mongering of .v[] is because the callee parses out and removes
"-p" as an argv element that it understood shifting the remainder in
the array, with the expectation that the caller would use the array
it passed (i.e. .v[]) and the return value from the call (i.e. 2 in
argc) for further processing. It is not getting the strvec and no
access to .nr to adjust, so this is close to the best it can do.
So there are two ways to fix this.
The easier, more performant, and closer to the original design
around the revisions API is to do this:
diff --git c/builtin/stash.c w/builtin/stash.c
index f5ddee5c7f..b6312b1b70 100644
--- c/builtin/stash.c
+++ w/builtin/stash.c
@@ -1016,6 +1016,8 @@ static int show_stash(int argc, const char **argv, const char *prefix,
}
argc = setup_revisions(revision_args.nr, revision_args.v, &rev, NULL);
+ for (i = argc; i < revision_args.nr; i++)
+ revision_args.v[i] = NULL;
if (argc > 1)
goto usage;
if (!rev.diffopt.output_format) {
A less performant but may in the longer term safer alternative is to
change the caller-callee contract around setup_revisions() so that
the later "unused" slots in the argv array is NULLed before
returning to the caller, i.e. instead of leaving
.v = { "show", "--no-such-option", "--no-such-option", NULL }
in the revision_args.v[] array, teach setup_revisions() to leave
.v = { "show", "--no-such-option", NULL, NULL }
there (again, we cannot do anything about .nr that is only available
to the caller).
next prev parent reply other threads:[~2025-09-19 16:00 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-19 10:18 [BUG] git stash show -p with invalid option aborts with double-free in show_stash() (strvec_clear) Lauri Niskanen
2025-09-19 13:11 ` Kristoffer Haugsbakk
2025-09-19 16:00 ` Junio C Hamano [this message]
2025-09-19 16:48 ` Jeff King
2025-09-19 17:13 ` Junio C Hamano
2025-09-19 16:58 ` Junio C Hamano
2025-09-19 17:20 ` Jeff King
2025-09-19 18:15 ` Junio C Hamano
2025-09-19 19:56 ` Jeff King
2025-09-19 22:33 ` [PATCH 0/6] fixing double-frees and leaks via setup_revisions() Jeff King
2025-09-19 22:40 ` [PATCH 1/6] stash: tell setup_revisions() to free our allocated strings Jeff King
2025-09-22 15:45 ` Junio C Hamano
2025-09-22 19:05 ` Jeff King
2025-09-22 19:36 ` Junio C Hamano
2025-09-22 20:25 ` Jeff King
2025-09-22 21:26 ` Junio C Hamano
2025-09-23 0:48 ` Jeff King
2025-09-19 22:45 ` [PATCH 2/6] revision: manage memory ownership of argv in setup_revisions() Jeff King
2025-09-19 22:48 ` [PATCH 3/6] revision: add wrapper to setup_revisions() from a strvec Jeff King
2025-09-20 5:10 ` Eric Sunshine
2025-09-20 5:48 ` Jeff King
2025-09-19 22:49 ` [PATCH 4/6] treewide: use setup_revisions_from_strvec() when we have " Jeff King
2025-09-19 22:50 ` [PATCH 5/6] treewide: pass strvecs around for setup_revisions_from_strvec() Jeff King
2025-09-19 23:11 ` Jeff King
2025-09-19 22:51 ` [PATCH 6/6] revision: retain argv NULL invariant in setup_revisions() Jeff King
2025-09-19 23:07 ` Jeff King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=xmqq4isy77qr.fsf@gitster.g \
--to=gitster@pobox.com \
--cc=ape@ape3000.com \
--cc=git@vger.kernel.org \
--cc=kristofferhaugsbakk@fastmail.com \
--cc=ps@pks.im \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).