Skip to content

Commit 7199203

Browse files
Martin Ågrengitster
authored andcommitted
object_array: add and use object_array_pop()
In a couple of places, we pop objects off an object array `foo` by decreasing `foo.nr`. We access `foo.nr` in many places, but most if not all other times we do so read-only, e.g., as we iterate over the array. But when we change `foo.nr` behind the array's back, it feels a bit nasty and looks like it might leak memory. Leaks happen if the popped element has an allocated `name` or `path`. At the moment, that is not the case. Still, 1) the object array might gain more fields that want to be freed, 2) a code path where we pop might start using names or paths, 3) one of these code paths might be copied to somewhere where we do, and 4) using a dedicated function for popping is conceptually cleaner. Introduce and use `object_array_pop()` instead. Release memory in the new function. Document that popping an object leaves the associated elements in limbo. The converted places were identified by grepping for "\.nr\>" and looking for "--". Make the new function return NULL on an empty array. This is consistent with `pop_commit()` and allows the following: while ((o = object_array_pop(&foo)) != NULL) { // do something } But as noted above, we don't need to go out of our way to avoid reading `foo.nr`. This is probably more readable: while (foo.nr) { ... o = object_array_pop(&foo); // do something } The name of `object_array_pop()` does not quite align with `add_object_array()`. That is unfortunate. On the other hand, it matches `object_array_clear()`. Arguably it's `add_...` that is the odd one out, since it reads like it's used to "add" an "object array". For that reason, side with `object_array_clear()`. Signed-off-by: Martin Ågren <[email protected]> Reviewed-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent dcb572a commit 7199203

File tree

6 files changed

+25
-10
lines changed

6 files changed

+25
-10
lines changed

builtin/fast-export.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,11 +634,10 @@ static void handle_tail(struct object_array *commits, struct rev_info *revs)
634634
{
635635
struct commit *commit;
636636
while (commits->nr) {
637-
commit = (struct commit *)commits->objects[commits->nr - 1].item;
637+
commit = (struct commit *)object_array_pop(commits);
638638
if (has_unshown_parent(commit))
639639
return;
640640
handle_commit(commit, revs);
641-
commits->nr--;
642641
}
643642
}
644643

builtin/fsck.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,12 +181,7 @@ static int traverse_reachable(void)
181181
if (show_progress)
182182
progress = start_progress_delay(_("Checking connectivity"), 0, 0, 2);
183183
while (pending.nr) {
184-
struct object_array_entry *entry;
185-
struct object *obj;
186-
187-
entry = pending.objects + --pending.nr;
188-
obj = entry->item;
189-
result |= traverse_one_object(obj);
184+
result |= traverse_one_object(object_array_pop(&pending));
190185
display_progress(progress, ++nr);
191186
}
192187
stop_progress(&progress);

builtin/reflog.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ static int commit_is_complete(struct commit *commit)
126126
struct commit *c;
127127
struct commit_list *parent;
128128

129-
c = (struct commit *)study.objects[--study.nr].item;
129+
c = (struct commit *)object_array_pop(&study);
130130
if (!c->object.parsed && !parse_object(&c->object.oid))
131131
c->object.flags |= INCOMPLETE;
132132

object.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,19 @@ static void object_array_release_entry(struct object_array_entry *ent)
353353
free(ent->path);
354354
}
355355

356+
struct object *object_array_pop(struct object_array *array)
357+
{
358+
struct object *ret;
359+
360+
if (!array->nr)
361+
return NULL;
362+
363+
ret = array->objects[array->nr - 1].item;
364+
object_array_release_entry(&array->objects[array->nr - 1]);
365+
array->nr--;
366+
return ret;
367+
}
368+
356369
void object_array_filter(struct object_array *array,
357370
object_array_each_func_t want, void *cb_data)
358371
{

object.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,14 @@ int object_list_contains(struct object_list *list, struct object *obj);
116116
void add_object_array(struct object *obj, const char *name, struct object_array *array);
117117
void add_object_array_with_path(struct object *obj, const char *name, struct object_array *array, unsigned mode, const char *path);
118118

119+
/*
120+
* Returns NULL if the array is empty. Otherwise, returns the last object
121+
* after removing its entry from the array. Other resources associated
122+
* with that object are left in an unspecified state and should not be
123+
* examined.
124+
*/
125+
struct object *object_array_pop(struct object_array *array);
126+
119127
typedef int (*object_array_each_func_t)(struct object_array_entry *, void *);
120128

121129
/*

shallow.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
9999
cur_depth = 0;
100100
} else {
101101
commit = (struct commit *)
102-
stack.objects[--stack.nr].item;
102+
object_array_pop(&stack);
103103
cur_depth = *(int *)commit->util;
104104
}
105105
}

0 commit comments

Comments
 (0)