fix(#257): mandatory authoritative wasm-validation backstop — loom cannot emit invalid output#260
Conversation
Generalize the #256 per-pass structural safety net into a systemic guarantee: `loom optimize` can NEVER emit structurally invalid wasm. - Mandatory final gate in `optimize_module`: snapshot the original parsed module up front; after the full pass pipeline, encode the optimized module and run the authoritative `wasmparser::validate`. On rejection (or encode failure), revert the ENTIRE optimization to the pristine original (valid, unoptimized) and emit a loud diagnostic. Worst case is unoptimized-but-valid output, never invalid output. Whole-optimization fallback-to-original is the guaranteed backstop; per-pass bisection to preserve maximum optimization is noted as follow-up. - Harden the lenient siblings `constant_folding` and `simplify_locals` with the #256 pattern (whole-module snapshot before the pass, encode + `wasmparser::validate` after, revert the pass on rejection). Both used `translator.verify(func)` whose SKIPPED-proof path (float load/store, size-threshold) returns Ok and kept the transform UNCHECKED. This keeps failures localized so more optimization survives; the final gate remains the ultimate guarantee. - No VALID transform is weakened; the gate only reverts genuinely-invalid output (#219/#256/inline capabilities preserved). Regression tests (loom-core): final gate keeps the #254 fixture valid; gate is a no-op on clean repro-219 and a hand-written clean module (optimization preserved, not reverted); and the backstop's detect + revert-to-original primitive turns a stack-underflow module into valid output. `cargo test --release --workspace` green (loom-core 427 passed). Fixes: #257 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Automated review for PR #260pulseengine/loom: Verdict: 🔴 Request changes Summary: Fixes #257 by adding a final gate to ensure loom's 'never emits invalid wasm' promise. Findings: 7 mechanical (rivet) · 0 from local AI model. Findings (7):
Generated by a local AI model and post-validated against a strict JSON contract. Each finding includes the verbatim line being criticised — verify by reading the file at the cited location. Reviewed at |
Fixes #257. Makes v1.1.18's reactive #254/#255 fix systemic: turns loom's 'never emits invalid wasm' promise from 'we fixed the two passes gale found' into a guarantee by construction.
Mandatory final gate (loom-core/src/lib.rs,
optimize_module)strip_debug_sections(the exact bytes the CLI emits), encode and run the authoritativewasmparser::validate. On rejection/encode-failure: revert the entire optimization to the original,record_revert("optimize_module:structural-invalid"), and print a loud diagnostic. Worst case = unoptimized-but-VALID output; never invalid. (Per-pass bisection noted as a follow-up refinement — not needed for the guarantee, since each pass already reverts its own invalid transforms.)Hardened the lenient siblings (#256 per-pass pattern)
constant_foldingandsimplify_localsusedtranslator.verify(), whose SKIPPED-proof path (float load/store, or theLOOM_Z3_MAX_INSTRUCTIONSsize threshold) returnedOk(())and kept the transform UNCHECKED — the exact loom optimize emits INVALID wasm (stack underflow) via the inline pass — verification skipped for float load/store functions, not reverted #254 bug class. Added a per-passfunctionssnapshot + encode +wasmparser::validate, reverting the whole pass on rejection.verify_or_revert_strict(skip = failure) or are covered by the final gate. No VALID transform weakened.Tests (4, loom-core)
wasmparser::validate, and reverting yields valid wasm.Checks
cargo test --release --workspacegreen (loom-core 427). fmt + clippy clean.Part of v1.2.0 (with #240 / #259). 🤖 Generated with Claude Code