Skip to content

Commit 8e21ff5

Browse files
chiyutianyigitster
authored andcommitted
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 4654134 (negotiator/skipping: avoid stack overflow, 2022-10-25) Reported-by: Xin Xing <[email protected]> Signed-off-by: Han Xin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2807bd2 commit 8e21ff5

File tree

1 file changed

+29
-10
lines changed

1 file changed

+29
-10
lines changed

negotiator/default.c

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,30 +55,49 @@ static int clear_marks(const char *refname, const struct object_id *oid,
5555
static void mark_common(struct negotiation_state *ns, struct commit *commit,
5656
int ancestors_only, int dont_parse)
5757
{
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;
6066

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;
6372

6473
if (!(o->flags & SEEN))
6574
rev_list_push(ns, commit, SEEN);
6675
else {
6776
struct commit_list *parents;
6877

69-
if (!ancestors_only && !(o->flags & POPPED))
70-
ns->non_common_revs--;
7178
if (!o->parsed && !dont_parse)
7279
if (repo_parse_commit(the_repository, commit))
73-
return;
80+
continue;
7481

7582
for (parents = commit->parents;
7683
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+
}
8097
}
8198
}
99+
100+
clear_prio_queue(&queue);
82101
}
83102

84103
/*

0 commit comments

Comments
 (0)