clean up name allocation in prepare_revision_walk

When we enter prepare_revision_walk, we have zero or more entries in our "pending" array. We disconnect that array from the rev_info, and then process each entry: 1. If the entry is a commit and the --source option is in effect, we keep a pointer to the object name. 2. Otherwise, we re-add the item to the pending list with a blank name. We then throw away the old array by freeing the array itself, but do not touch the "name" field of each entry. For any items of type (2), we leak the memory associated with the name. This commit fixes that by calling object_array_clear, which handles the cleanup for us. That breaks (1), though, because it depends on the memory pointed to by the name to last forever. We can solve that by making a copy of the name. This is slightly less efficient, but it shouldn't matter in practice, as we do it only for the tip commits of the traversal. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Oct 15, 2014 at 18:35 UTC 1da1e07c835e900337714cfad6c32a8dc0b36ac3
1 file changed +7 -7
revision.c
+7 -7
@@ -300,7 +300,7 @@ static struct commit *handle_commit(struct rev_info *revs,
300 revs->limited = 1;
301 }
302 if (revs->show_source && !commit->util)
303 - commit->util = (void *) name;
303 + commit->util = xstrdup(name);
304 return commit;
305 }
306
@@ -2656,15 +2656,16 @@ void reset_revision_walk(void)
2656
2657 int prepare_revision_walk(struct rev_info *revs)
2658 {
2659 - int nr = revs->pending.nr;
2660 - struct object_array_entry *e, *list;
2659 + int i;
2660 + struct object_array old_pending;
2661 struct commit_list **next = &revs->commits;
2662
2663 - e = list = revs->pending.objects;
2663 + memcpy(&old_pending, &revs->pending, sizeof(old_pending));
2664 revs->pending.nr = 0;
2665 revs->pending.alloc = 0;
2666 revs->pending.objects = NULL;
2667 - while (--nr >= 0) {
2667 + for (i = 0; i < old_pending.nr; i++) {
2668 + struct object_array_entry *e = old_pending.objects + i;
2669 struct commit *commit = handle_commit(revs, e->item, e->name);
2670 if (commit) {
2671 if (!(commit->object.flags & SEEN)) {
@@ -2672,10 +2673,9 @@ int prepare_revision_walk(struct rev_info *revs)
2673 next = commit_list_append(commit, next);
2674 }
2675 }
2675 - e++;
2676 }
2677 if (!revs->leak_pending)
2678 - free(list);
2678 + object_array_clear(&old_pending);
2679
2680 /* Signal whether we need per-parent treesame decoration */
2681 if (revs->simplify_merges ||