github JRickey/BattleShip v0.7.2-beta-hotfix

latest release: v0.7.3-beta
5 hours ago

What's Changed

Highlight - Massively Improved Stability

Bug A — never-freed scene arena. Every scene transition allocated a fresh 16 MB arena via libc malloc but never freed the previous one (syTaskmanStartTask, taskman.c:1322). Two consequences:

  • ~16 MB/scene leak — hundreds of MB of mapped-but-dead memory in a long classic-mode session.
  • Far worse: old arenas stayed mapped and readable for the whole process lifetime. A dangling pointer from a prior scene resolved to plausible-looking data — old GBI commands, old vertex blobs, old reloc-token contents — instead of segfaulting at the dangling site. Bugs that should have been one-line fixes were instead presenting as random GBI-walker SIGSEGVs ten frames downstream of the actual cause.

Bug B — 8-bit reloc-token generation byte. The PORT replaces N64 segmented pointers with a 32-bit "reloc token" decoded against a flat lookup table. The table is reset on every scene transition (portRelocResetPointerTable, RelocPointerTable.cpp:130) and the high byte of every token carries a generation that's bumped on each reset to invalidate stale tokens. With 8 bits + the reserved-NULL convention starting at 0x80, only 128 generations existed before wrap. A long classic-mode session (round → CSS → round → results → ...) hits 10–20 scene transitions per attempt; 128 generations was exhausted in well under an hour of play. After wrap, a stale token's generation byte coincidentally re-matched the current one, the decoder accepted it, and returned whatever pointer happened to live at that table index now — typically a different fighter's data of the same shape. Silent wrong-pointer resolution, indistinguishable from a successful lookup.

Bug C — long-lived BSS structures holding raw GObj pointers. Several static / BSS arrays held GObj* (and figatree heap pointers) across scene transitions and were never cleared:

  • gSCManager{1PGame,VS,Transfer}BattleState.players[].fighter_gobj — read across scenes by ftshadow.c:107, sc1pgame.c:825, sc1pbonusstage.c:846-848, itmball.c:392, ftcomputer.c:5623, controller.c:208.
  • sMNVSResultsFighterGObjs[] + sMNVSResultsFigatreeHeaps[] — VS results screen.
  • sMN1PContinueFighterGObj + sMN1PContinueFigatreeHeap — 1P continue prompt.
  • Seven primary GObj* fields the decomp's mnPlayersVSInitPlayer reset overlooked: cursor, puck, type_button, name_emblem_gobj, panel_doors, panel, type, plus figatree_heap. (The decomp clears the secondary GObj fields but missed these primary ones.)

Why this release should massively improve stability

Fixing Bug A turns an entire class of dangling host pointer reads from silent data corruption into a hard SIGSEGV at the read site, any further bugs should be easily to see and patch.

Fixing Bug B extends safety from under an hour of play before silent token aliasing on wrap to days of continuous play

Fixing Bug C cleans four enumerated long-lived structures, the crash that previously hid inside the GBI walker now lands cleanly at mnVSResultsSetPlayerTagPosition:1043 and we can fix it as soon as there's a trace.

In summary: any dangling-pointer related bug now produces a clean stack pointing directly at the offending file and line instead of a random-looking crash dozens of frames further downstream.

Additional Fixes

  • Fix NRage analog accuracy: run formula at firmware int16 scale by @JRickey in #116
  • Fix Windows launch crash since v0.5: noexcept LocateFile (issue #58) by @JRickey in #118

Full Changelog: v0.7.1-beta-hotfix...v0.7.2-beta-hotfix

Don't miss a new BattleShip release

NewReleases is sending notifications on new releases.