git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [BUG] git stash show -p with invalid option aborts with double-free in show_stash() (strvec_clear)

From
Junio C Hamano <gitster@pobox.com>
Date
Sep 19, 2025, 16:00 UTC
Message-ID
<xmqq4isy77qr.fsf@gitster.g>
In-Reply-To
<1321ff39-6f09-426a-aa75-939ef4e1ad93@app.fastmail.com>
"Kristoffer Haugsbakk" <kristofferhaugsbakk@fastmail.com> writes:
Show 6 quoted lines
>> 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).
Previous: Kristoffer HaugsbakkNext: Jeff King
Message 3 of 26 in “[BUG] git stash show -p with invalid option aborts with double-free in show_stash() (strvec_clear)”
  1. Lauri NiskanenSep 19, 2025
  2. Kristoffer HaugsbakkSep 19, 2025
  3. Junio C HamanoSep 19, 2025
  4. Jeff KingSep 19, 2025
  5. Junio C HamanoSep 19, 2025
  6. Junio C HamanoSep 19, 2025
  7. Jeff KingSep 19, 2025
  8. Junio C HamanoSep 19, 2025
  9. Jeff KingSep 19, 2025
  10. 0/6 fixing double-frees and leaks via setup_revisions()Jeff King, Sep 19, 2025
  11. 1/6 stash: tell setup_revisions() to free our allocated stringsJeff King, Sep 19, 2025
  12. Junio C HamanoSep 22, 2025
  13. Jeff KingSep 22, 2025
  14. Junio C HamanoSep 22, 2025
  15. Jeff KingSep 22, 2025
  16. Junio C HamanoSep 22, 2025
  17. Jeff KingSep 23, 2025
  18. 2/6 revision: manage memory ownership of argv in setup_revisions()Jeff King, Sep 19, 2025
  19. 3/6 revision: add wrapper to setup_revisions() from a strvecJeff King, Sep 19, 2025
  20. Eric SunshineSep 20, 2025
  21. Jeff KingSep 20, 2025
  22. 4/6 treewide: use setup_revisions_from_strvec() when we have a strvecJeff King, Sep 19, 2025
  23. 5/6 treewide: pass strvecs around for setup_revisions_from_strvec()Jeff King, Sep 19, 2025
  24. Jeff KingSep 19, 2025
  25. 6/6 revision: retain argv NULL invariant in setup_revisions()Jeff King, Sep 19, 2025
  26. Jeff KingSep 19, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.