Skip to content

Commit 1878b5e

Browse files
avargitster
authored andcommitted
revision.[ch]: provide and start using a release_revisions()
The users of the revision.[ch] API's "struct rev_info" are a major source of memory leaks in the test suite under SANITIZE=leak, which in turn adds a lot of noise when trying to mark up tests with "TEST_PASSES_SANITIZE_LEAK=true". The users of that API are largely one-shot, e.g. "git rev-list" or "git log", or the "git checkout" and "git stash" being modified here For these callers freeing the memory is arguably a waste of time, but in many cases they've actually been trying to free the memory, and just doing that in a buggy manner. Let's provide a release_revisions() function for these users, and start migrating them over per the plan outlined in [1]. Right now this only handles the "pending" member of the struct, but more will be added in subsequent commits. Even though we only clear the "pending" member now, let's not leave a trap in code like the pre-image of index_differs_from(), where we'd start doing the wrong thing as soon as the release_revisions() learned to clear its "diffopt". I.e. we need to call release_revisions() after we've inspected any state in "struct rev_info". This leaves in place e.g. clear_pathspec(&rev.prune_data) in stash_working_tree() in builtin/stash.c, subsequent commits will teach release_revisions() to free "prune_data" and other members that in some cases are individually cleared by users of "struct rev_info" by reaching into its members. Those subsequent commits will remove the relevant calls to e.g. clear_pathspec(). We avoid amending code in index_differs_from() in diff-lib.c as well as wt_status_collect_changes_index(), has_unstaged_changes() and has_uncommitted_changes() in wt-status.c in a way that assumes that we are already clearing the "diffopt" member. That will be handled in a subsequent commit. 1. https://lore.kernel.org/git/[email protected]/ Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent bf20fe4 commit 1878b5e

File tree

7 files changed

+19
-8
lines changed

7 files changed

+19
-8
lines changed

builtin/checkout.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ static void show_local_changes(struct object *head,
629629
diff_setup_done(&rev.diffopt);
630630
add_pending_object(&rev, head, NULL);
631631
run_diff_index(&rev, 0);
632-
object_array_clear(&rev.pending);
632+
release_revisions(&rev);
633633
}
634634

635635
static void describe_detached_head(const char *msg, struct commit *commit)

builtin/stash.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,6 @@ static int check_changes_tracked_files(const struct pathspec *ps)
10471047
goto done;
10481048
}
10491049

1050-
object_array_clear(&rev.pending);
10511050
result = run_diff_files(&rev, 0);
10521051
if (diff_result_code(&rev.diffopt, result)) {
10531052
ret = 1;
@@ -1056,6 +1055,7 @@ static int check_changes_tracked_files(const struct pathspec *ps)
10561055

10571056
done:
10581057
clear_pathspec(&rev.prune_data);
1058+
release_revisions(&rev);
10591059
return ret;
10601060
}
10611061

@@ -1266,9 +1266,8 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
12661266

12671267
done:
12681268
discard_index(&istate);
1269-
UNLEAK(rev);
1270-
object_array_clear(&rev.pending);
12711269
clear_pathspec(&rev.prune_data);
1270+
release_revisions(&rev);
12721271
strbuf_release(&diff_output);
12731272
remove_path(stash_index_path.buf);
12741273
return ret;

diff-lib.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ int index_differs_from(struct repository *r,
662662
diff_flags_or(&rev.diffopt.flags, flags);
663663
rev.diffopt.ita_invisible_in_index = ita_invisible_in_index;
664664
run_diff_index(&rev, 1);
665-
object_array_clear(&rev.pending);
665+
release_revisions(&rev);
666666
return (rev.diffopt.flags.has_changes != 0);
667667
}
668668

range-diff.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,6 @@ int is_range_diff_range(const char *arg)
596596
}
597597

598598
free(copy);
599-
object_array_clear(&revs.pending);
599+
release_revisions(&revs);
600600
return negative > 0 && positive > 0;
601601
}

revision.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,6 +2922,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
29222922
return left;
29232923
}
29242924

2925+
void release_revisions(struct rev_info *revs)
2926+
{
2927+
object_array_clear(&revs->pending);
2928+
}
2929+
29252930
static void add_child(struct rev_info *revs, struct commit *parent, struct commit *child)
29262931
{
29272932
struct commit_list *l = xcalloc(1, sizeof(*l));

revision.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,12 @@ void repo_init_revisions(struct repository *r,
377377
int setup_revisions(int argc, const char **argv, struct rev_info *revs,
378378
struct setup_revision_opt *);
379379

380+
/**
381+
* Free data allocated in a "struct rev_info" after it's been
382+
* initialized with repo_init_revisions().
383+
*/
384+
void release_revisions(struct rev_info *revs);
385+
380386
void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
381387
const struct option *options,
382388
const char * const usagestr[]);

wt-status.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ static void wt_status_collect_changes_index(struct wt_status *s)
662662

663663
copy_pathspec(&rev.prune_data, &s->pathspec);
664664
run_diff_index(&rev, 1);
665-
object_array_clear(&rev.pending);
665+
release_revisions(&rev);
666666
clear_pathspec(&rev.prune_data);
667667
}
668668

@@ -2545,6 +2545,7 @@ int has_unstaged_changes(struct repository *r, int ignore_submodules)
25452545
rev_info.diffopt.flags.quick = 1;
25462546
diff_setup_done(&rev_info.diffopt);
25472547
result = run_diff_files(&rev_info, 0);
2548+
release_revisions(&rev_info);
25482549
return diff_result_code(&rev_info.diffopt, result);
25492550
}
25502551

@@ -2577,7 +2578,7 @@ int has_uncommitted_changes(struct repository *r,
25772578

25782579
diff_setup_done(&rev_info.diffopt);
25792580
result = run_diff_index(&rev_info, 1);
2580-
object_array_clear(&rev_info.pending);
2581+
release_revisions(&rev_info);
25812582
return diff_result_code(&rev_info.diffopt, result);
25822583
}
25832584

0 commit comments

Comments
 (0)