Expand description
Trap-preservation obligations (VCR-VER-002, synth #166 / ordeal#59).
WASM operations like div_s, load/store, call_indirect,
unreachable, and the float→int truncations (iN.trunc_fM_s/u) are
partial: they trap on some inputs. A validator that
proves only value equivalence over a total model cannot see a lowering that
drops a trap — deleting a trapping guard looks value-equal
(synth#633/#666/#665/#642/#709). This module is the thin synth-facing layer
over ordeal::trap: it maps synth’s WasmOps to trap conditions built
over synth’s own BV/Bool terms, and exposes the trap-preservation
gate so “the trap survived the lowering” becomes a checkable obligation.
§Boundary (unchanged from ordeal#59)
ordeal classifies operand/pointer bits — it never models op values (those
are consumer-supplied) and does no floating-point arithmetic. Every builder
here is a Bool/BV over the existing closed QF_BV fragment. A verdict of
TrapVerdict::Preserved is an ordeal Unsat whose LRAT certificate is
re-checked before it is returned, so soundness is that of the normal
certificate-checked pipeline.
§Which VC for which op class
- div/rem — the ARM lowering carries a value (the quotient/remainder), so
the full
prove_trap_equivalence(trap clause and guarded value clause) applies. - load/store, call_indirect, unreachable — synth models no memory
contents nor table values, so these use
prove_trap_condition_equivalence(trap clause only). This is the ordeal#59 agreement. - float→int trunc (
i32/i64.trunc_f{32,64}_{s,u}, Phase B) — the trap predicate is a pure bit-pattern classifier over the float OPERAND’s bits (NaN/±∞ exponent patterns + sign-split monotonic magnitude thresholds, ordeal 0.9.1’strap_trunc; floats enter as BV32/BV64, no FP theory). synth’s QF_BV model carries no float→int value function, so this class usesprove_trap_condition_equivalence(trap clause only) — exactly the #709 soundness surface: ARMVCVTsaturates where WASM traps, so a lowering that keeps the saturated value but drops the guard is the bug shape this clause rejects.
Structs§
- Call
Indirect - The operands of a
call_indirecttrap check (WASM §4.4.8) — the synth-BVmirror ofordeal::trap::CallIndirect. - Define
OrTrap - A value paired with the condition under which the op traps instead of
producing it — the synth-
BV/Boolmirror ofordeal::trap::DefineOrTrap.valueis the op’s result (e.g. the ARM quotient);may_trapis one of the trap-condition builders below.
Enums§
- DivOp
- Which division/remainder op, for
trap_div. - FpFmt
- An IEEE-754 binary interchange format, for the trunc-trap classifiers.
- IntTarget
- The integer target of a truncation, for
fp_trunc_out_of_range. - Trap
Verdict - The verdict of a trap-preservation gate.
- Type
Trap - The type-check mode of a
call_indirect, per its table — the synth-BVmirror ofordeal::trap::TypeTrap.
Functions§
- div_op
- Map a division/remainder
WasmOp(i32 or i64) to itsDivOp;Nonefor any non-div/rem op. - prove_
trap_ condition_ equivalence - Trap-clause-only gate (
orig.may_trap ⇔ opt.may_trap) — for ops whose value synth does not model (load/store, call_indirect, unreachable, float→int trunc).TrapVerdict::Preserved⟹ the lowering neither drops nor spuriously adds the trap. - prove_
trap_ equivalence - Full trap-preservation gate (trap clause and guarded value clause) — for
ops whose value synth models (div/rem).
TrapVerdict::Preserved⟹ the lowering preserves both traps and values. - trap_
always - Trap condition for
unreachable: an unconditional trap. - trap_
call_ indirect - Trap condition for
call_indirect:bounds ∨ null-slot ∨ type. - trap_
div - Trap condition for a div/rem op: divide-by-zero (all four) plus
INT_MIN / -1signed overflow (div_sONLY). The width is taken fromdividend— pass 32-bit terms for i32 ops, 64-bit for i64. - trap_
mem_ oob - Trap condition for an OOB
load/store: asize-byte access ataddrexceedsmem_bound(addr + size >u mem_bound, wraparound-safe).addr,size, andmem_boundmust share a width;mem_boundis synth’s symbolic native-pointer linear-memory extent. - trap_
trunc - Trap condition for
iN.trunc_fM_s/u(WASM float→int truncation, #709):NaN ∨ ±∞ ∨ out-of-rangeclassified purely over the float operand’s bit pattern (bitsis the BV32/BV64 the float travels as — no FP theory). Pass the triple fromtrunc_op.bitsmust be exactlyfmt.total_bits()wide (32 for f32, 64 for f64) — a width mismatch is an internal bug, so it panics loud rather than returning an ill-sorted term. - trunc_
op - Map a float→int truncation
WasmOpto its(float format, integer target, signedness)triple;Nonefor any non-trunc op. Covers all six trunc variants synth’s decoder produces (i64.trunc_f32_s/uare notWasmOpvariants; the rawtrap_truncbuilder still covers those shapes if they ever land).