Skip to content

Translation validation: verify refinement with traps as first-class state (Alive2 encoding), not value-equivalence + guards #300

Description

@avrabe

Ask

Move trap-preservation from guards around the validator to the validator's encoding itself: verify refinement, not value-equivalence, with traps as a first-class component of the abstract state. This is Alive2's central design decision, and it is the named, published answer to the exact class loom shipped five times (#273/#274/#276/#278/#281).

Why the current shape leaves the hole open

The Z3 translation validator proves value equivalence over a model in which every Wasm operation is total — traps are unmodelled. trap_gate.rs says so directly, and that is why an identity rewrite (x * 0 → 0, dropping a dead div result, constant-condition select) could be certified equivalent while deleting a mandatory trap.

The current defence is sound but structural: a recursive trap-freedom guard (is_no_trap_expr / is_forwardable_expr) gates ~25 fold sites, with trap_backstop.rs calling into trap_gate. That is a per-rule allowlist. The residual risk is exactly the one the research names: a new rewrite added tomorrow is trap-unsafe by default and only safe if its author remembers the guard. The oracle still cannot see traps; we are relying on the guard never being forgotten.

The prior art (this is not new theory)

Alive2: Bounded Translation Validation for LLVM — Lopes, Lee, Hur, Liu, Regehr, PLDI 2021 (paper, repo).

The load-bearing decision: the correctness relation is refinement, not equality — a transformation may only eliminate non-determinism/UB, never introduce it, degenerating to equivalence only when no UB exists. UB, poison and undef are modelled as first-class parts of the abstract state, so an optimization that removes a mandatory error condition is a refinement violation and is rejected by construction — no allowlist required.

Empirical warrant, and the part that should interest us most: running Alive2 over LLVM's own unit tests found 47 new bugs (28 fixed) and forced 8 patches to the LLVM Language Reference. Building a trap-faithful encoding is itself what exposed that the specification was underspecified. That is our recurring fault class, and it means this work pays off twice.

Concretely

  1. Encode trap as state. Extend the validator's abstract state with an explicit trap/⊥ component per Wasm trapping op (div/rem by zero, INT_MIN / -1, OOB load/store, unreachable, indirect-call type mismatch).
  2. Switch the relation to refinement. optimized ⊑ original: for every input, if the original traps the optimized may do anything; if the original does not trap, the optimized must not trap and must agree on values. Deleting a reachable trap becomes unprovable — the encoding rejects it without any syntactic guard.
  3. Then demote the guards to a backstop. Keep is_no_trap_expr as defence-in-depth, but stop it being the primary mechanism.
  4. Relationship to Systemic trap-preservation gate (#257 for traps): verify trap-equivalence via ordeal trap-semantics #279. The systemic trap-gate issue is the certificate-checked checker; this issue is the encoding it should be checking. They compose: refinement encoding = the right property; ordeal certificate = independently re-checkable evidence for it.

Honest note

This is a real piece of work, not a config change, and Alive2 is bounded (it validates within bounds, not a whole-compiler proof). The claim here is only that it converts a class of "green but wrong" into "unprovable", which is exactly the trade we want.

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