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

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

From
LNLauri Niskanen <ape@ape3000.com>
Date
Sep 19, 2025, 10:18 UTC
Message-ID
<CAMCKZdV+ASXAhYXaTdtB=7YZprCxFUjwEsqQP7i_ccOwx8Lo6Q@mail.gmail.com>
What did you do before the bug happened?

Create a repo and a stash entry, then invoke `git stash show -p` with an invalid option:

git init repro cd repro touch a git add a git commit -m init echo x >> a git stash git stash show -p --invalid

What did you expect to happen?
Git should print a usage / option error and exit cleanly without crashing.
What happened instead?
free(): double free detected in tcache 2

GDB backtrace: #0 __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44 #1 0x00007ffff7c98a13 in __pthread_kill_internal (threadid=<optimized out>, signo=6) at pthread_kill.c:89 #2 0x00007ffff7c3e410 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26 #3 0x00007ffff7c2557a in __GI_abort () at abort.c:77 #4 0x00007ffff7c26613 in __libc_message_impl (fmt=fmt@entry=0x7ffff7db4355 "%s\n") at ../sysdeps/posix/libc_fatal.c:138 #5 0x00007ffff7ca2d65 in malloc_printerr (str=str@entry=0x7ffff7db7d78 "free(): double free detected in tcache 2") at malloc.c:5892 #6 0x00007ffff7ca82e8 in tcache_double_free_verify (e=<optimized out>) at malloc.c:3350 #7 0x00007ffff7ca80a5 in __GI___libc_free (mem=<optimized out>) at malloc.c:3547 #8 0x00005555558570ce in strvec_clear (array=0x7fffffffc580) at /usr/src/debug/git/git/strvec.c:134 #9 0x000055555567d9f9 in show_stash (argc=<optimized out>, argv=<optimized out>, prefix=<optimized out>, repo=<optimized out>) at builtin/stash.c:1047 #10 0x0000555555686f25 in cmd_stash (argc=3, argv=0x5555559bd260, prefix=0x0, repo=0x555555992ae0 <the_repo.lto_priv>) at builtin/stash.c:2410 #11 0x000055555555fd43 in run_builtin (p=0x555555984698 <commands.lto_priv+2904>, argc=<optimized out>, argv=<optimized out>, repo=0x555555992ae0 <the_repo.lto_priv>) at /usr/src/debug/git/git/git.c:480 #12 handle_builtin (args=args@entry=0x7fffffffe1d0) at /usr/src/debug/git/git/git.c:746 #13 0x00005555555608a2 in run_argv (args=0x7fffffffe1d0) at /usr/src/debug/git/git/git.c:813 #14 cmd_main (argc=<optimized out>, argv=<optimized out>) at /usr/src/debug/git/git/git.c:953 #15 0x000055555555d784 in main (argc=5, argv=0x7fffffffe518) at /usr/src/debug/git/git/common-main.c:9

Valgrind: ==2507916== Memcheck, a memory error detector ==2507916== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al. ==2507916== Using Valgrind-3.25.1 and LibVEX; rerun with -h for copyright info ==2507916== Command: git stash show -p --invalid ==2507916== ==2507916== Invalid free() / delete / delete[] / realloc() ==2507916== at 0x4CB18EF: free (vg_replace_malloc.c:989) ==2507916== by 0x43030CD: strvec_clear (strvec.c:134) ==2507916== by 0x41299F8: show_stash.lto_priv.0 (stash.c:1047) ==2507916== by 0x4132F24: cmd_stash (stash.c:2410) ==2507916== by 0x400BD42: UnknownInlinedFun (git.c:480) ==2507916== by 0x400BD42: handle_builtin (git.c:746) ==2507916== by 0x400C8A1: UnknownInlinedFun (git.c:813) ==2507916== by 0x400C8A1: cmd_main (git.c:953) ==2507916== by 0x4009783: main (common-main.c:9) ==2507916== Address 0x4ff4540 is 0 bytes inside a block of size 8 free'd ==2507916== at 0x4CB18EF: free (vg_replace_malloc.c:989) ==2507916== by 0x43030CD: strvec_clear (strvec.c:134) ==2507916== by 0x41299F8: show_stash.lto_priv.0 (stash.c:1047) ==2507916== by 0x4132F24: cmd_stash (stash.c:2410) ==2507916== by 0x400BD42: UnknownInlinedFun (git.c:480) ==2507916== by 0x400BD42: handle_builtin (git.c:746) ==2507916== by 0x400C8A1: UnknownInlinedFun (git.c:813) ==2507916== by 0x400C8A1: cmd_main (git.c:953) ==2507916== by 0x4009783: main (common-main.c:9) ==2507916== Block was alloc'd at ==2507916== at 0x4CAE7A8: malloc (vg_replace_malloc.c:446) ==2507916== by 0x4E6E2AF: strdup (strdup.c:42) ==2507916== by 0x4129624: UnknownInlinedFun (wrapper.c:43) ==2507916== by 0x4129624: UnknownInlinedFun (strvec.c:25) ==2507916== by 0x4129624: show_stash.lto_priv.0 (stash.c:994) ==2507916== by 0x4132F24: cmd_stash (stash.c:2410) ==2507916== by 0x400BD42: UnknownInlinedFun (git.c:480) ==2507916== by 0x400BD42: handle_builtin (git.c:746) ==2507916== by 0x400C8A1: UnknownInlinedFun (git.c:813) ==2507916== by 0x400C8A1: cmd_main (git.c:953) ==2507916== by 0x4009783: main (common-main.c:9) ==2507916== usage: git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]

    -u, --[no-]include-untracked
                          include untracked files in the stash
    --only-untracked      only show untracked files in the stash

==2507916== ==2507916== HEAP SUMMARY: ==2507916== in use at exit: 696,349 bytes in 371 blocks ==2507916== total heap usage: 750 allocs, 380 frees, 1,221,944 bytes allocated ==2507916== ==2507916== LEAK SUMMARY: ==2507916== definitely lost: 3 bytes in 1 blocks ==2507916== indirectly lost: 0 bytes in 0 blocks ==2507916== possibly lost: 120 bytes in 3 blocks ==2507916== still reachable: 696,226 bytes in 367 blocks ==2507916== suppressed: 0 bytes in 0 blocks ==2507916== Rerun with --leak-check=full to see details of leaked memory ==2507916== ==2507916== For lists of detected and suppressed errors, rerun with: -s ==2507916== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

[System Info]
git version:
git version 2.51.0
cpu: x86_64
built from commit: c44beea485f0f2feaf460e2ac87fdd5608d63cf0
sizeof-long: 8
sizeof-size_t: 8
shell-path: /bin/sh
libcurl: 8.15.0
OpenSSL: OpenSSL 3.5.2 5 Aug 2025
zlib-ng: 2.2.5
SHA-1: SHA1_DC
SHA-256: SHA256_BLK
default-ref-format: files
default-hash: sha1
uname: Linux 6.16.7-arch1-1 #1 SMP PREEMPT_DYNAMIC Thu, 11 Sep 2025
17:42:36 +0000 x86_64
compiler info: gnuc: 15.2
libc info: glibc: 2.42
$SHELL (typically, interactive shell): /usr/bin/zsh
[Enabled Hooks]

-- Lauri Niskanen

Next: Kristoffer Haugsbakk
Message 1 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.