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()
This commit is contained in:
commit
83489a5b20
28
bisect.c
28
bisect.c
@ -648,11 +648,14 @@ static struct commit_list *managed_skipped(struct commit_list *list,
|
||||
}
|
||||
|
||||
static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
|
||||
struct strvec *rev_argv,
|
||||
const char *prefix,
|
||||
const char *bad_format, const char *good_format,
|
||||
int read_paths)
|
||||
{
|
||||
struct strvec rev_argv = STRVEC_INIT;
|
||||
struct setup_revision_opt opt = {
|
||||
.free_removed_argv_elements = 1,
|
||||
};
|
||||
int i;
|
||||
|
||||
repo_init_revisions(r, revs, prefix);
|
||||
@ -660,17 +663,16 @@ static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
|
||||
revs->commit_format = CMIT_FMT_UNSPECIFIED;
|
||||
|
||||
/* rev_argv.argv[0] will be ignored by setup_revisions */
|
||||
strvec_push(&rev_argv, "bisect_rev_setup");
|
||||
strvec_pushf(&rev_argv, bad_format, oid_to_hex(current_bad_oid));
|
||||
strvec_push(rev_argv, "bisect_rev_setup");
|
||||
strvec_pushf(rev_argv, bad_format, oid_to_hex(current_bad_oid));
|
||||
for (i = 0; i < good_revs.nr; i++)
|
||||
strvec_pushf(&rev_argv, good_format,
|
||||
strvec_pushf(rev_argv, good_format,
|
||||
oid_to_hex(good_revs.oid + i));
|
||||
strvec_push(&rev_argv, "--");
|
||||
strvec_push(rev_argv, "--");
|
||||
if (read_paths)
|
||||
read_bisect_paths(&rev_argv);
|
||||
read_bisect_paths(rev_argv);
|
||||
|
||||
setup_revisions(rev_argv.nr, rev_argv.v, revs, NULL);
|
||||
/* XXX leak rev_argv, as "revs" may still be pointing to it */
|
||||
setup_revisions(rev_argv->nr, rev_argv->v, revs, &opt);
|
||||
}
|
||||
|
||||
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
|
||||
static int check_ancestors(struct repository *r, int rev_nr,
|
||||
struct commit **rev, const char *prefix)
|
||||
{
|
||||
struct strvec rev_argv = STRVEC_INIT;
|
||||
struct rev_info revs;
|
||||
int res;
|
||||
|
||||
bisect_rev_setup(r, &revs, prefix, "^%s", "%s", 0);
|
||||
bisect_rev_setup(r, &revs, &rev_argv, prefix, "^%s", "%s", 0);
|
||||
|
||||
bisect_common(&revs);
|
||||
res = (revs.commits != NULL);
|
||||
@ -885,6 +888,7 @@ static int check_ancestors(struct repository *r, int rev_nr,
|
||||
clear_commit_marks_many(rev_nr, rev, ALL_REV_FLAGS);
|
||||
|
||||
release_revisions(&revs);
|
||||
strvec_clear(&rev_argv);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1010,6 +1014,7 @@ void read_bisect_terms(const char **read_bad, const char **read_good)
|
||||
*/
|
||||
enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
|
||||
{
|
||||
struct strvec rev_argv = STRVEC_INIT;
|
||||
struct rev_info revs = REV_INFO_INIT;
|
||||
struct commit_list *tried;
|
||||
int reaches = 0, all = 0, nr, steps;
|
||||
@ -1037,7 +1042,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
|
||||
if (res)
|
||||
goto cleanup;
|
||||
|
||||
bisect_rev_setup(r, &revs, prefix, "%s", "^%s", 1);
|
||||
bisect_rev_setup(r, &revs, &rev_argv, prefix, "%s", "^%s", 1);
|
||||
|
||||
revs.first_parent_only = !!(bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY);
|
||||
revs.limited = 1;
|
||||
@ -1054,7 +1059,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
|
||||
*/
|
||||
res = error_if_skipped_commits(tried, NULL);
|
||||
if (res < 0)
|
||||
return res;
|
||||
goto cleanup;
|
||||
printf(_("%s was both %s and %s\n"),
|
||||
oid_to_hex(current_bad_oid),
|
||||
term_good,
|
||||
@ -1112,6 +1117,7 @@ enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
|
||||
res = bisect_checkout(bisect_rev, no_checkout);
|
||||
cleanup:
|
||||
release_revisions(&revs);
|
||||
strvec_clear(&rev_argv);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -668,10 +668,10 @@ static void show_setup_revisions_tweak(struct rev_info *rev,
|
||||
int cmd_show(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
struct object_array_entry *objects;
|
||||
unsigned int i;
|
||||
struct setup_revision_opt opt;
|
||||
struct pathspec match_all;
|
||||
int i, count, ret = 0;
|
||||
int ret = 0;
|
||||
|
||||
init_log_defaults();
|
||||
git_config(git_log_config, NULL);
|
||||
@ -698,12 +698,10 @@ int cmd_show(int argc, const char **argv, const char *prefix)
|
||||
if (!rev.no_walk)
|
||||
return cmd_log_deinit(cmd_log_walk(&rev), &rev);
|
||||
|
||||
count = rev.pending.nr;
|
||||
objects = rev.pending.objects;
|
||||
rev.diffopt.no_free = 1;
|
||||
for (i = 0; i < count && !ret; i++) {
|
||||
struct object *o = objects[i].item;
|
||||
const char *name = objects[i].name;
|
||||
for (i = 0; i < rev.pending.nr && !ret; i++) {
|
||||
struct object *o = rev.pending.objects[i].item;
|
||||
const char *name = rev.pending.objects[i].name;
|
||||
switch (o->type) {
|
||||
case OBJ_BLOB:
|
||||
ret = show_blob_object(&o->oid, &rev, name);
|
||||
@ -726,7 +724,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
|
||||
if (!o)
|
||||
ret = error(_("could not read object %s"),
|
||||
oid_to_hex(oid));
|
||||
objects[i].item = o;
|
||||
rev.pending.objects[i].item = o;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
@ -743,11 +741,24 @@ int cmd_show(int argc, const char **argv, const char *prefix)
|
||||
rev.shown_one = 1;
|
||||
break;
|
||||
case OBJ_COMMIT:
|
||||
rev.pending.nr = rev.pending.alloc = 0;
|
||||
rev.pending.objects = NULL;
|
||||
{
|
||||
struct object_array old;
|
||||
struct object_array blank = OBJECT_ARRAY_INIT;
|
||||
|
||||
memcpy(&old, &rev.pending, sizeof(old));
|
||||
memcpy(&rev.pending, &blank, sizeof(rev.pending));
|
||||
|
||||
add_object_array(o, name, &rev.pending);
|
||||
ret = cmd_log_walk_no_free(&rev);
|
||||
|
||||
/*
|
||||
* No need for
|
||||
* object_array_clear(&pending). It was
|
||||
* cleared already in prepare_revision_walk()
|
||||
*/
|
||||
memcpy(&rev.pending, &old, sizeof(rev.pending));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = error(_("unknown type: %d"), o->type);
|
||||
}
|
||||
|
@ -1104,6 +1104,9 @@ static int compute_summary_module_list(struct object_id *head_oid,
|
||||
{
|
||||
struct strvec diff_args = STRVEC_INIT;
|
||||
struct rev_info rev;
|
||||
struct setup_revision_opt opt = {
|
||||
.free_removed_argv_elements = 1,
|
||||
};
|
||||
struct module_cb_list list = MODULE_CB_LIST_INIT;
|
||||
int ret = 0;
|
||||
|
||||
@ -1121,7 +1124,7 @@ static int compute_summary_module_list(struct object_id *head_oid,
|
||||
init_revisions(&rev, info->prefix);
|
||||
rev.abbrev = 0;
|
||||
precompose_argv_prefix(diff_args.nr, diff_args.v, NULL);
|
||||
setup_revisions(diff_args.nr, diff_args.v, &rev, NULL);
|
||||
setup_revisions(diff_args.nr, diff_args.v, &rev, &opt);
|
||||
rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;
|
||||
rev.diffopt.format_callback = submodule_summary_callback;
|
||||
rev.diffopt.format_callback_data = &list;
|
||||
|
5
remote.c
5
remote.c
@ -2147,6 +2147,9 @@ static int stat_branch_pair(const char *branch_name, const char *base,
|
||||
struct object_id oid;
|
||||
struct commit *ours, *theirs;
|
||||
struct rev_info revs;
|
||||
struct setup_revision_opt opt = {
|
||||
.free_removed_argv_elements = 1,
|
||||
};
|
||||
struct strvec argv = STRVEC_INIT;
|
||||
|
||||
/* 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,
|
||||
strvec_push(&argv, "--");
|
||||
|
||||
repo_init_revisions(the_repository, &revs, NULL);
|
||||
setup_revisions(argv.nr, argv.v, &revs, NULL);
|
||||
setup_revisions(argv.nr, argv.v, &revs, &opt);
|
||||
if (prepare_revision_walk(&revs))
|
||||
die(_("revision walk setup failed"));
|
||||
|
||||
|
@ -2784,6 +2784,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
|
||||
const char *arg = argv[i];
|
||||
if (strcmp(arg, "--"))
|
||||
continue;
|
||||
if (opt && opt->free_removed_argv_elements)
|
||||
free((char *)argv[i]);
|
||||
argv[i] = NULL;
|
||||
argc = i;
|
||||
if (argv[i + 1])
|
||||
|
@ -375,7 +375,8 @@ struct setup_revision_opt {
|
||||
const char *def;
|
||||
void (*tweak)(struct rev_info *, struct setup_revision_opt *);
|
||||
unsigned int assume_dashdash:1,
|
||||
allow_exclude_promisor_objects:1;
|
||||
allow_exclude_promisor_objects:1,
|
||||
free_removed_argv_elements:1;
|
||||
unsigned revarg_opt;
|
||||
};
|
||||
int setup_revisions(int argc, const char **argv, struct rev_info *revs,
|
||||
|
@ -184,8 +184,6 @@ int cmd__fast_rebase(int argc, const char **argv)
|
||||
last_picked_commit = commit;
|
||||
last_commit = create_commit(result.tree, commit, last_commit);
|
||||
}
|
||||
/* TODO: There should be some kind of rev_info_free(&revs) call... */
|
||||
memset(&revs, 0, sizeof(revs));
|
||||
|
||||
merge_switch_to_result(&merge_opt, head_tree, &result, 1, !result.clean);
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
test_description="The Git C functions aren't broken by setlocale(3)"
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./lib-gettext.sh
|
||||
|
||||
test_expect_success 'git show a ISO-8859-1 commit under C locale' '
|
||||
|
@ -6,6 +6,7 @@
|
||||
test_description='Try various core-level commands in subdirectory.
|
||||
'
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
. "$TEST_DIRECTORY"/lib-read-tree.sh
|
||||
|
||||
|
@ -4,6 +4,7 @@ test_description='checkout into detached HEAD state'
|
||||
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
|
||||
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
|
||||
check_detached () {
|
||||
|
@ -4,6 +4,7 @@ test_description='Examples from the git-notes man page
|
||||
|
||||
Make sure the manual is not full of lies.'
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup' '
|
||||
|
@ -1,6 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='Test ref-filter and pretty APIs for commit and tag messages using CRLF'
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
|
||||
LIB_CRLF_BRANCHES=""
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
test_description='remerge-diff handling'
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
|
||||
# This test is ort-specific
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
test_description='git show'
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
|
@ -5,6 +5,7 @@ test_description='pre-commit and pre-merge-commit hooks'
|
||||
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
|
||||
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
||||
|
||||
TEST_PASSES_SANITIZE_LEAK=true
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'root commit' '
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
test_description='git svn authorship'
|
||||
|
||||
TEST_FAILS_SANITIZE_LEAK=true
|
||||
. ./lib-git-svn.sh
|
||||
|
||||
test_expect_success 'setup svn repository' '
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
test_description='git svn dcommit --interactive series'
|
||||
|
||||
TEST_FAILS_SANITIZE_LEAK=true
|
||||
. ./lib-git-svn.sh
|
||||
|
||||
test_expect_success 'initialize repo' '
|
||||
|
Loading…
Reference in New Issue
Block a user