Skip to content

Commit f93c1d8

Browse files
peffgitster
authored andcommitted
revision: add wrapper to setup_revisions() from a strvec
The setup_revisions() function was designed to take the argc/argv pair from the operating system. But we sometimes construct our own argv using a strvec and pass that in. There are a few gotchas that callers need to deal with here: 1. You should always pass the free_removed_argv_elements option via setup_revision_opt. Otherwise, entries may be leaked if setup_revisions() re-shuffles options. 2. After setup_revisions() returns, the strvec state is odd. We get a reduced argc from setup_revisions() telling us how many unknown options were left in place. Entries after that in argv may be retained, or may be NULL (depending on how the reshuffling happened). But the strvec's "nr" field still represents the original value, and some of the entries it thinks it is still storing may be NULL. Callers must be careful with how they access it. Some callers deal with (1), but not all. In practice they are OK because they do not pass any options that would cause setup_revisions() to re-shuffle (namely unknown options which may be relayed from the user, and the use of the "--" separator). But it's probably a good idea to consistently pass this option anyway to future-proof ourselves against the details of setup_revisions() changing. No callers address (2), though I don't think there any visible bugs. Most of them simply call strvec_clear() and never otherwise look at the result. And in fact, if they naively set foo.nr to the argc returned by setup_revisions(), that would cause leaks! Because setup_revisions() does not free consumed options[1], we have to leave the "nr" field of the strvec at its original value to find and free them during strvec_clear(). So I don't think there are any bugs to fix here, but we can make things safer and simpler for callers. Let's introduce a helper function that sets the free_removed_argv_elements automatically and shrinks the strvec to represent the retained options afterwards (taking care to free the now-obsolete entries). We'll start by converting all of the call-sites which use the free_removed_argv_elements option. There should be no behavior change for them, except that their "shrunken" entries are cleaned up immediately, rather than waiting for a strvec_clear() call. [1] Arguably setup_revisions() should be doing this step for us if we told it to free removed options, but there are many existing callers which will be broken if it did. Introducing this helper is a possible first step towards that. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent cd43948 commit f93c1d8

File tree

6 files changed

+27
-19
lines changed

6 files changed

+27
-19
lines changed

bisect.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -674,9 +674,6 @@ static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
674674
const char *bad_format, const char *good_format,
675675
int read_paths)
676676
{
677-
struct setup_revision_opt opt = {
678-
.free_removed_argv_elements = 1,
679-
};
680677
int i;
681678

682679
repo_init_revisions(r, revs, prefix);
@@ -693,7 +690,7 @@ static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
693690
if (read_paths)
694691
read_bisect_paths(rev_argv);
695692

696-
setup_revisions(rev_argv->nr, rev_argv->v, revs, &opt);
693+
setup_revisions_from_strvec(rev_argv, revs, NULL);
697694
}
698695

699696
static void bisect_common(struct rev_info *revs)

builtin/stash.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,6 @@ static void diff_include_untracked(const struct stash_info *info, struct diff_op
956956
static int show_stash(int argc, const char **argv, const char *prefix,
957957
struct repository *repo UNUSED)
958958
{
959-
struct setup_revision_opt opt = { .free_removed_argv_elements = 1 };
960959
int i;
961960
int ret = -1;
962961
struct stash_info info = STASH_INFO_INIT;
@@ -1015,8 +1014,8 @@ static int show_stash(int argc, const char **argv, const char *prefix,
10151014
}
10161015
}
10171016

1018-
argc = setup_revisions(revision_args.nr, revision_args.v, &rev, &opt);
1019-
if (argc > 1)
1017+
setup_revisions_from_strvec(&revision_args, &rev, NULL);
1018+
if (revision_args.nr > 1)
10201019
goto usage;
10211020
if (!rev.diffopt.output_format) {
10221021
rev.diffopt.output_format = DIFF_FORMAT_PATCH;

builtin/submodule--helper.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -616,9 +616,6 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
616616
struct rev_info rev = REV_INFO_INIT;
617617
struct strbuf buf = STRBUF_INIT;
618618
const char *git_dir;
619-
struct setup_revision_opt opt = {
620-
.free_removed_argv_elements = 1,
621-
};
622619

623620
if (validate_submodule_path(path) < 0)
624621
die(NULL);
@@ -655,7 +652,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
655652

656653
repo_init_revisions(the_repository, &rev, NULL);
657654
rev.abbrev = 0;
658-
setup_revisions(diff_files_args.nr, diff_files_args.v, &rev, &opt);
655+
setup_revisions_from_strvec(&diff_files_args, &rev, NULL);
659656
run_diff_files(&rev, 0);
660657

661658
if (!diff_result_code(&rev)) {
@@ -1094,9 +1091,6 @@ static int compute_summary_module_list(struct object_id *head_oid,
10941091
{
10951092
struct strvec diff_args = STRVEC_INIT;
10961093
struct rev_info rev;
1097-
struct setup_revision_opt opt = {
1098-
.free_removed_argv_elements = 1,
1099-
};
11001094
struct module_cb_list list = MODULE_CB_LIST_INIT;
11011095
int ret = 0;
11021096

@@ -1114,7 +1108,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
11141108
repo_init_revisions(the_repository, &rev, info->prefix);
11151109
rev.abbrev = 0;
11161110
precompose_argv_prefix(diff_args.nr, diff_args.v, NULL);
1117-
setup_revisions(diff_args.nr, diff_args.v, &rev, &opt);
1111+
setup_revisions_from_strvec(&diff_args, &rev, NULL);
11181112
rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;
11191113
rev.diffopt.format_callback = submodule_summary_callback;
11201114
rev.diffopt.format_callback_data = &list;

remote.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2137,9 +2137,6 @@ static int stat_branch_pair(const char *branch_name, const char *base,
21372137
struct object_id oid;
21382138
struct commit *ours, *theirs;
21392139
struct rev_info revs;
2140-
struct setup_revision_opt opt = {
2141-
.free_removed_argv_elements = 1,
2142-
};
21432140
struct strvec argv = STRVEC_INIT;
21442141

21452142
/* Cannot stat if what we used to build on no longer exists */
@@ -2174,7 +2171,7 @@ static int stat_branch_pair(const char *branch_name, const char *base,
21742171
strvec_push(&argv, "--");
21752172

21762173
repo_init_revisions(the_repository, &revs, NULL);
2177-
setup_revisions(argv.nr, argv.v, &revs, &opt);
2174+
setup_revisions_from_strvec(&argv, &revs, NULL);
21782175
if (prepare_revision_walk(&revs))
21792176
die(_("revision walk setup failed"));
21802177

revision.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3178,6 +3178,25 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
31783178
return left;
31793179
}
31803180

3181+
void setup_revisions_from_strvec(struct strvec *argv, struct rev_info *revs,
3182+
struct setup_revision_opt *opt)
3183+
{
3184+
struct setup_revision_opt fallback_opt;
3185+
int ret;
3186+
3187+
if (!opt) {
3188+
memset(&fallback_opt, 0, sizeof(fallback_opt));
3189+
opt = &fallback_opt;
3190+
}
3191+
opt->free_removed_argv_elements = 1;
3192+
3193+
ret = setup_revisions(argv->nr, argv->v, revs, opt);
3194+
3195+
for (size_t i = ret; i < argv->nr; i++)
3196+
free((char *)argv->v[i]);
3197+
argv->nr = ret;
3198+
}
3199+
31813200
static void release_revisions_cmdline(struct rev_cmdline_info *cmdline)
31823201
{
31833202
unsigned int i;

revision.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,8 @@ struct setup_revision_opt {
441441
};
442442
int setup_revisions(int argc, const char **argv, struct rev_info *revs,
443443
struct setup_revision_opt *);
444+
void setup_revisions_from_strvec(struct strvec *argv, struct rev_info *revs,
445+
struct setup_revision_opt *);
444446

445447
/**
446448
* Free data allocated in a "struct rev_info" after it's been

0 commit comments

Comments
 (0)