builtin/describe: fix memory leak with `--contains=`

When calling `git describe --contains=`, we end up invoking `cmd_name_rev()` with some munged argv array. This array may contain allocated strings and furthermore will likely be modified by the called function. This results in two memory leaks: - First, we leak the array that we use to assemble the arguments. - Second, we leak the allocated strings that we may have put into the array. Fix those leaks by creating a separate copy of the array that we can hand over to `cmd_name_rev()`. This allows us to free all strings contained in the `strvec`, as the original vector will not be modified anymore. Furthermore, free both the `strvec` and the copied array to fix the first memory leak. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Aug 1, 2024 at 12:38 UTC 8e2e28799d2353e32c393bd7938c457e5e08fc63
1 file changed +17 -1
builtin/describe.c
+17 -1
@@ -619,6 +619,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
619 if (contains) {
620 struct string_list_item *item;
621 struct strvec args;
622 + const char **argv_copy;
623 + int ret;
624
625 strvec_init(&args);
626 strvec_pushl(&args, "name-rev",
@@ -637,7 +639,21 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
639 strvec_pushv(&args, argv);
640 else
641 strvec_push(&args, "HEAD");
640 - return cmd_name_rev(args.nr, args.v, prefix);
642 +
643 + /*
644 + * `cmd_name_rev()` modifies the array, so we'd leak its
645 + * contained strings if we didn't do a copy here.
646 + */
647 + ALLOC_ARRAY(argv_copy, args.nr + 1);
648 + for (size_t i = 0; i < args.nr; i++)
649 + argv_copy[i] = args.v[i];
650 + argv_copy[args.nr] = NULL;
651 +
652 + ret = cmd_name_rev(args.nr, argv_copy, prefix);
653 +
654 + strvec_clear(&args);
655 + free(argv_copy);
656 + return ret;
657 }
658
659 hashmap_init(&names, commit_name_neq, NULL, 0);