forked from Ports/goldeneye-pc-port
fix(linux): thread a va_list* through _Printf (x86-64 SysV ABI) (#22)
* fix(linux): thread a va_list* through _Printf (x86-64 SysV ABI) On the x86-64 System V ABI `va_list` is an array type, so a by-value `va_list` parameter decays to a pointer. `_Printf()` was passing `&args` (the address of that local pointer, not the argument list) to `_Putfld()`, which does `va_arg(*args, ...)` — so `_Putfld` walked garbage and segfaulted. Latent at `-Og`, fatal at `-O2` (PR #9), which is why the Linux release build crashed at boot: bossInitMainthreadData (boss.c:247, the D121 per-level -m token sprintf) -> sprintf("-level_%c%c %s", ...) -> _Putfld -> SIGSEGV @ xprintf.c Same UB class as D187. Windows x64's `va_list` is a scalar (`char*`), so `&args` happened to work there — the Windows build is unaffected. Fix: under `#ifdef PORT`, `_Printf` takes `va_list *` and passes it straight to `_Putfld` (which already expects `va_list *`); `src/sprintf.c` (the only PC caller — `rmon.c` is excluded from the build) passes `&args` of a real `va_list` object. N64 build untouched (`#ifdef PORT`, and it byte-matches the ROM). Verified: - Windows: build links, `-level_09` framediff 3/3 within golden threshold. - Linux -O2: boot crash gone, now advances past bossInitMainthreadData into stage load (uncovers a separate pre-existing stan.c stack overflow during BUNKER1 prop setup — tracked separately). * docs: D188 (xprintf va_list ABI) + D189 (stan.c stack-smash) findings + porting-notes D7
This commit is contained in:
1 parent
bde5e0bdfa
commit
1261389a5c
4 files changed
+55
No files matched your search
@@ -606,6 +606,31 @@ silently disappears.
|
||||
(the missing primitive is often small). Needs an `-O2` build + an eyeball
|
||||
or a targeted crop diff.
|
||||
|
||||
## D7. `va_list` is an ARRAY type on x86-64 SysV — never take `&` of a by-value `va_list` param
|
||||
|
||||
On Windows x64 `va_list` is a scalar (`char *`), so passing a `va_list`
|
||||
parameter by value and later taking its address (`&args`) to hand a helper a
|
||||
"pointer to the list" happens to work. On the **x86-64 System V ABI**
|
||||
(Linux/macOS) `va_list` is `__va_list_tag[1]` — an array — so a by-value
|
||||
`va_list` parameter has already decayed to `__va_list_tag *`. `&args` is then
|
||||
the address of the *local pointer slot*, not the argument list, and a helper
|
||||
doing `va_arg(*args, …)` walks garbage → segfault. Latent at `-Og`, fatal at
|
||||
`-O2`.
|
||||
|
||||
- Instance: **D188** — the IDO printf engine `_Printf`
|
||||
(`src/libultrare/libc/xprintf.c`) passed `&args` to `_Putfld`; crashed at
|
||||
boot on Linux `-O2` via `bossInitMainthreadData` → `sprintf`. Fix: under
|
||||
`#ifdef PORT`, thread a real `va_list *` from the top (`sprintf.c` passes
|
||||
`&args` of an actual `va_list` object; `_Printf` takes `va_list *` and
|
||||
passes it straight through). `#else` keeps the ROM-matching body.
|
||||
- Rule: to share one arg-walk between functions, pass `va_list *` explicitly
|
||||
from the outermost `va_start` scope. Never `&` a `va_list` that arrived as
|
||||
a parameter. `va_copy` into a fresh local is the other portable option when
|
||||
the callee must not disturb the caller's position.
|
||||
- Same "works on MinGW, UB on SysV, exposed at `-O2`" shape as D6 — suspect
|
||||
this class for any Linux-only crash whose backtrace runs through
|
||||
`xprintf`/`_Putfld`/`vsnprintf`-alikes.
|
||||
|
||||
## E. Process / method notes
|
||||
|
||||
- Investigation loop is: reproduce → env-gated capped probe → root-cause
|
||||
|
||||
Reference in new issue
Block a user