Skip to content

Fix sound test menu reloc flood + SSB64_START_SCENE crash on exit#74

Merged
JRickey merged 1 commit intomainfrom
agent/audio-test-debug
May 2, 2026
Merged

Fix sound test menu reloc flood + SSB64_START_SCENE crash on exit#74
JRickey merged 1 commit intomainfrom
agent/audio-test-debug

Conversation

@JRickey
Copy link
Copy Markdown
Owner

@JRickey JRickey commented May 2, 2026

Summary

Two related fixes for the Sound Test menu under the LP64 port. Independently confirmed via SSB64_START_SCENE=59:

  • src/mn/mndata/mnsoundtest.c — pre-fixup the 10 digit Sprites in llIFCommonPlayerDamageFileID at file-load time. mnSoundTestUpdateNumberSprites does sobj->sprite = *lbRelocGetFileData(Sprite*, ...), which value-copies the digit Sprite from file data without going through lbCommonMakeSObjForGObj. On LP64 the file has only had pass1 BSWAP32 applied, so nbitmaps reads as the original ndisplist (36) and the renderer walks 36 garbage Bitmap structs per draw. Symptom: selected-track digits never render and ~35,000 RelocPointerTable invalid/stale-token errors per session. Mirrors the existing ifCommonPlayerDamageSetDigitAttr pattern (same file, same digit sprites, same trap, already fixed there).

  • src/sc/scmanager.c — when SSB64_START_SCENE honours an override, OR LBBACKUP_UNLOCK_MASK_ALL into gSCManagerBackupData.unlock_mask. The decomp assumes scene_prev only ever names a scene the player was allowed to reach; that invariant gates mnDataMakeSoundTest() (and likely other unlock-conditional GObj setups). The override violates it on a fresh save: jumping into Sound Test and pressing B back to Data sets sMNDataOption=SoundTest while sMNDataOptionSoundTestGObj=NULL, crashing in mnDataSetOptionSpriteColors at offset 0xC8. Restoring the invariant at the override site (rather than clamping at every consumer) keeps mndata.c and any future unlock-conditional menus correct without per-site defensive guards.

Verification

  • SSB64_START_SCENE=59 + navigate music/sounds/voices: digits render correctly across all 10 positions, RelocPointerTable error count went from 35,0030, NULL bitmap->buf log went from 200.
  • Same path + B-back into Data menu: lands cleanly on Sound Test option highlighted, no SIGSEGV.

Test plan

  • Load a save with Sound Test unlocked normally, navigate Title → Data → Sound Test, confirm digits render and B-back into Data still works (no regression on the unlock_mask path).
  • SSB64_START_SCENE=59 on fresh save: enter, scrub all three options, B-back to Data, exit to Title — should be clean.
  • Fresh save without override: confirm Sound Test is still gated behind its unlock condition (the override-site code only runs when getenv("SSB64_START_SCENE") != NULL, so normal play is unaffected).

🤖 Generated with Claude Code

mnSoundTestUpdateNumberSprites value-copies digit Sprites with
sobj->sprite = *lbRelocGetFileData(Sprite*, ...), bypassing the
portFixupSprite/Bitmap/SpriteBitmapData chain that lbCommonMakeSObjForGObj
normally applies. Only digit 0 happened to be fixed up (via the line-1421
SObj setup); digits 1-9 stayed in pass1-BSWAP32 form, so nbitmaps read 36
(originally ndisplist), the renderer walked 36 garbage Bitmaps, and
lbCommonDrawSObjBitmap NULL-skipped every draw — selected-track digits
didn't render and the log flooded with ~35k RelocPointerTable stale-token
errors per session. Pre-fixup all 10 digits in mnSoundTestSetupFiles,
mirroring the established ifCommonPlayerDamageSetDigitAttr pattern for
the same file (llIFCommonPlayerDamageFileID).

Separately, SSB64_START_SCENE=59 lets the user jump straight into Sound
Test on a fresh save where LBBACKUP_UNLOCK_MASK_SOUNDTEST isn't set.
mnDataInitVars then maps scene_prev=SoundTest -> sMNDataOption=SoundTest
without validating against the unlock mask (the decomp assumes scene_prev
can only name a reachable scene). Exiting back to Data crashed in
mnDataSetOptionSpriteColors at offset 0xC8 because mnDataMakeSoundTest
was skipped and sMNDataOptionSoundTestGObj stayed NULL. Restore the
invariant at the override site by ORing LBBACKUP_UNLOCK_MASK_ALL into
the backup data when SSB64_START_SCENE is honoured, so every consumer
sees consistent state without each having to defend against the gap.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JRickey JRickey merged commit c5d7abc into main May 2, 2026
@JRickey JRickey deleted the agent/audio-test-debug branch May 3, 2026 16:42
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.

1 participant