Skip to content

fix: prevent infinite recursion in FlagManager.clearFlags - #1777

Merged
Travja merged 2 commits into
devfrom
split/1677-flagmanager-reentrancy
Jul 23, 2026
Merged

fix: prevent infinite recursion in FlagManager.clearFlags#1777
Travja merged 2 commits into
devfrom
split/1677-flagmanager-reentrancy

Conversation

@Travja

@Travja Travja commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Split out of #1677 (piece 4 of 8 — see that PR for the full breakdown).

What

If a FlagExpireTrigger-driven skill adds a new flag to an entity while FlagManager.clearFlags() is clearing that same entity's flags, the new flag re-creates a FlagData entry, and removing it during the same clear pass re-enters clearFlags() for that entity — recursing indefinitely. This was reportedly observed on player death, where clearing flags can trigger skills that re-flag the dying entity.

Guards clearFlags() with a per-entity "currently clearing" set, so a reentrant call for the same entity becomes a no-op instead of recursing.

Why split out separately

Small, standalone bug fix isolated to one class — easy to review and test on its own (repro: a flag-expire-triggered skill that re-adds a flag to the same entity during clearFlags, e.g. on death).

Testing

Could not build locally (private Maven repo unreachable in this sandbox). Needs manual/CI verification, especially a repro of the original infinite-recursion scenario.


Generated by Claude Code

Split out of #1677 (piece 4 of 8).

If a FlagExpireTrigger-driven skill adds a new flag to an entity while
FlagManager.clearFlags() is clearing that same entity's flags, the new
flag re-creates a FlagData entry, and removing it during the same clear
pass re-enters clearFlags() for that entity, recursing indefinitely
(observed on player death, where clearing flags can trigger skills that
re-flag the dying entity).

Guard clearFlags() with a per-entity "currently clearing" set so a
reentrant call for the same entity is a no-op instead of recursing.
Reproduces the infinite-recursion scenario the guard fixes: a
FlagExpireTrigger-driven skill reacting to FlagExpireEvent by adding a
new flag to the same entity while clearFlags() is still unwinding for
that entity. Without the clearingEntities guard, this recurses through
clear() -> removeFlag() -> (synchronous event) -> addFlag() ->
clearFlags() until the stack overflows; with it, the reentrant call is
a no-op and the newly-added flag survives.
@Travja
Travja merged commit 3cd14ff into dev Jul 23, 2026
3 checks passed
@Travja
Travja deleted the split/1677-flagmanager-reentrancy branch July 23, 2026 02:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants