From 92986a07a94b60b8a714825c12937ff979eb0341 Mon Sep 17 00:00:00 2001 From: dolent Date: Tue, 29 Sep 2026 13:26:20 -0700 Subject: [PATCH] docs: D420 findings entry (crouched-rifle firing animation table: linker adjacency) Co-Authored-By: Claude Fable 5.1 (cherry picked from commit d954dfb581900eff9aa0dad58b337d6bc990b726) --- docs/dev/findings-index.csv | 1 + docs/dev/findings.md | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/docs/dev/findings-index.csv b/docs/dev/findings-index.csv index 5d06e463..1565ef92 100644 --- a/docs/dev/findings-index.csv +++ b/docs/dev/findings-index.csv @@ -285,6 +285,7 @@ D405,CLOSED,"fast3d/OpenGL: MSAA above the driver max black-screens; two glBindF D406,RESOLVED,front-end PC Options screen:,"RESOLVED (2026-09-28, port-layer only, Steam Deck-validated):" D407,PARTIAL,Tanks cannot be boarded/exited on PC —,"PARTIAL (fix landed in v0.4.0, port-only):" D408,OPEN,Game.SkipIntro skips the post-mission failure dossier:,"OPEN (cosmetic, not root-caused past the handoff site)." +D420,FIXED,Crouched-rifle firing animation (crouched_rifle_firing_animation_groupA) never resolved on PC -> SIGSEGV in modelConstrainOrWrapAnimFrame when an MP player cro…,"FIXED — layout only (§D5 linker adjacency, D164 class):" MACOS-WEAK-ALIAS,FIXED,macOS/arm64 (M0.4): #pragma weak X = Y has no Mach-O equivalent —,"FIXED (macOS port, lv.c/spectrum.c/objective_status.c) —" MACOS-LIBCXX-SHIMS,FIXED,macOS/arm64 (M0.6): the decomp's include/ stubs shadow libc++'s wrapper headers —,"FIXED (macOS port) — new port/shim/math.h + generated hostmath.h; the existing host{string,stdlib,stddef}.h.in now also pull libc++'s c++/v1/.h wrapper, guarded && defined(__cplusplus)." MACOS-64BIT-GATE,FIXED,"macOS/arm64 (M0.2): __x86_64__ was used as the ""64-bit PC"" gate —","FIXED — 22 sites in 14 src/+assets/ files and port/include/pc_protos.h now use PLATFORM_64BIT (defined by CMake on every 64-bit PC target, undefined on N64, so the N64 branch is unchanged)." diff --git a/docs/dev/findings.md b/docs/dev/findings.md index d9768361..87a3ec5a 100644 --- a/docs/dev/findings.md +++ b/docs/dev/findings.md @@ -693,6 +693,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121). | D406 | **front-end PC Options screen: long sections (INPUT, 17 visible rows) run off the bottom of the 440x330 paper, and rows past the silent 14-row page cap (Crouch mode, Reset to defaults, Bindings…) are unreachable from the front screen** (user report 2026-09-28, v0.4.0 pre-push review) — full `## D406` entry at file tail | RESOLVED (2026-09-28, port-layer only, Steam Deck-validated): in-section pagination in `frontoptions.c` (11 rows/page; the vertical stepper crosses page boundaries both ways; dim 'Page p/N' marker + bottom hint on every page; slider bars start past long labels; F10 overlay untouched). D406b/c/d same-cycle refinements (label/track overlap, hint visibility/wording, hint position). | | D407 | **Tanks cannot be boarded/exited on PC — the v0.4.0 use/reload split (D378/D393) removed the B-button tap the engine's tank handlers in `bondview2.c` consume (user report 2026-09-28, Runway/Streets)** — full `## D407` entry at file tail | PARTIAL (fix landed in v0.4.0, port-only): present `GE_CONT_B` on the use (E / pad A) rising edge only while `g_PlayerIsInTank == 1` or `g_BondCanEnterTank != 0`; E keeps its D378 no-reload-fallback semantics elsewhere, N64 layout unaffected. D407(b) same cycle: front PC Options page-edge highlight clamp + mouse-wheel / W-S paging (wheel queue consumed on the menu, D223); its wheel mapping shipped inverted and was fixed to match W/S (wheel up = step up). D407(c): board-animation lockout, menu-accept B gate in tank states, in-tank aim routed through the legacy velocity stick + `Input.TankAimScale` knob. RESOLVED 2026-09-28: all port-only (src/game zero-diff), 10 TANKDBG probes stripped, release binary verified clean, user live tank drive signed off (board + exit OK, aim feel good). | | D408 | **`Game.SkipIntro` skips the post-mission failure dossier: with it on, entering a level then aborting (watch Z+A) or dying (KIA) returns straight to the menus — no REPORT / "Mission status: KILLED IN ACTION / ABORTED" screen** (user report 2026-09-28; save/AllUnlocked ruled out) — full `## D408` entry at file tail | OPEN (cosmetic, not root-caused past the handoff site). v0.4.0 decision: SkipIntro stays EXPERIMENTAL / not recommended for regular users — F10 row relabelled "Skip intro (EXPERIMENTAL)". | +| D420 | **Crouched-rifle firing animation (`crouched_rifle_firing_animation_groupA`) never resolved on PC -> SIGSEGV in modelConstrainOrWrapAnimFrame when an MP player crouch-fires a rifle (2026-09-28).** — full `## D420` entry at file tail | FIXED — layout only (§D5 linker adjacency, D164 class): `crouched_rifle_firing_animation_group1` has no zero terminator and on N64 falls through into `...groupA` (source-order .data); GCC places groupA first, so groupA[0] kept the raw anim offset 0xB84. `#ifdef PORT` one array {right, left, terminator} + `groupA` alias (chr.c/chr.h); N64 resolution restored. | | MACOS-WEAK-ALIAS | **macOS/arm64 (M0.4): `#pragma weak X = Y` has no Mach-O equivalent — clang errors "aliases are not supported on darwin", and the pragma form silently emits a TU-local symbol instead** — full `## MACOS-WEAK-ALIAS` entry at file tail | FIXED (macOS port, `lv.c`/`spectrum.c`/`objective_status.c`) — replaced with a `#if defined(PORT) && defined(__APPLE__)` global symbol equate (`.globl _X` / `_X = _Y`); Win/Linux keep the pragma. Verified: 3 TUs compile, aliases are global `S`/`D`/`T` symbols. | | MACOS-LIBCXX-SHIMS | **macOS/arm64 (M0.6): the decomp's `include/` stubs shadow libc++'s wrapper headers — ``/``/``/`` hard-error, and `acosf`/`fmodf`/`fabsf` are undeclared** — full `## MACOS-LIBCXX-SHIMS` entry at file tail | FIXED (macOS port) — new `port/shim/math.h` + generated `hostmath.h`; the existing `host{string,stdlib,stddef}.h.in` now also pull libc++'s `c++/v1/.h` wrapper, guarded `&& defined(__cplusplus)`. `limits.h`/`assert.h` needed no shim. All 186 TUs compile. | | MACOS-64BIT-GATE | **macOS/arm64 (M0.2): `__x86_64__` was used as the "64-bit PC" gate — on arm64 it silently selected the N64 branch (34 undefined `_ANIM_DATA_*`, objecthandler `.bss` overrun, audio heap sizing)** — full `## MACOS-64BIT-GATE` entry at file tail | FIXED — 22 sites in 14 `src/`+`assets/` files and `port/include/pc_protos.h` now use `PLATFORM_64BIT` (defined by CMake on every 64-bit PC target, undefined on N64, so the N64 branch is unchanged). | @@ -15537,6 +15538,43 @@ included; D281 keeps the shipped mitigation + disclosure, zero-saves root cause **Status:** OPEN — cosmetic (no crash, no data loss; the mission still records as failed/aborted and the menus are fully functional). Root-causing needs a side-by-side of front-end state (`current_menu`, `g_CurrentStageToLoad`, `mission_failed_or_aborted`, `g_isBondKIA`) on the fail return with SkipIntro off vs on — candidate for v0.5.0 alongside the D216 audio half. +## D420 — crouched-rifle firing animation never resolved on PC (linker adjacency) -> MP crash (2026-09-28) + +**Symptom.** SIGSEGV in `modelConstrainOrWrapAnimFrame` from `playerTick` +(bondview2.c ~11021) with `anim = 0xb84`, when a multiplayer player +crouch-fires a rifle (found by the 5PLUS bot runs: Complex, 4 seats, M16, +frame 5030; present in the 0.9.x friend bundles). Found on +`exp/5plus-multiplayer` as "D341" (renamed D420 here: D341 is upstream's). + +**Root cause (layout, porting-notes §D5 "linker adjacency", D164 class).** +`firing_animation_groups[1][5]` points at `crouched_rifle_firing_animation_groupA` +(chr.c). The tables hold anim *offsets*; `initWeaponAnimGroups` -> +`initResolveAnimGroupTable` rebases each table up to its zero terminator. +`crouched_rifle_firing_animation_group1` has ONE entry and **no terminator**: +on N64 .data is laid out in source order, so resolving group1 walks on into +groupA (resolving it too, len 2). GCC placed groupA *below* group1, so +groupA[0] kept the raw offset `PTR_ANIM_fire_kneel_left_leg` (0xB84) and +`modelSetAnimation` received it as a `ModelAnimation*`. Side effect before +the fix: crouching rifle guards saw len 1 instead of the N64's 2. + +**Not covered upstream:** upstream D392 (chraction.c firing-table fields) +and D336 (bondhead.c) are different sites; chr.c/chr.h were unchanged on +09278407. + +**Fix (8595a06e, `#ifdef PORT`, `#else` = decomp):** chr.c one array +`{kneel_right_leg, kneel_left_leg, terminator}` (exactly the N64 layout); +chr.h `#define crouched_rifle_firing_animation_groupA +(&crouched_rifle_firing_animation_group1[1])`. Resolution and len are the +N64's; no logic change. Upstream candidate (a real port bug). + +**Verified (programmer, 5plus + main):** repro (4 seats, bots, Complex, +pinned seed, 18 078 frames x3) no crash, SH identical across runs; 8 seats +remote mines no crash; every firing/struck anim table in chr.c scanned -- +this was the only unterminated one; gdb scan of all 24 +`firing_animation_groups` entries at run time: 1 bad pointer before, 0 after +(also 0 on the main-line cherry-pick); P1 gate (1 324 recordings, frame +dumps) unchanged; netplay 2P/4P identical. + ## MACOS-WEAK-ALIAS — macOS/arm64 (M0.4): `#pragma weak X = Y` has no Mach-O equivalent **Context.** The decomp uses GCC's `#pragma weak alias = target` in five TUs to create a weak symbol alias: `src/libultra/gu/sinf.c` + `cosf.c` (`fsin/sinf = __sinf`, `fcos/cosf = __cosf`), `src/game/objective_status.c` (`objectiveGetStatus_WEAK = get_status_of_objective`), `src/game/lv.c` (`g_DebugPortalsInputBufferSource1..4 = g_DebugPortalsInputBuffer1..4`), `src/game/spectrum.c` (`spec_keyboard_row_z_c_v = spec_keyboard_buffer`). On ELF/MinGW this is a normal weak alias. On Darwin/Mach-O it is not: - `__attribute__((weak, alias("target")))` → hard error: `aliases are not supported on darwin`.