fix(parser): fold extended-const init/offset expressions (LS-A-11)#152
Conversation
Two const-expression parsers in meld-core read only the first operator
and silently dropped the rest:
- segments.rs::parse_const_expr_with_value parses data and element
segment offset expressions. A data segment with offset
(i32.const 5)(i32.const 10) i32.add landed at offset 5 instead of 15.
- merger.rs::convert_init_expr parses global initializer expressions.
A global initialized to (i32.const 100)(i32.const 23) i32.add was
emitted with init value 100 instead of 123.
wasmparser 0.246 enables WasmFeatures::extended_const by default, so
any input authored after wit-bindgen / clang-wasi grew extended-const
support can trigger this. Wasm validator accepts the truncated form
because a single well-typed const is still valid; the bug is silent
data corruption with no trap, affecting every downstream runtime
[H-1 semantic divergence, H-2 wrong memory address, H-3.3 init-expr
stopped too soon].
Fix:
- New shared helpers fold_extended_const_i32 / fold_extended_const_i64
in segments.rs walk all operators with a small stack-machine
interpreter, applying i32.add / i32.sub / i32.mul (and i64
counterparts) with wrapping semantics, and return the folded scalar.
- segments.rs::parse_const_expr_with_value routes I32Const / I64Const
arms through the helpers.
- merger.rs::convert_init_expr routes I32Const / I64Const arms through
the helpers; falls back to ConstExpr::raw if folding fails.
Tests (6 new):
- segments::ls_a_11_extended_const_i32_{add,sub,mul}_is_folded
- segments::ls_a_11_single_const_still_works (regression)
- merger::ls_a_11_convert_init_expr_folds_extended_const_i32_add
- merger::ls_a_11_convert_init_expr_preserves_single_const (regression)
LS-A-11 added to safety/stpa/loss-scenarios.yaml under UCA-M-6 with
approved status. Discovered by the post-v0.8.0 Mythos delta-pass sweep
on the 8 Tier-5 files unscanned at v0.8.0 cut time (gate introduced
in #151).
Refs: LS-A-11, UCA-M-6, H-1, H-2, H-3.3
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mythos delta-pass requiredThis PR modifies one or more Tier-5 source files (per Before merge, run the Mythos discover protocol on the
Why this gate exists: LS-A-10 The gate check on this PR will pass once the label is |
|
Mythos delta-pass evidence Tier-5 files touched: Pass methodology: Two fresh agents ran Result: 1 finding (LS-A-11), validated, fixed in this PR with 6 regression tests. Adjacent findings not in this PR (will land in follow-up PRs as separate clusters):
|
Summary
First fix from the post-v0.8.0 Mythos delta-pass sweep on the 8 Tier-5
files unscanned at v0.8.0 cut time. Two const-expression parsers in
meld-core read only the first operator and silently dropped the rest,
silently truncating any wasm 2.0 `extended-const` expression.
The bug
Concrete example: a global initialized to `(i32.const 100)(i32.const 23) i32.add` (intended value 123) was emitted as `(i32.const 100)`. A data segment with offset `(i32.const 5)(i32.const 10) i32.add` landed at offset 5 instead of 15.
wasmparser 0.246 enables `WasmFeatures::extended_const` by default, so any input authored after wit-bindgen / clang-wasi grew extended-const support can trigger this. The wasm validator accepts the truncated form because a single well-typed const is still valid; the bug is silent data corruption with no trap, affecting every downstream runtime.
Fix
New shared helpers `fold_extended_const_i32` / `fold_extended_const_i64`
in `segments.rs` walk all operators with a small stack-machine
interpreter:
```rust
loop {
let op = ops.read()?;
match op {
Operator::End => break,
Operator::I32Const { value } => stack.push(value),
Operator::I32Add => fold_i32_binop(&mut stack, i32::wrapping_add)?,
Operator::I32Sub => fold_i32_binop(&mut stack, i32::wrapping_sub)?,
Operator::I32Mul => fold_i32_binop(&mut stack, i32::wrapping_mul)?,
other => return Err(UnsupportedFeature(...)),
}
}
```
Both `parse_const_expr_with_value` and `convert_init_expr` route
their `I32Const` / `I64Const` arms through these helpers. Unsupported
operators (e.g., `global.get` mixed with arithmetic) error out
explicitly rather than silently truncating.
Tests (6 new)
Safety case
LS-A-11 added to `safety/stpa/loss-scenarios.yaml` under UCA-M-6 with approved status. Hazards: H-1 (semantic divergence), H-2 (wrong memory address), H-3.3 (init-expr stopped too soon).
Tier-5 gate
This PR touches `segments.rs` and `merger.rs`, both Tier-5. The new `mythos-gate` workflow will fire and request the `mythos-pass-done` label. The pass IS the work in this PR (Mythos discovery → validation via concrete PoC failure → fix → regression test).
Test plan
Refs
🤖 Generated with Claude Code