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 [1]. 1. https://lore.kernel.org/git/20221025232934.1504445-1-jonathantanmy@xxxxxxxxxx/ Reported-by: Xin Xing <xingxin.xx@xxxxxxxxxxxxx> Signed-off-by: Han Xin <hanxin.hx@xxxxxxxxxxxxx> --- negotiator/default.c | 16 ++++++++++++---- negotiator/skipping.c | 2 ++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/negotiator/default.c b/negotiator/default.c index f4b78eb47d..6ab7f11409 100644 --- a/negotiator/default.c +++ b/negotiator/default.c @@ -55,9 +55,15 @@ static int clear_marks(const char *refname, const struct object_id *oid, static void mark_common(struct negotiation_state *ns, struct commit *commit, int ancestors_only, int dont_parse) { - if (commit != NULL && !(commit->object.flags & COMMON)) { + struct prio_queue queue = { NULL }; + + prio_queue_put(&queue, commit); + while ((commit = prio_queue_get(&queue))) { struct object *o = (struct object *)commit; + if (commit == NULL || (commit->object.flags & COMMON)) + continue; + if (!ancestors_only) o->flags |= COMMON; @@ -70,15 +76,17 @@ static void mark_common(struct negotiation_state *ns, struct commit *commit, ns->non_common_revs--; if (!o->parsed && !dont_parse) if (repo_parse_commit(the_repository, commit)) - return; + continue; + ancestors_only = 0; for (parents = commit->parents; parents; parents = parents->next) - mark_common(ns, parents->item, 0, - dont_parse); + prio_queue_put(&queue, parents->item); } } + + clear_prio_queue(&queue); } /* diff --git a/negotiator/skipping.c b/negotiator/skipping.c index c7d6ab39bc..3d262b3533 100644 --- a/negotiator/skipping.c +++ b/negotiator/skipping.c @@ -108,6 +108,8 @@ static void mark_common(struct data *data, struct commit *seen_commit) prio_queue_put(&queue, p->item); } } + + clear_prio_queue(&queue); } /* -- 2.40.0