Skip to content

Fix pline recursion loop when descending/ascending stairs - #6

Merged
Critlist merged 1 commit into
mainfrom
fix/issue-5-pline-recursion
Aug 13, 2026
Merged

Fix pline recursion loop when descending/ascending stairs#6
Critlist merged 1 commit into
mainfrom
fix/issue-5-pline-recursion

Conversation

@Critlist

Copy link
Copy Markdown
Owner

Summary

  • Fixes pline recursion loop while getting down the stairs #5 — infinite pru()newsym()pline()pru() recursion that could crash the game with a stack overflow when taking stairs.
  • Root cause: pru()'s "track last displayed @" tracking (a modern addition for redraw sync on modern terminals) has no notion of level identity, so after dodown()/doup() it holds the previous level's last position. pru() then calls newsym() on that foreign coordinate, which is frequently unconnected rock (typ==0) — hitting newsym()'s original-1982 pline("Bad newsym...") diagnostic. pline() can re-enter pru(), and since the tracking state was only updated after the newsym() call, the re-entrant call sees the same stale state and repeats forever.
  • Two changes, both documented per docs/CODING_STANDARDS.md:
    • dodown()/doup() now call a new clearpru() right after moving the player onto the new level, so stale cross-level coordinates are never handed to newsym().
    • pru() now updates its tracking state before calling newsym() instead of after, so even a re-entrant call can no longer repeat the same call — makes the recursion structurally impossible regardless of cause.
  • All original 1982 logic (including the "Bad newsym" diagnostic itself) is preserved untouched; only the modern addition's ordering/scope changed.

Test plan

  • Full project build (cmake --build build) succeeds cleanly.
  • Standalone repro harness (not checked in) built against both the pre-fix and post-fix hack.pri.c, reproducing the exact reported call sequence (pru at old position → level-data corrupted the way an unconnected new-level tile would be → pru at new position with flags.dscr set):
    • Old code: reliably SIGSEGVs after ~7000 recursive frames.
    • Fixed code: returns cleanly (exit 0).
  • Manual playtest of repeated stair traversal in a real terminal session (recommend before merge, given this touches the render path).

🤖 Generated with Claude Code

pru()'s "track last displayed @" tracking (added to keep redraws in
sync on modern terminals) has no notion of which level it belongs to.
After dodown()/doup() swap in a new level's map data, the tracked
position still refers to the previous level, so pru() calls newsym()
on foreign coordinates that are frequently unconnected rock (typ==0).
That hits newsym()'s default case and its original 1982 "Bad newsym"
diagnostic, which calls pline(), which can re-enter pru() — and since
the tracking state was only updated *after* the newsym() call, the
re-entrant call sees the same stale state and repeats the same
newsym() call forever, overflowing the stack.

Fixes this with two changes: dodown()/doup() now invalidate the
tracking via a new clearpru() so stale cross-level coordinates are
never passed to newsym() in the first place, and pru() now updates its
tracking state before calling newsym() instead of after, so even a
re-entrant call can no longer repeat the same call.

Verified with a standalone harness linking the old and fixed hack.pri.c
against the same repro scenario: the old code reliably SIGSEGVs after
~7000 recursive frames, the fixed code returns cleanly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Critlist
Critlist merged commit 9275a77 into main Aug 13, 2026
5 checks passed
@Critlist
Critlist deleted the fix/issue-5-pline-recursion branch August 13, 2026 00:01
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.

pline recursion loop while getting down the stairs

1 participant