Skip to content

Commit b2ccdf7

Browse files
Martin Ågrengitster
authored andcommitted
leak_pending: use object_array_clear(), not free()
Setting `leak_pending = 1` tells `prepare_revision_walk()` not to release the `pending` array, and makes that the caller's responsibility. See 4a43d37 (revision: add leak_pending flag, 2011-10-01) and 353f565 (bisect: use leak_pending flag, 2011-10-01). Commit 1da1e07 (clean up name allocation in prepare_revision_walk, 2014-10-15) fixed a memory leak in `prepare_revision_walk()` by switching from `free()` to `object_array_clear()`. However, where we use the `leak_pending`-mechanism, we're still only calling `free()`. Use `object_array_clear()` instead. Copy some helpful comments from 353f565 to the other callers that we update to clarify the memory responsibilities, and to highlight that the commits are not affected when we clear the array -- it is indeed correct to both tidy up the commit flags and clear the object array. Document `leak_pending` in revision.h to help future users get this right. Signed-off-by: Martin Ågren <[email protected]> Reviewed-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent cb7b29e commit b2ccdf7

File tree

4 files changed

+29
-3
lines changed

4 files changed

+29
-3
lines changed

bisect.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,8 @@ static int check_ancestors(const char *prefix)
826826

827827
/* Clean up objects used, as they will be reused. */
828828
clear_commit_marks_for_object_array(&pending_copy, ALL_REV_FLAGS);
829-
free(pending_copy.objects);
829+
830+
object_array_clear(&pending_copy);
830831

831832
return res;
832833
}

builtin/checkout.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,18 +796,25 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
796796
for_each_ref(add_pending_uninteresting_ref, &revs);
797797
add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING);
798798

799+
/* Save pending objects, so they can be cleaned up later. */
799800
refs = revs.pending;
800801
revs.leak_pending = 1;
801802

803+
/*
804+
* prepare_revision_walk (together with .leak_pending = 1) makes us
805+
* the sole owner of the list of pending objects.
806+
*/
802807
if (prepare_revision_walk(&revs))
803808
die(_("internal error in revision walk"));
804809
if (!(old->object.flags & UNINTERESTING))
805810
suggest_reattach(old, &revs);
806811
else
807812
describe_detached_head(_("Previous HEAD position was"), old);
808813

814+
/* Clean up objects used, as they will be reused. */
809815
clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
810-
free(refs.objects);
816+
817+
object_array_clear(&refs);
811818
}
812819

813820
static int switch_branches(const struct checkout_opts *opts,

bundle.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,14 @@ int verify_bundle(struct bundle_header *header, int verbose)
157157
req_nr = revs.pending.nr;
158158
setup_revisions(2, argv, &revs, NULL);
159159

160+
/* Save pending objects, so they can be cleaned up later. */
160161
refs = revs.pending;
161162
revs.leak_pending = 1;
162163

164+
/*
165+
* prepare_revision_walk (together with .leak_pending = 1) makes us
166+
* the sole owner of the list of pending objects.
167+
*/
163168
if (prepare_revision_walk(&revs))
164169
die(_("revision walk setup failed"));
165170

@@ -176,8 +181,10 @@ int verify_bundle(struct bundle_header *header, int verbose)
176181
refs.objects[i].name);
177182
}
178183

184+
/* Clean up objects used, as they will be reused. */
179185
clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
180-
free(refs.objects);
186+
187+
object_array_clear(&refs);
181188

182189
if (verbose) {
183190
struct ref_list *r;

revision.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,17 @@ struct rev_info {
149149
date_mode_explicit:1,
150150
preserve_subject:1;
151151
unsigned int disable_stdin:1;
152+
/*
153+
* Set `leak_pending` to prevent `prepare_revision_walk()` from clearing
154+
* the array of pending objects (`pending`). It will still forget about
155+
* the array and its entries, so they really are leaked. This can be
156+
* useful if the `struct object_array` `pending` is copied before
157+
* calling `prepare_revision_walk()`. By setting `leak_pending`, you
158+
* effectively claim ownership of the old array, so you should most
159+
* likely call `object_array_clear(&pending_copy)` once you are done.
160+
* Observe that this is about ownership of the array and its entries,
161+
* not the commits referenced by those entries.
162+
*/
152163
unsigned int leak_pending:1;
153164
/* --show-linear-break */
154165
unsigned int track_linear:1,

0 commit comments

Comments
 (0)