]> git.ipfire.org Git - thirdparty/git.git/commitdiff
git: fix leaking argv when handling builtins
authorPatrick Steinhardt <ps@pks.im>
Thu, 26 Sep 2024 11:46:06 +0000 (13:46 +0200)
committerJunio C Hamano <gitster@pobox.com>
Fri, 27 Sep 2024 15:25:34 +0000 (08:25 -0700)
In `handle_builtin()` we may end up creating an ad-hoc argv array in
case we see that the command line contains the "--help" parameter. In
this case we observe two memory leaks though:

  - We leak the `struct strvec` itself because we directly exit after
    calling `run_builtin()`, without bothering about any cleanups.

  - Even if we free'd that vector we'd end up leaking some of its
    strings because `run_builtin()` will modify the array.

Plug both of these leaks.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
git.c
t/t0012-help.sh

diff --git a/git.c b/git.c
index 9a618a2740f1953e21bc18a49cc8db1ffb5dd4db..3c7fabfda262bdb29f595df6ecdc944d66f4efa9 100644 (file)
--- a/git.c
+++ b/git.c
@@ -711,6 +711,7 @@ static void strip_extension(const char **argv)
 static void handle_builtin(int argc, const char **argv)
 {
        struct strvec args = STRVEC_INIT;
+       const char **argv_copy = NULL;
        const char *cmd;
        struct cmd_struct *builtin;
 
@@ -731,13 +732,28 @@ static void handle_builtin(int argc, const char **argv)
                }
 
                argc++;
-               argv = args.v;
+
+               /*
+                * `run_builtin()` will modify the argv array, so we need to
+                * create a shallow copy such that we can free all of its
+                * strings.
+                */
+               CALLOC_ARRAY(argv_copy, argc + 1);
+               COPY_ARRAY(argv_copy, args.v, argc);
+
+               argv = argv_copy;
        }
 
        builtin = get_builtin(cmd);
-       if (builtin)
-               exit(run_builtin(builtin, argc, argv));
+       if (builtin) {
+               int ret = run_builtin(builtin, argc, argv);
+               strvec_clear(&args);
+               free(argv_copy);
+               exit(ret);
+       }
+
        strvec_clear(&args);
+       free(argv_copy);
 }
 
 static void execv_dashed_external(const char **argv)
index 1d273d91c2125ae2c16ae1a14c628cf23fcecc06..9eae0d835637885dfc2c236544b4d828020e502e 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='help'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 configure_help () {