Project

General

Profile

Feature #554 » 0001-Detect-infinite-recursion-when-evaluating-requiremen.patch

main, S3_2 - Alina Lenk, 05/04/2024 11:21 PM

View differences:

common/requirements.c
const struct player *other_player,
const struct requirement *req)
{
/* Recursion detection: Maintain a stack of requirements that are
* currently being checked, and abort if we see the same req twice.
* Note that we're only storing the reqs themselves; we're not making
* an exception for the same req being evaluated against multiple
* different contexts. */
struct recur_node {
const struct recur_node *next;
const struct requirement *req;
};
/* The current deepest level of recursion */
static const struct recur_node *recur_head = nullptr;
/* Stack node representing this call to tri_req_present() */
const struct recur_node recur_current = {
.next = recur_head,
.req = req,
};
const struct recur_node *recur_i;
enum fc_tristate result;
if (context == NULL) {
context = req_context_empty();
}
......
fc_assert_ret_val(req_definitions[req->source.kind].cb != NULL, TRI_NO);
return req_definitions[req->source.kind].cb(nmap, context,
other_player, req);
for (recur_i = recur_head; recur_i != nullptr; recur_i = recur_i->next) {
if (are_requirements_equal(req, recur_i->req)) {
/* Infinite recursion! Abort and return TRI_MAYBE. */
struct astring astr;
log_warn("Infinite recursion when evaluating requirement: %s",
req_to_fstring(req, &astr));
astr_free(&astr);
return TRI_MAYBE;
}
}
/* push */
recur_head = &recur_current;
result = req_definitions[req->source.kind].cb(nmap, context,
other_player, req);
/* pop */
recur_head = recur_current.next;
return result;
}
/**********************************************************************//**
(1-1/2)