Skip to content

arm backend silently skips functions on a wasm-tools-valid module — component validator reports false value-stack underflow (Select/LocalSet) #329

Description

@avrabe

Summary

synth compile --cortex-m --all-exports silently skips two functions of the falcon flight core because synth's component validator reports a wasm value-stack underflow — on a module that wasm-tools validate accepts as fully valid. The skipped functions are absent from the ELF (an on-target completeness gap, distinct from the regalloc skips tracked in #242 and the call_indirect dispatch gap in #275).

Reproduction (deterministic, from public assets)

# falcon-flight-v1.56.wasm — relay release asset, sha256 3fb275db…a41341
loom optimize falcon-flight-v1.56.wasm -o f.loom.wasm        # loom v1.1.13
meld fuse f.loom.wasm -o f.fused.wasm                        # meld v0.30.0 (also repro's on v0.29.0)
wasm-tools validate f.fused.wasm                             # => VALID
synth compile f.fused.wasm --cortex-m --all-exports -o out.elf

Observed on both synth v0.11.39 and v0.11.40 (so not version-introduced):

warning: skipping function 'func_30': ... Component validation failed:
  wasm value-stack underflow at op 21 (LocalSet(2)): would pop 1 from depth 0
warning: skipping function 'func_39': ... Component validation failed:
  wasm value-stack underflow at op 2 (Select): would pop 3 from depth 2

Committed artifact for byte-exact repro: repro/synth-underflow/falcon-v1.56.fused.wasm in pulseengine/jess (sha256 bd946fb5…29713).

Analysis

The module is spec-valid (wasm-tools agrees), so this is synth's internal abstract-stack model under-counting, not a malformed input:

  • func_39, op 2 = Select: a select pops 3 (two operands + i32 condition), but synth's model believes depth is only 2 at op 2 — i.e. the two operands feeding the select aren't both on synth's tracked stack that early. Suggests block/control-flow results (or function params) not seeded onto the abstract stack.
  • func_30, op 21 = LocalSet(2): pops 1, synth thinks depth 0 — same family of under-count, here after ~20 ops.

Both failures are very early in the function, which points at stack initialization / block-result accounting rather than a deep-nesting edge. Possibly related to the (closed) #72 explicit-value-stack work, but that landed and this still reproduces.

Impact for jess

2 functions of the verified flight core are silently dropped from the Cortex-M ELF. Combined with #275 (dispatch) and the #242 regalloc skips, it's part of the on-target completeness picture jess tracks (recorded as AFD-017). Non-blocking for the wasm/kiln path (whole module present there); blocking for a complete self-contained firmware.

Suggested fix

Seed synth's abstract value stack from the function signature (params) and block/loop result types before instruction walk, and verify the Select lowering accounts for all three pops. A targeted fixture from func_39 (the Select case) would lock it. Happy to extract a minimal reproducer from the committed core if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions