fix(model): D191 — Bunker ii / Statue crash: bondviewSelectCuff Switches stride

bondviewSelectCuff byte-indexed header->Switches (a ModelNode* array,
8-byte stride on PC per D43/D45) with `offset = switchindex << 2`, the
N64 4-byte-pointer stride. Every base[N] deref then landed mid-slot and
produced a half-word-swapped pointer (0x70267a90 -> 0x70267a9000000000),
non-NULL by luck, handed straight into modelGetNodeRwData -> SIGSEGV on
the frame the player fires (gunUpdateAndFire -> bondviewSelectCuff,
switchindex=29). Confirmed by a gdb backtrace from the shipped v0.1.0
bundle on the Bunker ii first-guard-kill repro.

Identical to D141, which fixed the same Switches byte-index bug in
gunfire.c; this call site was missed. Fix is PORT-only:
`offset = switchindex * sizeof(ModelNode *)`. The downstream
`base = (u8*)switches + offset` math and the #else N64 line are unchanged.
ABI / pointer-width only (D3x class) — no game-logic change.

Verified: build clean; -level_09 golden framediff 3/3; -level_27 +
scripted-fire crash-free; user playtest of Bunker ii + Statue both
crash-free -> 21/21 solo levels crash-free (v0.2.0 gate).
This commit is contained in:
James Dansereau committed 2026-09-08 09:12:12 -04:00
1 parent 524a95f824
commit 61a2073470
1 file changed
+11
+11
View File
@@ -8381,7 +8381,18 @@ void bondviewSelectCuff(Model *model, ModelFileHeader *header, s32 switchindex)
local = fileGetBondForCurrentFolder();
switches = header->Switches;
#ifdef PORT
/* D191: same bug class as D141 (gunfire.c). `header->Switches` is a
* ModelNode* array -- 8-byte stride on PC, not 4 -- but this code byte-
* indexes it as `switchindex * 4`, so every `base[N]` below reads a
* misaligned half-pointer (a bogus non-NULL ModelNode*) and
* modelGetNodeRwData faults. Seen killing the first Bunker ii guard and
* on Statue after the Trevelyan cutscene. Use the real pointer stride;
* the `base = (u8*)switches + offset` math downstream is unchanged. */
offset = switchindex * (s32) sizeof(ModelNode *);
#else
offset = switchindex << 2;
#endif
if (1);