mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
Root-caused via a live Steam Deck session over SSH: sub_GAME_7F09BAC4 (vtxstore_fix_refs) read an active OBJ record's Model* through ((Model*)((ChrRecord*)prop->chr)->chrflags) - a union pun onto ChrRecord.chrflags, which is typed CHRFLAG, a 4-byte enum. On 32-bit N64 this is bit-exact (the enum and a pointer are both 4 bytes, so casting the enum's value to Model* reproduces the real stored bytes). On 64-bit PC, Model* is 8 bytes but the enum read is still only 4 - the cast reads just the pointer's low 32 bits as an int and zero-extends it back to a 64-bit address, discarding the real high bits. This is the D3x pointer-width ABI class from AGENTS.md - a struct field misread across the 32-to-64-bit pointer-width transition. This was actually flagged as suspect (a) in the very first D255 investigation, then wrongly deprioritized in favor of a "destroy-path race" theory once a register capture happened to show Rdi=(nil) and looked like it confirmed a different, unrelated NULL-model theory. It didn't: (nil) is exactly what a 32-bit-truncated read produces whenever the real pointer's low 32 bits happen to be zero - a coincidence that pointed two sessions' worth of investigation at the wrong field. Proof: reading the same record through the correctly 64-bit-typed ObjectRecord.model field (this session's diagnostic probe) was always a valid, non-NULL pointer - the object's model was never actually missing. Fix: read the pointer through ObjectRecord.model (the same union memory, correctly typed) instead of through the mistyped ChrRecord.chrflags alias, at both use sites in the function. Identical bytes and identical result on N64; correct on 64-bit PC. Verified live on the user's own Steam Deck hardware over SSH, running their own prepared ROM assets: held through the entire Facility level including repeated terminal destruction (the most consistent prior repro) and through Caverns' radio-objective terminals (the second confirmed level), zero crashes. Windows rebuild + full 21-level verify.sh sweep also clean. The separate audio-thread crash (D285, caught during this same live session) is unrelated and unaffected by this fix.