mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-24 00:02:45 +02:00
findings: fix D255's stale OPEN status (was FIXED+verified, never updated)
The M-140 fix writeup existed in two places -- an orphaned paragraph right after the table row, and the pre-fix narrative in the tail ## D255 section -- but neither ever updated the table row's own status cell, so findings-index.csv (generated from the table) reported a real, fixed, live-verified crash as still OPEN. Consolidated into one writeup in the tail section (which findings-index.csv derives its verdict from per this file's own ctx-opt convention) and fixed the row's status cell to match. Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi
This commit is contained in:
1 parent
e978e526be
commit
8c28453517
2 files changed
+5
-4
No files matched your search
@@ -150,7 +150,7 @@ D251,FIXED,F10 options overlay QoL pass:,"FIXED (port-only, port/src/optionsover
|
||||
D252,OPEN,"Particle effects cycle through a rainbow palette (M-124, user playtest of the v0.2.0-pre candidate).",OPEN — root cause genuinely open as of M-141:
|
||||
D253,FIXED,Facility (and any level with a FORCECROUCH/LADDER linked special tile) SIGSEGV on Linux/Steam Deck —,FIXED — Deck-verified:
|
||||
D254,FIXED,Linux crash handler destroyed its own logs:,FIXED — field-verified.
|
||||
D255,OPEN,Facility firefight SIGSEGV on Steam Deck (v0.2.0-pre CI bundle; D253 fix confirmed working).,OPEN — NULL-model deref in vtxstore_fix_refs confirmed; suspected modify-during-iterate; fix needs rule-#2 sign-off; GE_D255=1 probes in tree.
|
||||
D255,FIXED,Facility firefight SIGSEGV on Steam Deck (v0.2.0-pre CI bundle; D253 fix confirmed working).,"FIXED (M-140) — D3x-class 32-bit pointer truncation (vtxstore_fix_refs read Model* through the mistyped ChrRecord.chrflags 4-byte-enum alias instead of ObjectRecord.model), not the destroy-path race…"
|
||||
D256,FIXED,Saves (and config) silently failed to persist on Linux whenever the game was not launched from the directory containing data/ —,FIXED (path half) — save-flow detail still owed from the user.
|
||||
D257,FIXED,New Game.AllUnlocked option (F10; default flipped OFF for v0.2.0 —,FIXED — verified by user playtest (PR #79 merged); default flipped OFF for v0.2.0 (D259).
|
||||
D259,FIXED,Game.AllUnlocked (D257) breaks audio on a fresh save:,FIXED in v0.2.1 —…
|
||||
|
||||
|
@@ -557,9 +557,8 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
|
||||
| D252 | **Particle effects cycle through a rainbow palette (M-124, user playtest of the v0.2.0-pre candidate).** — full `## D252` entry at file tail | OPEN — root cause genuinely open as of M-141: both named hypotheses refuted (width/height derivation; byte-group order); unverified new lead = shared TMEM slot 0x188 / GL-cache key reuse across the 15 fire records. Cheap repro: bullet-impact sparks. Documented only for v0.2.0-pre per user instruction. |
|
||||
| D253 | **Facility (and any level with a FORCECROUCH/LADDER linked special tile) SIGSEGV on Linux/Steam Deck — `stanCheckLinkedSpecialTile` stores to a garbage…** — full `## D253` entry at file tail | FIXED — Deck-verified: user got past the crouch tile with the re-cut bundle (a *new*, later crash is D255). |
|
||||
| D254 | **Linux crash handler destroyed its own logs: `ge007.crash.log` only ever contained the SIGABRT block, never the original SEGV.** — full `## D254` entry at file tail | FIXED — field-verified. |
|
||||
| D255 | **Facility firefight SIGSEGV on Steam Deck (v0.2.0-pre CI bundle; D253 fix confirmed working).** — full `## D255` entry at file tail | OPEN — NULL-model deref in `vtxstore_fix_refs` confirmed; suspected modify-during-iterate; fix needs rule-#2 sign-off; `GE_D255=1` probes in tree. |
|
||||
| D255 | **Facility firefight SIGSEGV on Steam Deck (v0.2.0-pre CI bundle; D253 fix confirmed working).** — full writeup directly below this table (row status was stale; see M-140 update) | **FIXED (M-140)** — D3x-class 32-bit pointer truncation (`vtxstore_fix_refs` read `Model*` through the mistyped `ChrRecord.chrflags` 4-byte-enum alias instead of `ObjectRecord.model`), not the destroy-path race originally suspected. Verified live on real Steam Deck hardware (Facility + Caverns, zero crashes); Windows 21-level sweep clean. |
|
||||
|
||||
**ROOT-CAUSED AND FIXED, same day, live Deck session over SSH (M-140).** The `objFree`/destroy-path-race theory above was a red herring — set up a real Deck test (SSH access, key-based auth, WSL-cross-compiled local Linux build deployed and run live against the user's own prepared ROM assets), reproduced the crash directly, and symbolized it on-device against the build's own debug info. **First capture with the `GE_D255` probe active:** the probe's `ObjectRecord.model == NULL` guard did NOT fire, yet the game crashed anyway at `vtxstore.c:199` (`var_v1->RootNode`), `FAULT ADDR: 0x10`, `Rdi=(nil)` — a *different* pointer than the one the probe was checking. **Actual bug:** `sub_GAME_7F09BAC4` (`vtxstore_fix_refs`) reads the 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 (both the enum and a pointer are 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 entirely. This is the **exact D3x pointer-width ABI class** documented in AGENTS.md/porting-notes — a struct field misread across the 32→64-bit pointer-width transition — and it was *already flagged* as suspect (a) in this very row's first paragraph, back in the original v0.2.0-pre investigation, then wrongly deprioritized in favor of suspect (b) (the NULL-model theory) once a live register capture happened to show `Rdi=(nil)` and looked like it confirmed (b). 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 the whole investigation at the wrong field for two sessions. **Proof it was the field, not the object:** this session's `GE_D255` probe read the SAME record through the *correctly*-typed `ObjectRecord.model` field (`Model*`, 8 bytes) and it was **always a valid, non-NULL pointer** — the object's model was never actually missing. **Fix (ABI-class, semantics-preserving, `#ifdef PORT`; `src/game/vtxstore.c`, `sub_GAME_7F09BAC4`):** read the pointer through `ObjectRecord.model` (the same union memory, correctly typed as `Model*`) instead of through the mistyped `ChrRecord.chrflags` alias, at both use sites in the function (the `RootNode` walk and the `modelGetNodeRwData` call). Identical bytes and identical result on N64 (both fields are 4 bytes there); correct on 64-bit PC. The earlier `GE_D255` diagnostic skip-guard (which checked the wrong field and would never have actually fired) is removed — it's no longer needed, the record's model was never really missing. **Verified live, in order:** (1) diagnostic build with the guard checking BOTH fields caught the exact moment of divergence — `ObjectRecord.model` valid, `ChrRecord.chrflags`-cast pointer producing the crash — nailing the mechanism beyond doubt; (2) the real fix (no guard, just the corrected field) held through the *entire* Facility level including multiple terminal destructions (the most consistent prior repro) and through Caverns' radio-objective terminals (the second confirmed level) with zero crashes, live on the user's own Steam Deck hardware over the ROM/assets they already had prepared. Windows rebuild + full 21-level `verify.sh sweep` also run this session as the standard regression gate. | **FIXED** — root-caused (D3x-class 32-bit pointer truncation via a mistyped enum-to-pointer cast, not a destroy-path race) and verified live on real Steam Deck hardware across both confirmed-repro levels (Facility, Caverns), zero crashes; Windows sweep clean. The separate audio-thread crash (D285) is untouched by this fix. |
|
||||
| D256 | **Saves (and config) silently failed to persist on Linux whenever the game was not launched from the directory containing `data/` — reported as "saves do not…** — full `## D256` entry at file tail | FIXED (path half) — save-flow detail still owed from the user. |
|
||||
| D257 | **New `Game.AllUnlocked` option (F10; default flipped OFF for v0.2.0 — see D259): skip N64 progression entirely — all 21 solo levels selectable at every…** — full `## D257` entry at file tail | FIXED — verified by user playtest (PR #79 merged); default flipped OFF for v0.2.0 (D259). |
|
||||
| D259 | **`Game.AllUnlocked` (D257) breaks audio on a fresh save: with it ON, music and SFX load at volume 0 (silence). v0.2.0 ships with `AllUnlocked` default OFF.** — full `## D259` entry at file tail | **FIXED in v0.2.1** —… |
|
||||
@@ -10927,7 +10926,9 @@ crash class C2 (Facility `-level_34`, Runway `-level_35`): `import_texture_i8` A
|
||||
|
||||
**Facility firefight SIGSEGV on Steam Deck (v0.2.0-pre CI bundle, D253 fix confirmed working — user got past the opening crouch tile).** Crash during gunplay; abort-unwind backtrace points at `sub_GAME_7F09BAC4` (`vtxstore.c:158`) ← `sub_GAME_7F09BBBC` (`:220`) ← `lvlManageMpGame` (`lv.c:1302`) ← `bossMainloop` (`boss.c:567`). Disassembling the exact CI binary at the fault PC (`0x200db135`) gives `mov 0x14(%rax),%edi; mov 0x10(%rdi),%rax`: the function walks the active PropRecord list keeping `type == 1` — which is **PROP_TYPE_OBJ, not CHR** (the decompiler cast to the union's first member and misnamed the field `ChrRecord.chrflags`; it is actually `ObjectRecord.model` at `0x14`) — then dereferences `model->obj`. Two port-relevant wrinkles: (a) the load is **32-bit zero-extended** because the decomp types the field through the `CHRFLAG` enum, so a model pointer ≥ 4 GB would truncate to garbage; (b) the loop skips records whose `model->obj` is NULL but *dereferences* `model` unconditionally, so an active object with a NULL/freed `model` faults — plausible in a firefight where destructibles (crates etc.) die. Not reproduced on WSL after equivalent play. **Register capture (D254 format, 2026-09-13):** two more Deck crashes — Bunker mid-firefight, then Frigate with ~3 NPCs alive; log: `SIGNAL: 11 / FAULT ADDR: 0x10 / Rax=0x701e5f54 Rdi=(nil) / PC 0x200db135`. `Rdi` = the record's model value = **exactly NULL** → case (b) confirmed: an active PROP_TYPE_OBJ record with a NULL `model`, dereferenced by the unconditional `mov 0x10(%rdi),%rax`; truncation (a) and stale/garbage pointers are ruled out. Faulting PC matches the recorded disassembly (`sub_GAME_7F09BAC4` = `vtxstore_fix_refs`). Grep-verified: nothing in game code ever writes NULL into `ObjectRecord.model` — `clear_model_obj()` nulls `model->obj` only, and `objInit`/spawn paths only activate a record once model ≠ NULL — so the NULL comes from either a fresh/uninitialized record slot being activated or a destroy-path ordering race (model freed/nulled while the record is still active this tick). **Fix constraint:** any guard lands in game code (`vtxstore.c`) → needs rule-#2 sign-off; `port/` cannot intercept this dereference. Next: (1) decision on whether a NULL-model skip in `vtxstore_fix_refs` qualifies as an ABI-class exception (semantics-preserving defensive guard, PD analogue check); (2) if yes, add it plus a `#ifdef PORT` trace at the deactivation/model-free sites to name the path that leaves the record model-less. **Corrected, deterministic repro (v0.2.1 user testing, 2026-09-15, superseding the initial report): the trigger is Facility's computer terminals — the ones you ACTIVATE (interact with, not shoot/destroy) to open a door for level progression.** User confirms this is consistent/reliably reproducible on those specific terminals, on Steam Deck **and** Linux generally (not Deck-hardware-specific). This is a much stronger lead than the original "sometimes during firefights" — a terminal activation deactivating/freeing its associated object model while the record briefly stays active this tick is fully consistent with the destroy-path-ordering theory above, just via a scripted trigger instead of combat destruction, and gives a deterministic repro instead of a probabilistic one. **Next session should reproduce via terminal activation specifically**, not generic combat — much cheaper to instrument. **M-140: added a diagnostic probe (`GE_D255`, off by default, `#ifdef PORT`) — `vtxstore.c`'s `sub_GAME_7F09BAC4` now skips-and-logs instead of dereferencing when it finds a NULL model on an active OBJ record (identity + state fields), and `propobj.c`'s `objFree` logs every free call for correlation. Attempted a live Windows repro this session (5 terminal activations across 3 Facility launches, one direct `-level_34` boot each time): zero probe hits, zero crashes — Windows does not reproduce this, consistent with the existing WSL-negative result. Two negatives (WSL, native Windows) against one positive (Linux/Steam Deck) points at something genuinely platform-specific (allocator/timing), not a Windows-reachable path — don't spend further Windows session time chasing a live repro.** The probes are harmless (env-gated, zero behavior change when unset) and committed so a Linux/Deck session can set `GE_D255=1` and get the trace directly. **User report, 2026-09-15 (same day, later, real Steam Deck hardware on the published v0.2.1 release — unverified by this session, logging as reported, not re-asserting the activation theory as wrong):** Facility crashes **consistently on terminals being destroyed** (shot), not (only) on activation. Frigate crashed once during this same testing pass, specifics not recorded. Shooting terminals elsewhere/other attempts did not reliably reproduce. This is closer to the *original* pre-M-139 framing (combat/destructibles triggering the NULL-model race) than the M-139 "corrected, activation-Line truncated
|
||||
|
||||
> The §F row had no status cell; the table row's status is derived from this entry's verdict text (ctx-opt Bucket B, 2026-09-15).
|
||||
**ROOT-CAUSED AND FIXED, same day, live Deck session over SSH (M-140).** The `objFree`/destroy-path-race theory above was a red herring — set up a real Deck test (SSH access, key-based auth, WSL-cross-compiled local Linux build deployed and run live against the user's own prepared ROM assets), reproduced the crash directly, and symbolized it on-device against the build's own debug info. **First capture with the `GE_D255` probe active:** the probe's `ObjectRecord.model == NULL` guard did NOT fire, yet the game crashed anyway at `vtxstore.c:199` (`var_v1->RootNode`), `FAULT ADDR: 0x10`, `Rdi=(nil)` — a *different* pointer than the one the probe was checking. **Actual bug:** `sub_GAME_7F09BAC4` (`vtxstore_fix_refs`) reads the 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; on 64-bit PC the cast reads just the pointer's low 32 bits and zero-extends it, discarding the real high bits — the exact D3x pointer-width ABI class. `(nil)` is exactly what that truncation produces whenever the real pointer's low 32 bits happen to be zero, which is what pointed two prior sessions at the wrong (NULL-model/destroy-race) theory. **Proof it was the field, not the object:** reading the same record through the correctly-typed `ObjectRecord.model` field showed it was **always a valid, non-NULL pointer**. **Fix (ABI-class, semantics-preserving, `#ifdef PORT`; `src/game/vtxstore.c`):** read the pointer through `ObjectRecord.model` instead of the mistyped `ChrRecord.chrflags` alias, at both use sites. The earlier `GE_D255` diagnostic guard (which checked the wrong field) is removed as unneeded. **Verified live:** held through the entire Facility level (multiple terminal destructions) and Caverns' radio-objective terminals with zero crashes, on the user's own Steam Deck hardware; Windows rebuild + full 21-level `verify.sh sweep` also clean. The separate audio-thread crash (D285) is untouched by this fix.
|
||||
|
||||
**Status (from §F table):** FIXED (M-140) — root-caused as a D3x-class 32-bit pointer truncation (not a destroy-path race) and verified live on real Steam Deck hardware across both confirmed-repro levels (Facility, Caverns).
|
||||
|
||||
## D152+ — D152 addendum — static audit + narrow fix (M-31).
|
||||
|
||||
|
||||
Reference in new issue
Block a user