negotiator/default: avoid stack overflow
mark_common() in negotiator/default.c may overflow the stack due to recursive function calls. Avoid this by instead recursing using a heap-allocated data structure. This is the same case as 4654134976f (negotiator/skipping: avoid stack overflow, 2022-10-25) Reported-by: Xin Xing <xingxin.xx@bytedance.com> Signed-off-by: Han Xin <hanxin.hx@bytedance.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Han Xin committed
Apr 26, 2023 at 21:15 UTC
8e21ff5edb305bcfc12fc782f1c92542c427b624
1 file changed
+29
-10
negotiator/default.c
+29
-10
@@ -55,30 +55,49 @@ static int clear_marks(const char *refname, const struct object_id *oid,
55
static void mark_common(struct negotiation_state *ns, struct commit *commit,
56
int ancestors_only, int dont_parse)
57
{
58
- if (commit != NULL && !(commit->object.flags & COMMON)) {
59
- struct object *o = (struct object *)commit;
58
+ struct prio_queue queue = { NULL };
59
+
60
+ if (!commit || (commit->object.flags & COMMON))
61
+ return;
62
+
63
+ prio_queue_put(&queue, commit);
64
+ if (!ancestors_only) {
65
+ commit->object.flags |= COMMON;
66
61
- if (!ancestors_only)
62
- o->flags |= COMMON;
67
+ if ((commit->object.flags & SEEN) && !(commit->object.flags & POPPED))
68
+ ns->non_common_revs--;
69
+ }
70
+ while ((commit = prio_queue_get(&queue))) {
71
+ struct object *o = (struct object *)commit;
72
73
if (!(o->flags & SEEN))
74
rev_list_push(ns, commit, SEEN);
75
else {
76
struct commit_list *parents;
77
69
- if (!ancestors_only && !(o->flags & POPPED))
70
- ns->non_common_revs--;
78
if (!o->parsed && !dont_parse)
79
if (repo_parse_commit(the_repository, commit))
73
- return;
80
+ continue;
81
82
for (parents = commit->parents;
83
parents;
77
- parents = parents->next)
78
- mark_common(ns, parents->item, 0,
79
- dont_parse);
84
+ parents = parents->next) {
85
+ struct commit *p = parents->item;
86
+
87
+ if (p->object.flags & COMMON)
88
+ continue;
89
+
90
+ p->object.flags |= COMMON;
91
+
92
+ if ((p->object.flags & SEEN) && !(p->object.flags & POPPED))
93
+ ns->non_common_revs--;
94
+
95
+ prio_queue_put(&queue, parents->item);
96
+ }
97
}
98
}
99
+
100
+ clear_prio_queue(&queue);
101
}
102
103
/*