Skip to content

Commit f92dbdb

Browse files
avargitster
authored andcommitted
revisions API: don't leak memory on argv elements that need free()-ing
Add a "free_removed_argv_elements" member to "struct setup_revision_opt", and use it to fix several memory leaks. We have various memory leaks in APIs that take and munge "const char **argv", e.g. parse_options(). Sometimes these APIs are given the "argv" we get to the "main" function, in which case we don't leak memory, but other times we're giving it the "v" member of a "struct strvec" we created. There's several potential ways to fix those sort of leaks, we could add a "nodup" mode to "struct strvec", which would work for the cases where we push constant strings to it. But that wouldn't work as soon as we used strvec_pushf(), or otherwise needed to duplicate or create a string for that "struct strvec". Let's instead make it the responsibility of the revisions API. If it's going to clobber elements of argv it can also free() them, which it will now do if instructed to do so via "free_removed_argv_elements". Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 57efebb commit f92dbdb

File tree

6 files changed

+17
-5
lines changed

6 files changed

+17
-5
lines changed

bisect.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,9 @@ static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
653653
const char *bad_format, const char *good_format,
654654
int read_paths)
655655
{
656+
struct setup_revision_opt opt = {
657+
.free_removed_argv_elements = 1,
658+
};
656659
int i;
657660

658661
repo_init_revisions(r, revs, prefix);
@@ -669,8 +672,7 @@ static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
669672
if (read_paths)
670673
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)

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
@@ -2169,6 +2169,9 @@ static int stat_branch_pair(const char *branch_name, const char *base,
21692169
struct object_id oid;
21702170
struct commit *ours, *theirs;
21712171
struct rev_info revs;
2172+
struct setup_revision_opt opt = {
2173+
.free_removed_argv_elements = 1,
2174+
};
21722175
struct strvec argv = STRVEC_INIT;
21732176

21742177
/* Cannot stat if what we used to build on no longer exists */
@@ -2203,7 +2206,7 @@ static int stat_branch_pair(const char *branch_name, const char *base,
22032206
strvec_push(&argv, "--");
22042207

22052208
repo_init_revisions(the_repository, &revs, NULL);
2206-
setup_revisions(argv.nr, argv.v, &revs, NULL);
2209+
setup_revisions(argv.nr, argv.v, &revs, &opt);
22072210
if (prepare_revision_walk(&revs))
22082211
die(_("revision walk setup failed"));
22092212

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/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)