MR bugfix: TIA segfault fix #668
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
[0, 159]beforeourPlayerPositionResetWhenTablelookups inRESP0/RESP1(the crash site from Segfault in Montezuma Revenge #11)HMOVEwrapping with proper modular arithmetic for all 5 position registersContext
The segfault in #11 occurs at this line in TIA::poke (case 0x11 — Reset Player 1):
int8_t when = ourPlayerPositionResetWhenTable[myNUSIZ1 & 7][myPOSP1][newx];The table is
int8_t[8][160][160], butmyPOSP1isint16_t. If it escapes[0, 159], the access is out-of-bounds → segfault.Analysis
In an attempt to reproduce #11 I ran the following, but it did not fail on my build - macOS ARM64 even after 5M+ frames of random play with bounds-check assertions compiled in.
Claude audited every code path that modifies the position registers. The HMOVE wrapping arithmetic is actually correct for the motion table's value range of [-15, +8] — the single-step correction (if ≥ 160 then -= 160) maintains the [0, 159] invariant.
I built from source, ran 5M+ frames of Montezuma's Revenge with bounds-check assertions, and nothing triggered. I can't be sure this will fix #11, but I thought you would it interesting regardless.
Since the
int16_tindices are used in array accesses with no validation, it's possible this is the fix. One confirmed unsafe path is state restore (TIA::load), where positions are deserialized from getInt() with no bounds check — RL methods using cloneState/restoreState could trigger this. Platform-specific compiler behaviour (Linux x86_64, aggressive optimizations) may also surface the issue during normal gameplay.