Skip to content

Fix #8785: StackEntry wasm stack type invariants and unreachable parser regressions - #8978

Open
ANAMASGARD wants to merge 7 commits into
WebAssembly:mainfrom
ANAMASGARD:fix/parser-validation-stack-underflow
Open

Fix #8785: StackEntry wasm stack type invariants and unreachable parser regressions#8978
ANAMASGARD wants to merge 7 commits into
WebAssembly:mainfrom
ANAMASGARD:fix/parser-validation-stack-underflow

Conversation

@ANAMASGARD

Copy link
Copy Markdown

Fixes parser/IRBuilder regressions from tracking Wasm operand-stack effects separately via StackEntry::wasmStackType (#8785).

  • Introduce wasmStackType on the IRBuilder expression stack and keep it in sync with Wasm stack semantics (unreachable barriers vs ordinary void instructions).
  • Fix unreachable operand popping for GC/array stores, struct.new, try/return_call, and related control-flow edge cases.
  • Drop non-final concrete stack entries when building typed multi-expression blocks.
  • Treat unreachable-typed void control flow as poppable where baseline did (fixes -S pipe roundtrip, e.g. array-multibyte).
  • Update ~93 lit -S expectations: output shape changes (extra block/drop/unreachable nesting), not semantic IR changes.

Test plan

  • build-clang/bin/binaryen-unittests — 379/379
  • build-clang/bin/binaryen-lit test/lit -j 2 — 982/986 (only 4 pre-existing d8/fuzz_shell*.wast failures; need v8)
  • Targeted validation tests: test/lit/validation/unreachable-*.wast
  • Hard failures cleared: array-multibyte, wat-kitchen-sink, remove-unused-brs_enable-multivalue, wasm-split/split-module-items

Track Wasm operand-stack effects separately from Binaryen IR types via
StackEntry::wasmStackType. Key fixes:
- Sync wasmStackType to none when dropping unreachable predecessors
- Guard finishScope tuple repackaging when hoist is empty
- Mask deeper stack values under unreachable in hoistLastValue

Adds validation tests for unreachable void-block drop, multivalue tuple
parsing, and related edge cases.
Extend pushControlFlow/finishScope handling so void unreachable fallthrough
control flow and return_call inside try remain parseable in concrete-result
functions, while preserving WebAssembly#8785 rejection of (block (unreachable)) (drop).

Allow void unreachable fallthrough blocks to satisfy concrete operand pops
(e.g. if/br_if conditions). Skip struct.get field typing when the ref is
unreachable. Add focused validation regressions for try/return_call and
concrete block ends.

Lit ledger: /tmp/binaryen-lit-ledger/report.md
Track void stack entries skipped in unreachable scopes so operand
popping can match concrete values below (gufa struct.new) while still
synthesizing unreachable operands when types mismatch (br_table index).
Treat wasm unreachable instructions (wasmStackType none but expr type
unreachable) as polymorphic stack values in hoistLastValue,
checkNeedsUnreachableFallback, and pop. Drop non-final concrete stack
entries when building typed multi-expression blocks.

Fixes array-multibyte parser failure and wasm-split validator errors.
Adds unreachable-array-store-value-valid.wast regression test.
When wasmStackType is none but a void block retains expr->type
unreachable, treat it as a poppable stack entry. Fixes -S pipe
roundtrip on array-multibyte and drop(block) reparse paths.
The parser now distinguishes unreachable barriers from ordinary void
entries, which changes block/drop/unreachable nesting in -S output
across many tests. Also fixes scratch-local-roundtrip RTRIP checks
and updates two validation tests to match baseline parse behavior.
@ANAMASGARD
ANAMASGARD requested a review from a team as a code owner August 7, 2026 06:37
@ANAMASGARD
ANAMASGARD requested review from aheejin and removed request for a team August 7, 2026 06:37
@kripken

kripken commented Aug 12, 2026

Copy link
Copy Markdown
Member

This is a large change, and I'm not sure if it makes sense to fix or not. That is, the motivation is good, but I'm not sure the complexity is worth the benefit in wasm-ir-builder.

@tlively ?

@tlively

tlively commented Aug 13, 2026

Copy link
Copy Markdown
Member

If I understand correctly, this is adding proper Wasm validation to IRBuilder by tracking Wasm types alongside the parsed expressions in IRBuilder's expression stack. In general, this would be great to have. Users generally expect us to reject invalid WebAssembly modules, and this would help us run more of the spec tests to test correctness of other parts of our implementation. However, a few initial notes:

  1. There needs to be a way to opt out of this extra validation so we can continue writing tests that parse to arbitrary valid Binaryen IR, even if the corresponding WebAssembly is invalid.
  2. It would be helpful to measure the performance overhead of this extra validation to make sure it is not significant.
  3. Please rewrite the PR description to contain more information about the technical approach and the reasons for various parts of the change. I cannot effectively review this without first having a high-level understanding of what the PR is doing.

Also, it would be good to reduce functional changes to the parser to a bare minimum. Since the goal is only to add extra validation, I would not expect the shape of the parsed IR to change due to this PR. In other words, I would expect that no tests have to be updated except possibly to opt out of the extra validation.

@tlively
tlively self-requested a review August 13, 2026 01:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants