git: fix leaking argv when handling builtins

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>

Patrick Steinhardt committed Sep 26, 2024 at 13:46 UTC 3aef7a05adb2868118181eb5605fffa65a9af2c8
2 files changed +20 -3
git.c
+19 -3
@@ -711,6 +711,7 @@ static void strip_extension(const char **argv)
711 static void handle_builtin(int argc, const char **argv)
712 {
713 struct strvec args = STRVEC_INIT;
714 + const char **argv_copy = NULL;
715 const char *cmd;
716 struct cmd_struct *builtin;
717
@@ -731,13 +732,28 @@ static void handle_builtin(int argc, const char **argv)
732 }
733
734 argc++;
734 - argv = args.v;
735 +
736 + /*
737 + * `run_builtin()` will modify the argv array, so we need to
738 + * create a shallow copy such that we can free all of its
739 + * strings.
740 + */
741 + CALLOC_ARRAY(argv_copy, argc + 1);
742 + COPY_ARRAY(argv_copy, args.v, argc);
743 +
744 + argv = argv_copy;
745 }
746
747 builtin = get_builtin(cmd);
738 - if (builtin)
739 - exit(run_builtin(builtin, argc, argv));
748 + if (builtin) {
749 + int ret = run_builtin(builtin, argc, argv);
750 + strvec_clear(&args);
751 + free(argv_copy);
752 + exit(ret);
753 + }
754 +
755 strvec_clear(&args);
756 + free(argv_copy);
757 }
758
759 static void execv_dashed_external(const char **argv)
t/t0012-help.sh
+1
@@ -2,6 +2,7 @@
2
3 test_description='help'
4
5 +TEST_PASSES_SANITIZE_LEAK=true
6 . ./test-lib.sh
7
8 configure_help () {