Skip to content

Commit 83489a5

Browse files
committed
Merge branch 'ab/plug-revisions-leak'
Plug a bit more leaks in the revisions API. * ab/plug-revisions-leak: revisions API: don't leak memory on argv elements that need free()-ing bisect.c: partially fix bisect_rev_setup() memory leak log: refactor "rev.pending" code in cmd_show() log: fix a memory leak in "git show <revision>..." test-fast-rebase helper: use release_revisions() (again) bisect.c: add missing "goto" for release_revisions()
2 parents 657c740 + f92dbdb commit 83489a5

17 files changed

+59
-28
lines changed

bisect.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -648,29 +648,31 @@ static struct commit_list *managed_skipped(struct commit_list *list,
648648
}
649649

650650
static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
651+
struct strvec *rev_argv,
651652
const char *prefix,
652653
const char *bad_format, const char *good_format,
653654
int read_paths)
654655
{
655-
struct strvec rev_argv = STRVEC_INIT;
656+
struct setup_revision_opt opt = {
657+
.free_removed_argv_elements = 1,
658+
};
656659
int i;
657660

658661
repo_init_revisions(r, revs, prefix);
659662
revs->abbrev = 0;
660663
revs->commit_format = CMIT_FMT_UNSPECIFIED;
661664

662665
/* rev_argv.argv[0] will be ignored by setup_revisions */
663-
strvec_push(&rev_argv, "bisect_rev_setup");
664-
strvec_pushf(&rev_argv, bad_format, oid_to_hex(current_bad_oid));
666+
strvec_push(rev_argv, "bisect_rev_setup");
667+
strvec_pushf(rev_argv, bad_format, oid_to_hex(current_bad_oid));
665668
for (i = 0; i < good_revs.nr; i++)
666-
strvec_pushf(&rev_argv, good_format,
669+
strvec_pushf(rev_argv, good_format,
667670
oid_to_hex(good_revs.oid + i));
668-
strvec_push(&rev_argv, "--");
671+
strvec_push(rev_argv, "--");
669672
if (read_paths)
670-
read_bisect_paths(&rev_argv);
673+
read_bisect_paths(rev_argv);
671674

672-
setup_revisions(rev_argv.nr, rev_argv.v, revs, NULL);
673-
/* XXX leak rev_argv, as "revs" may still be pointing to it */
675+
setup_revisions(rev_argv->nr, rev_argv->v, revs, &opt);
674676
}
675677

676678
static void bisect_common(struct rev_info *revs)
@@ -873,10 +875,11 @@ static enum bisect_error check_merge_bases(int rev_nr, struct commit **rev, int
873875
static int check_ancestors(struct repository *r, int rev_nr,
874876
struct commit **rev, const char *prefix)
875877
{
878+
struct strvec rev_argv = STRVEC_INIT;
876879
struct rev_info revs;
877880
int res;
878881

879-
bisect_rev_setup(r, &revs, prefix, "^%s", "%s", 0);
882+
bisect_rev_setup(r, &revs, &rev_argv, prefix, "^%s", "%s", 0);
880883

881884
bisect_common(&revs);
882885
res = (revs.commits != NULL);
@@ -885,6 +888,7 @@ static int check_ancestors(struct repository *r, int rev_nr,
885888
clear_commit_marks_many(rev_nr, rev, ALL_REV_FLAGS);
886889

887890
release_revisions(&revs);
891+
strvec_clear(&rev_argv);
888892
return res;
889893
}
890894

@@ -1010,6 +1014,7 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
10101014
*/
10111015
enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
10121016
{
1017+
struct strvec rev_argv = STRVEC_INIT;
10131018
struct rev_info revs = REV_INFO_INIT;
10141019
struct commit_list *tried;
10151020
int reaches = 0, all = 0, nr, steps;
@@ -1037,7 +1042,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
10371042
if (res)
10381043
goto cleanup;
10391044

1040-
bisect_rev_setup(r, &revs, prefix, "%s", "^%s", 1);
1045+
bisect_rev_setup(r, &revs, &rev_argv, prefix, "%s", "^%s", 1);
10411046

10421047
revs.first_parent_only = !!(bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY);
10431048
revs.limited = 1;
@@ -1054,7 +1059,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
10541059
*/
10551060
res = error_if_skipped_commits(tried, NULL);
10561061
if (res < 0)
1057-
return res;
1062+
goto cleanup;
10581063
printf(_("%s was both %s and %s\n"),
10591064
oid_to_hex(current_bad_oid),
10601065
term_good,
@@ -1112,6 +1117,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
11121117
res = bisect_checkout(bisect_rev, no_checkout);
11131118
cleanup:
11141119
release_revisions(&revs);
1120+
strvec_clear(&rev_argv);
11151121
return res;
11161122
}
11171123

builtin/log.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -668,10 +668,10 @@ static void show_setup_revisions_tweak(struct rev_info *rev,
668668
int cmd_show(int argc, const char **argv, const char *prefix)
669669
{
670670
struct rev_info rev;
671-
struct object_array_entry *objects;
671+
unsigned int i;
672672
struct setup_revision_opt opt;
673673
struct pathspec match_all;
674-
int i, count, ret = 0;
674+
int ret = 0;
675675

676676
init_log_defaults();
677677
git_config(git_log_config, NULL);
@@ -698,12 +698,10 @@ int cmd_show(int argc, const char **argv, const char *prefix)
698698
if (!rev.no_walk)
699699
return cmd_log_deinit(cmd_log_walk(&rev), &rev);
700700

701-
count = rev.pending.nr;
702-
objects = rev.pending.objects;
703701
rev.diffopt.no_free = 1;
704-
for (i = 0; i < count && !ret; i++) {
705-
struct object *o = objects[i].item;
706-
const char *name = objects[i].name;
702+
for (i = 0; i < rev.pending.nr && !ret; i++) {
703+
struct object *o = rev.pending.objects[i].item;
704+
const char *name = rev.pending.objects[i].name;
707705
switch (o->type) {
708706
case OBJ_BLOB:
709707
ret = show_blob_object(&o->oid, &rev, name);
@@ -726,7 +724,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
726724
if (!o)
727725
ret = error(_("could not read object %s"),
728726
oid_to_hex(oid));
729-
objects[i].item = o;
727+
rev.pending.objects[i].item = o;
730728
i--;
731729
break;
732730
}
@@ -743,11 +741,24 @@ int cmd_show(int argc, const char **argv, const char *prefix)
743741
rev.shown_one = 1;
744742
break;
745743
case OBJ_COMMIT:
746-
rev.pending.nr = rev.pending.alloc = 0;
747-
rev.pending.objects = NULL;
744+
{
745+
struct object_array old;
746+
struct object_array blank = OBJECT_ARRAY_INIT;
747+
748+
memcpy(&old, &rev.pending, sizeof(old));
749+
memcpy(&rev.pending, &blank, sizeof(rev.pending));
750+
748751
add_object_array(o, name, &rev.pending);
749752
ret = cmd_log_walk_no_free(&rev);
753+
754+
/*
755+
* No need for
756+
* object_array_clear(&pending). It was
757+
* cleared already in prepare_revision_walk()
758+
*/
759+
memcpy(&rev.pending, &old, sizeof(rev.pending));
750760
break;
761+
}
751762
default:
752763
ret = error(_("unknown type: %d"), o->type);
753764
}

builtin/submodule--helper.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,9 @@ static int compute_summary_module_list(struct object_id *head_oid,
11041104
{
11051105
struct strvec diff_args = STRVEC_INIT;
11061106
struct rev_info rev;
1107+
struct setup_revision_opt opt = {
1108+
.free_removed_argv_elements = 1,
1109+
};
11071110
struct module_cb_list list = MODULE_CB_LIST_INIT;
11081111
int ret = 0;
11091112

@@ -1121,7 +1124,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
11211124
init_revisions(&rev, info->prefix);
11221125
rev.abbrev = 0;
11231126
precompose_argv_prefix(diff_args.nr, diff_args.v, NULL);
1124-
setup_revisions(diff_args.nr, diff_args.v, &rev, NULL);
1127+
setup_revisions(diff_args.nr, diff_args.v, &rev, &opt);
11251128
rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;
11261129
rev.diffopt.format_callback = submodule_summary_callback;
11271130
rev.diffopt.format_callback_data = &list;

remote.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2147,6 +2147,9 @@ static int stat_branch_pair(const char *branch_name, const char *base,
21472147
struct object_id oid;
21482148
struct commit *ours, *theirs;
21492149
struct rev_info revs;
2150+
struct setup_revision_opt opt = {
2151+
.free_removed_argv_elements = 1,
2152+
};
21502153
struct strvec argv = STRVEC_INIT;
21512154

21522155
/* Cannot stat if what we used to build on no longer exists */
@@ -2181,7 +2184,7 @@ static int stat_branch_pair(const char *branch_name, const char *base,
21812184
strvec_push(&argv, "--");
21822185

21832186
repo_init_revisions(the_repository, &revs, NULL);
2184-
setup_revisions(argv.nr, argv.v, &revs, NULL);
2187+
setup_revisions(argv.nr, argv.v, &revs, &opt);
21852188
if (prepare_revision_walk(&revs))
21862189
die(_("revision walk setup failed"));
21872190

revision.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2784,6 +2784,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
27842784
const char *arg = argv[i];
27852785
if (strcmp(arg, "--"))
27862786
continue;
2787+
if (opt && opt->free_removed_argv_elements)
2788+
free((char *)argv[i]);
27872789
argv[i] = NULL;
27882790
argc = i;
27892791
if (argv[i + 1])

revision.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,8 @@ struct setup_revision_opt {
375375
const char *def;
376376
void (*tweak)(struct rev_info *, struct setup_revision_opt *);
377377
unsigned int assume_dashdash:1,
378-
allow_exclude_promisor_objects:1;
378+
allow_exclude_promisor_objects:1,
379+
free_removed_argv_elements:1;
379380
unsigned revarg_opt;
380381
};
381382
int setup_revisions(int argc, const char **argv, struct rev_info *revs,

t/helper/test-fast-rebase.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,6 @@ int cmd__fast_rebase(int argc, const char **argv)
184184
last_picked_commit = commit;
185185
last_commit = create_commit(result.tree, commit, last_commit);
186186
}
187-
/* TODO: There should be some kind of rev_info_free(&revs) call... */
188-
memset(&revs, 0, sizeof(revs));
189187

190188
merge_switch_to_result(&merge_opt, head_tree, &result, 1, !result.clean);
191189

t/t0203-gettext-setlocale-sanity.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
test_description="The Git C functions aren't broken by setlocale(3)"
77

8+
TEST_PASSES_SANITIZE_LEAK=true
89
. ./lib-gettext.sh
910

1011
test_expect_success 'git show a ISO-8859-1 commit under C locale' '

t/t1020-subdirectory.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
test_description='Try various core-level commands in subdirectory.
77
'
88

9+
TEST_PASSES_SANITIZE_LEAK=true
910
. ./test-lib.sh
1011
. "$TEST_DIRECTORY"/lib-read-tree.sh
1112

t/t2020-checkout-detach.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ test_description='checkout into detached HEAD state'
44
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
55
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
66

7+
TEST_PASSES_SANITIZE_LEAK=true
78
. ./test-lib.sh
89

910
check_detached () {

0 commit comments

Comments
 (0)