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>
Jonathan Tan committed
Oct 25, 2022 at 16:29 UTC
4654134976fd4d80ea664c159f798f21c7917d8c
1 file changed
+17
-12
negotiator/skipping.c
+17
-12
@@ -86,21 +86,26 @@ static int clear_marks(const char *refname, const struct object_id *oid,
86
/*
87
* Mark this SEEN commit and all its SEEN ancestors as COMMON.
88
*/
89
-static void mark_common(struct data *data, struct commit *c)
89
+static void mark_common(struct data *data, struct commit *seen_commit)
90
{
91
- struct commit_list *p;
91
+ struct prio_queue queue = { NULL };
92
+ struct commit *c;
93
93
- if (c->object.flags & COMMON)
94
- return;
95
- c->object.flags |= COMMON;
96
- if (!(c->object.flags & POPPED))
97
- data->non_common_revs--;
94
+ prio_queue_put(&queue, seen_commit);
95
+ while ((c = prio_queue_get(&queue))) {
96
+ struct commit_list *p;
97
+ if (c->object.flags & COMMON)
98
+ return;
99
+ c->object.flags |= COMMON;
100
+ if (!(c->object.flags & POPPED))
101
+ data->non_common_revs--;
102
99
- if (!c->object.parsed)
100
- return;
101
- for (p = c->parents; p; p = p->next) {
102
- if (p->item->object.flags & SEEN)
103
- mark_common(data, p->item);
103
+ if (!c->object.parsed)
104
+ return;
105
+ for (p = c->parents; p; p = p->next) {
106
+ if (p->item->object.flags & SEEN)
107
+ prio_queue_put(&queue, p->item);
108
+ }
109
}
110
}
111