Repository navigation
Port: fix the Help and Monica inventory crashes and effects stuck bright - #122
Merged
Merged
Conversation
carrdylan52
marked this pull request as draft
October 19, 2026 00:55
MenuManualInit fills five 10-row Help columns (entries 0-49) and reads manual_boot_event_no[entry] for each, but the table has 47 entries. Retail reads the table's padding and the next table's pointer there. In C++ that read is undefined, and since Release builds moved to -O3 with ThinLTO clang drops the loop exit for the last column (MenuDCMsg[8]). The loop then writes values[], value_width[] and item_mes[] past the window until it faults, so opening Help from the dungeon menu crashed. The PC copy of menuop.cpp now gives the table 50 entries. Entries 47-49 have no manual page and no event flag, so they stay locked. The PS2 source and its data layout are unchanged.
Since the native motion rework (c0f07fe) each action's channels are sliced to its KEY interval and posed at local frames clamped to the action's end. The material, camera and vertex channels still go through the game's MotionProc, which interpolates toward the next key; at an action's last frame there is none, so it divides zero by zero and the material alpha and colour become NaN. The full retail motion carried on past the KEY interval, so the game never hit this. Effects that fade out by material transparency then drew at full brightness when their action ended: the chest-opening light motes and the weapon build-up sunburst stayed lit for as long as the effect was held, and Max's and Monica's charge burst flashed back for the frames it sat on its last key. Auxiliary channels at or past their last key now take that key's value through the blend form of MotionProc, which reads it without dividing. Frames before an action's end render byte-identically.
The bait hit-test looked up Max's esa0 part before checking the page. Monica's form has no esa0, so GetPartInfo walked onto a freed part with a null name and strcmp read address 0. Opening the inventory in the prologue battle crashed as soon as the mouse moved. Check the page first, and look parts up in the mouse code with a lookup that skips freed parts, as GetPutPosXY already does.
carrdylan52
force-pushed
the
pr/crash-fixes
branch
from
October 19, 2026 01:11
3c9ea2d to
e88420e
Compare
carrdylan52
marked this pull request as ready for review
October 19, 2026 01:34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Two crashes and one regression that leaves effects stuck at full brightness. All three were found in playtesting and reproduce on current master. Each fix is its own commit.
Opening Help from the dungeon menu crashes (Release builds)
Before:
MenuManualInitfills five 10-row Help columns (entries 0–49), butmanual_boot_event_nohas 47 entries. In the PAL ELF the 94-byte table sits at 0x3597d0 and the next pointer table at 0x359830. So entry 47 reads two padding bytes, and entries 48–49 read the first pointer. In C++ that read is undefined. In Release builds (-O3, ThinLTO), the last column's loop in the generated code has no exit. It writesvalues[],value_width[]anditem_mes[]past the window until it faults.After: Help opens. The PC copy of
menuop.cpppads the table to 50 entries with -1, so rows 47–49, which have no manual page, stay locked. The PS2 source and its data layout are unchanged.How: a new fixup in
scripts/port/header_fixups.py, covered byscripts/port/test_header_fixups.py.Effects stuck at full brightness when their action ends (regression from c0f07fe)
Before: each action's channels are sliced to its KEY interval and posed at local frames clamped to the action's end. The material, camera and vertex channels still go through
MotionProc. On an action's last frame it picks the final key as both endpoints and divides by their zero frame difference, so material alpha and colour become NaN. As a result:After: auxiliary channels at or past their last key take that key's value through the blend form of
MotionProc, which doesn't divide. Frames before an action's end are unchanged.Opening the inventory in Monica's prologue crashes when the mouse moves
Before: the bait hit-test looked up Max's
esa0part before checking which page was open. Monica's form has noesa0, soGetPartInforeached a freed part with a null name, andstrcmpread address 0 (menu_mouse_item.cppBaitHit→GetPartInfo→strcmp).After: the page is checked first, and the mouse code looks parts up with
MenuMouseFindPart, which skips freed parts asGetPutPosXYalready does.Tests:
Headless replays, each run on master and then on this branch:
tools/input/help-mouse.inputfrom--jump dungeon:0:1: master segfaults; this branch shows the Help list.tools/input/area-dungeon-treasure.inputat frame 3700: master shows the chest motes lit under the "Obtained" message; this branch shows none.tools/input/area-dungeon-ranged.inputat frame 3298: master shows the charge rings back after release; this branch shows none.--jump opening, open Item and move the mouse: master crashes inBaitHit; this branch doesn't.