diff --git a/docs/wasm-inflate-panic.md b/docs/wasm-inflate-panic.md index f02f4a0..3f939bb 100644 --- a/docs/wasm-inflate-panic.md +++ b/docs/wasm-inflate-panic.md @@ -204,6 +204,41 @@ remaining paths are generated-wasm inspection of the BLOCK_PTR/register restart sequence, or building per-op TCI. A deterministic reproducer exists (remove `wasm_tci_only_tb`, open example.txt, faults at MEPC 0x4201e210, gen 16). +### E9 — static analysis of generated wasm (dump + wasm2wat) +Added a node-only dump hook (`wasm_dump_module`, tcg.c finalize) that writes the +first compiled store-TB and load-TB modules; `_scratch/dump-tbs.mjs` boots the +firmware under node far enough to emit them. `wasm2wat --enable-threads` gives +readable IR. + +**Finding 1 (real bug, fixed-then-shelved):** the ld/st slow paths detect an +asyncify yield with the thread-global `DONE_FLAG` (ctx+20), while the general +call path uses `UNWINDING` (ctx+28), which is reset before each call and set +*only* by the coroutine switch. `DONE_FLAG` is set by *any* nested ld/st helper, +so a nested guest access inside a store/load helper that then yields makes the +outer op falsely read "completed" and swallow the unwind. Converting ld/st to +the `UNWINDING` mechanism is the correct fix. **But** rebuilding with compiled +stores + the UNWINDING fix still crashes identically (gen 16, same MEPC), so the +store helpers on this path never actually yield — this bug is latent here. Change +shelved (not shipped) to avoid touching the working compiled-load path without a +green test; recorded for a future upstream fix. + +**Finding 2 (reframes the root cause):** combine E5 with the load result. E5 +routes *every* store through the C softmmu helper (correct memory write) and +still crashes; loads share the identical restart/block structure and work. So +the corruption is **not** in the store data codegen, the restart machinery, or +the yield handling. What remains is that a store *writes* guest memory using an +address/value taken from guest registers (wasm globals). A compiled TB that +computes a wrong register value corrupts memory only through a store — a wrong +address fed to a *load* just reads harmless garbage. This matches every prior +result: emergent (depends which ops precede a store), deterministic, and +non-localizable by store region or width. The remaining hunt is a +register-producing op whose compiled codegen diverges from TCI, exposed +destructively via stores — which needs a compiled-vs-TCI per-TB register +differential, not more whole-TB gating. + +Tooling retained: `wasm_dump_module` + `wasm_tb_had_store/load` tags + +`_scratch/dump-tbs.mjs`. + ### Next options 1. **Ship E1 as a guarded workaround** — reader works now; measure real navigation/page-turn perf before judging it unacceptable. diff --git a/third_party/qemu b/third_party/qemu index e80c3c7..e45c1e2 160000 --- a/third_party/qemu +++ b/third_party/qemu @@ -1 +1 @@ -Subproject commit e80c3c708863b30fef43609e5edf65398862f7f3 +Subproject commit e45c1e2db1b3bae1ff0ee7b1e64be7a1eabe8219