git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 3/6] leak_pending: use `object_array_clear()`, not `free()`

From
MÅMartin Ågren <martin.agren@gmail.com>
Date
Sep 22, 2017, 23:34 UTC
Message-ID
<d4df674923b0dbc5c2e232cdc56a75205653d275.1506120292.git.martin.agren@gmail.com>
In-Reply-To
<cover.1506120291.git.martin.agren@gmail.com>

Setting `leak_pending = 1` tells `prepare_revision_walk()` not to release the `pending` array, and makes that the caller's responsibility. See 4a43d374f (revision: add leak_pending flag, 2011-10-01) and 353f5657a (bisect: use leak_pending flag, 2011-10-01).

Commit 1da1e07c8 (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 353f5657a 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 <martin.agren@gmail.com>
---
 bisect.c           |  3 ++-
 builtin/checkout.c |  9 ++++++++-
 bundle.c           |  9 ++++++++-
 revision.h         | 11 +++++++++++
 4 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/bisect.c b/bisect.c
index a9fd9fbc6..fc797f6ae 100644
--- a/bisect.c
+++ b/bisect.c
@@ -826,7 +826,8 @@ static int check_ancestors(const char *prefix)
 
 	/* Clean up objects used, as they will be reused. */
 	clear_commit_marks_for_object_array(&pending_copy, ALL_REV_FLAGS);
-	free(pending_copy.objects);
+
+	object_array_clear(&pending_copy);
 
 	return res;
 }
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2d75ac66c..52f1b6770 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -796,9 +796,14 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
 	for_each_ref(add_pending_uninteresting_ref, &revs);
 	add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING);
 
+	/* Save pending objects, so they can be cleaned up later. */
 	refs = revs.pending;
 	revs.leak_pending = 1;
 
+	/*
+	 * prepare_revision_walk (together with .leak_pending = 1) makes us
+	 * the sole owner of the list of pending objects.
+	 */
 	if (prepare_revision_walk(&revs))
 		die(_("internal error in revision walk"));
 	if (!(old->object.flags & UNINTERESTING))
@@ -806,8 +811,10 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new)
 	else
 		describe_detached_head(_("Previous HEAD position was"), old);
 
+	/* Clean up objects used, as they will be reused. */
 	clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
-	free(refs.objects);
+
+	object_array_clear(&refs);
 }
 
 static int switch_branches(const struct checkout_opts *opts,
diff --git a/bundle.c b/bundle.c
index d15db03c8..c092d5d68 100644
--- a/bundle.c
+++ b/bundle.c
@@ -157,9 +157,14 @@ int verify_bundle(struct bundle_header *header, int verbose)
 	req_nr = revs.pending.nr;
 	setup_revisions(2, argv, &revs, NULL);
 
+	/* Save pending objects, so they can be cleaned up later. */
 	refs = revs.pending;
 	revs.leak_pending = 1;
 
+	/*
+	 * prepare_revision_walk (together with .leak_pending = 1) makes us
+	 * the sole owner of the list of pending objects.
+	 */
 	if (prepare_revision_walk(&revs))
 		die(_("revision walk setup failed"));
 
@@ -176,8 +181,10 @@ int verify_bundle(struct bundle_header *header, int verbose)
 				refs.objects[i].name);
 		}
 
+	/* Clean up objects used, as they will be reused. */
 	clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS);
-	free(refs.objects);
+
+	object_array_clear(&refs);
 
 	if (verbose) {
 		struct ref_list *r;
diff --git a/revision.h b/revision.h
index bc18487d6..3162cc78e 100644
--- a/revision.h
+++ b/revision.h
@@ -149,6 +149,17 @@ struct rev_info {
 			date_mode_explicit:1,
 			preserve_subject:1;
 	unsigned int	disable_stdin:1;
+	/*
+	 * Set `leak_pending` to prevent `prepare_revision_walk()` from clearing
+	 * the array of pending objects (`pending`). It will still forget about
+	 * the array and its entries, so they really are leaked. This can be
+	 * useful if the `struct object_array` `pending` is copied before
+	 * calling `prepare_revision_walk()`. By setting `leak_pending`, you
+	 * effectively claim ownership of the old array, so you should most
+	 * likely call `object_array_clear(&pending_copy)` once you are done.
+	 * Observe that this is about ownership of the array and its entries,
+	 * not the commits referenced by those entries.
+	 */
 	unsigned int	leak_pending:1;
 	/* --show-linear-break */
 	unsigned int	track_linear:1,
-- 
2.14.1.727.g9ddaf86
Previous: Martin ÅgrenNext: Jeff King
Message 8 of 27 in “diff-lib: clear `pending` object-array in `index_differs_from()`”
  1. diff-lib: clear `pending` object-array in `index_differs_from()`Martin Ågren, Sep 20, 2017
  2. Jeff KingSep 20, 2017
  3. Martin ÅgrenSep 21, 2017
  4. Jeff KingSep 21, 2017
  5. 0/6 reroll ma/plugleaks; more `object_array`-fixesMartin Ågren, Sep 22, 2017
  6. 1/6 builtin/commit: fix memory leak in `prepare_index()`Martin Ågren, Sep 22, 2017
  7. 2/6 commit: fix memory leak in `reduce_heads()`Martin Ågren, Sep 22, 2017
  8. 3/6 leak_pending: use `object_array_clear()`, not `free()`Martin Ågren, Sep 22, 2017
  9. Jeff KingSep 23, 2017
  10. 4/6 object_array: use `object_array_clear()`, not `free()`Martin Ågren, Sep 22, 2017
  11. Jeff KingSep 23, 2017
  12. Martin ÅgrenSep 23, 2017
  13. 5/6 object_array: add and use `object_array_pop()`Martin Ågren, Sep 22, 2017
  14. Jeff KingSep 23, 2017
  15. Martin ÅgrenSep 23, 2017
  16. Jeff KingSep 23, 2017
  17. 6/6 pack-bitmap[-write]: use `object_array_clear()`, don't leakMartin Ågren, Sep 22, 2017
  18. Jeff KingSep 23, 2017
  19. Jeff KingSep 23, 2017
  20. Martin ÅgrenSep 23, 2017
  21. Jeff KingSep 23, 2017
  22. Jeff KingSep 23, 2017
  23. Martin ÅgrenSep 24, 2017
  24. Jeff KingSep 25, 2017
  25. Martin ÅgrenOct 1, 2017
  26. Junio C HamanoSep 24, 2017
  27. Martin ÅgrenSep 24, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.