builtin/show-branch: fix several memory leaks

There are several memory leaks in git-show-branch(1). Fix them. 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:40 UTC 11d6a81c01b6e1931667e98d7cbe34014310af3a
3 files changed +38 -16
builtin/show-branch.c
+36 -16
@@ -502,14 +502,14 @@ static int rev_is_head(const char *head, const char *name)
502 return !strcmp(head, name);
503 }
504
505 -static int show_merge_base(struct commit_list *seen, int num_rev)
505 +static int show_merge_base(const struct commit_list *seen, int num_rev)
506 {
507 int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
508 int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
509 int exit_status = 1;
510
511 - while (seen) {
512 - struct commit *commit = pop_commit(&seen);
511 + for (const struct commit_list *s = seen; s; s = s->next) {
512 + struct commit *commit = s->item;
513 int flags = commit->object.flags & all_mask;
514 if (!(flags & UNINTERESTING) &&
515 ((flags & all_revs) == all_revs)) {
@@ -635,7 +635,7 @@ static int parse_reflog_param(const struct option *opt, const char *arg,
635 int cmd_show_branch(int ac, const char **av, const char *prefix)
636 {
637 struct commit *rev[MAX_REVS], *commit;
638 - char *reflog_msg[MAX_REVS];
638 + char *reflog_msg[MAX_REVS] = {0};
639 struct commit_list *list = NULL, *seen = NULL;
640 unsigned int rev_mask[MAX_REVS];
641 int num_rev, i, extra = 0;
@@ -692,6 +692,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
692 parse_reflog_param),
693 OPT_END()
694 };
695 + const char **args_copy = NULL;
696 + int ret;
697
698 init_commit_name_slab(&name_slab);
699
@@ -699,8 +701,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
701
702 /* If nothing is specified, try the default first */
703 if (ac == 1 && default_args.nr) {
704 + DUP_ARRAY(args_copy, default_args.v, default_args.nr);
705 ac = default_args.nr;
703 - av = default_args.v;
706 + av = args_copy;
707 }
708
709 ac = parse_options(ac, av, prefix, builtin_show_branch_options,
@@ -780,7 +783,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
783 }
784
785 for (i = 0; i < reflog; i++) {
783 - char *logmsg;
786 + char *logmsg = NULL;
787 char *nth_desc;
788 const char *msg;
789 char *end;
@@ -790,6 +793,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
793 if (read_ref_at(get_main_ref_store(the_repository),
794 ref, flags, 0, base + i, &oid, &logmsg,
795 &timestamp, &tz, NULL)) {
796 + free(logmsg);
797 reflog = i;
798 break;
799 }
@@ -842,7 +846,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
846
847 if (!ref_name_cnt) {
848 fprintf(stderr, "No revs to be shown.\n");
845 - exit(0);
849 + ret = 0;
850 + goto out;
851 }
852
853 for (num_rev = 0; ref_name[num_rev]; num_rev++) {
@@ -879,11 +884,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
884
885 commit_list_sort_by_date(&seen);
886
882 - if (merge_base)
883 - return show_merge_base(seen, num_rev);
887 + if (merge_base) {
888 + ret = show_merge_base(seen, num_rev);
889 + goto out;
890 + }
891
885 - if (independent)
886 - return show_independent(rev, num_rev, rev_mask);
892 + if (independent) {
893 + ret = show_independent(rev, num_rev, rev_mask);
894 + goto out;
895 + }
896
897 /* Show list; --more=-1 means list-only */
898 if (1 < num_rev || extra < 0) {
@@ -919,8 +928,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
928 putchar('\n');
929 }
930 }
922 - if (extra < 0)
923 - exit(0);
931 + if (extra < 0) {
932 + ret = 0;
933 + goto out;
934 + }
935
936 /* Sort topologically */
937 sort_in_topological_order(&seen, sort_order);
@@ -932,8 +943,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
943 all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
944 all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
945
935 - while (seen) {
936 - struct commit *commit = pop_commit(&seen);
946 + for (struct commit_list *l = seen; l; l = l->next) {
947 + struct commit *commit = l->item;
948 int this_flag = commit->object.flags;
949 int is_merge_point = ((this_flag & all_revs) == all_revs);
950
@@ -973,6 +984,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
984 if (shown_merge_point && --extra < 0)
985 break;
986 }
987 +
988 + ret = 0;
989 +
990 +out:
991 + for (size_t i = 0; i < ARRAY_SIZE(reflog_msg); i++)
992 + free(reflog_msg[i]);
993 + free_commit_list(seen);
994 + free_commit_list(list);
995 + free(args_copy);
996 free(head);
977 - return 0;
997 + return ret;
998 }
t/t3202-show-branch.sh
+1
@@ -2,6 +2,7 @@
2
3 test_description='test show-branch'
4
5 +TEST_PASSES_SANITIZE_LEAK=true
6 . ./test-lib.sh
7
8 test_expect_success 'error descriptions on empty repository' '
t/t6010-merge-base.sh
+1
@@ -6,6 +6,7 @@
6 test_description='Merge base and parent list computation.
7 '
8
9 +TEST_PASSES_SANITIZE_LEAK=true
10 . ./test-lib.sh
11
12 M=1130000000