forked from Ports/goldeneye-pc-port
fix(linux): survive the decomp's latent stack-buffer overruns (D189) (#24)
* fix(linux): survive the decomp's latent stack-buffer overruns (D189)
The decompiled game code has a class of fixed-size stack-buffer over/under-
runs that write a few words into adjacent stack scratch:
* stan.c sub_GAME_7F0B1DDC — `StandTile *tileStack[39]` with a bail check
of `if (cat >= 41)` that only runs once per outer iteration, so `cat`
reaches 40 + pointCount and the append writes several slots past the end.
BUNKER1 (-level_09) prop room-list setup legitimately visits ~40 tiles.
* bondview2.c bondviewCalcIntroSwirlCamera — `f32 pointbuf[10]` indexed
`&pointbuf[i*3]` for i in [-1..2] then written [0..5], i.e. [-3 .. 11].
On the N64 and on the MinGW/Windows build (neither uses a stack protector)
these are harmless in practice — the Windows build is stable over thousands
of frames. Only Ubuntu's gcc default (`-fstack-protector-strong`) turns them
into a fatal `__stack_chk_fail`, at BUNKER1 stage load and again at the intro
swirl camera (~frame 5).
Two-part fix:
* `-fno-stack-protector` globally (CMakeLists) — matches the N64 and MinGW
builds so the same code runs the same way. A hardened Linux build would
need the whole overrun class swept first.
* `StandTile *tileStack[64]` under `#ifdef PORT` (stan.c) — the one case
that is cleanly understood and bounded (`pointCount` is 4-bit, so 40+15
is the true worst case). Pure local scratch, never escapes, no behaviour
change. N64 keeps `[39]` under `#else`.
* stan.c:2225 link-resolve also switched to the D177 PORT_PTRADD macro for
idiom consistency (the blob maps below 4 GiB so the bare cast is
currently lossless; #else is byte-identical).
Stacked on the D188 xprintf fix. Verified: Windows -level_09 framediff 3/3
within golden threshold (all changes are #ifdef PORT or no-op on MinGW);
Linux -O2 -level_09 now runs to frame 2100+ with no crash.
* docs: D189 update (stack-protector / latent overrun class) + porting-notes D8
* docs: D190 — Linux -level_45 objective.c load crash (open); D189 sweep 5/6
This commit is contained in:
1 parent
1261389a5c
commit
86440e3b58
4 files changed
+64
-2
No files matched your search
@@ -220,6 +220,18 @@ add_compile_options(
|
||||
-fwrapv
|
||||
-include "versioninfo.h"
|
||||
)
|
||||
# The decompiled game code has a class of latent fixed-size stack-buffer
|
||||
# over/under-runs (e.g. stan.c sub_GAME_7F0B1DDC's tileStack, bondview2.c
|
||||
# bondviewCalcIntroSwirlCamera's pointbuf[10] indexed [-3..11]) that write a
|
||||
# few words into adjacent stack scratch. On the N64, and on the MinGW/Windows
|
||||
# build (no default stack protector), this is harmless in practice — verified
|
||||
# stable over thousands of frames. Only Ubuntu's gcc default
|
||||
# (-fstack-protector-strong) turns these into a fatal __stack_chk_fail at
|
||||
# stage load / first frames. Match the N64 and MinGW builds so the same code
|
||||
# runs the same way; the genuinely understood cases are still fixed properly
|
||||
# under #ifdef PORT (D189). A hardened Linux build would need the whole class
|
||||
# swept first — tracked in docs/dev/findings.md.
|
||||
add_compile_options(-fno-stack-protector)
|
||||
# Keep frame pointers: dbghelp's StackWalk64 (crash handler + thread dumps)
|
||||
# cannot read DWARF unwind info on MinGW, so the EBP chain is the only way to
|
||||
# get a real backtrace of a hung/crashed game thread.
|
||||
|
||||
Reference in new issue
Block a user