diff options
author | Jonathan Tan <jonathantanmy@google.com> | 2022-10-26 02:29:34 +0300 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2022-10-26 03:14:40 +0300 |
commit | 4654134976fd4d80ea664c159f798f21c7917d8c (patch) | |
tree | a30ae251be8a8291989791ce4e985e9652e8b1f4 /negotiator | |
parent | 7d8dc5a1af9da32ac7454499f308db757eb19642 (diff) |
negotiator/skipping: avoid stack overflow
mark_common() in negotiator/skipping.c may overflow the stack due to
recursive function calls. Avoid this by instead recursing using a
heap-allocated data structure.
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'negotiator')
-rw-r--r-- | negotiator/skipping.c | 29 |
1 files changed, 17 insertions, 12 deletions
diff --git a/negotiator/skipping.c b/negotiator/skipping.c index c4398f5ae1..0f5ac48e87 100644 --- a/negotiator/skipping.c +++ b/negotiator/skipping.c @@ -86,21 +86,26 @@ static int clear_marks(const char *refname, const struct object_id *oid, /* * Mark this SEEN commit and all its SEEN ancestors as COMMON. */ -static void mark_common(struct data *data, struct commit *c) +static void mark_common(struct data *data, struct commit *seen_commit) { - struct commit_list *p; + struct prio_queue queue = { NULL }; + struct commit *c; - if (c->object.flags & COMMON) - return; - c->object.flags |= COMMON; - if (!(c->object.flags & POPPED)) - data->non_common_revs--; + prio_queue_put(&queue, seen_commit); + while ((c = prio_queue_get(&queue))) { + struct commit_list *p; + if (c->object.flags & COMMON) + return; + c->object.flags |= COMMON; + if (!(c->object.flags & POPPED)) + data->non_common_revs--; - if (!c->object.parsed) - return; - for (p = c->parents; p; p = p->next) { - if (p->item->object.flags & SEEN) - mark_common(data, p->item); + if (!c->object.parsed) + return; + for (p = c->parents; p; p = p->next) { + if (p->item->object.flags & SEEN) + prio_queue_put(&queue, p->item); + } } } |