Summary
On the optimized (non-relocatable) ARM path (optimizer_bridge.rs::ir_to_arm), a block + br_if lowers to a conditional branch whose target is miscomputed — it lands in the middle of an instruction and does not skip past the block. Surfaced incidentally while validating an unrelated optimized-path change; not present on the --relocatable path.
Repro (generic)
(module
(memory 1)
(export "memory" (memory 0))
(func (export "init_branch") (param $sel i32)
(i32.store (i32.const 0) (i32.const 11))
(i32.store (i32.const 4) (i32.const 22))
(block $skip
(br_if $skip (i32.eqz (local.get $sel)))
(i32.store (i32.const 8) (i32.const 33))
(i32.store16 (i32.const 12) (i32.const 44)))))
synth compile init_branch.wat -o /tmp/b.elf -b arm --target cortex-m4 --all-exports
arm-none-eabi-objdump -d -M force-thumb /tmp/b.elf
The emitted bne.n targets offset 0xdc, which is the 3rd byte of the movw r9,#8 that begins the conditional block (0xda), rather than the address after the block. Executing init_branch(0) (br_if taken → block should be skipped) under emulation yields wrong memory ({0:33, 4:22, 12:44}) vs wasmtime ground truth ({0:11, 4:22} — fields 8/12 untouched).
Scope
- Only the optimized path.
--relocatable (the host-link / native-pointer path) is unaffected.
- The branch-target/offset resolution for
block/br_if appears to compute against the wrong instruction index (off by a fraction of an instruction → mid-instruction landing).
Impact
Any non-relocatable compile of a function with block/br_if (or other multi-block control flow that routes through this path) can silently miscompile. Belongs to the patch-accreting-codegen class the VCR-* program (#242) is replacing.
Notes
Found while gating a separate optimized-path perf change (#468) — that change explicitly declines on any control flow, so it is unaffected and does not depend on this fix. Filing separately so the control-flow miscompile is tracked on its own.
Summary
On the optimized (non-relocatable) ARM path (
optimizer_bridge.rs::ir_to_arm), ablock+br_iflowers to a conditional branch whose target is miscomputed — it lands in the middle of an instruction and does not skip past the block. Surfaced incidentally while validating an unrelated optimized-path change; not present on the--relocatablepath.Repro (generic)
The emitted
bne.ntargets offset0xdc, which is the 3rd byte of themovw r9,#8that begins the conditional block (0xda), rather than the address after the block. Executinginit_branch(0)(br_if taken → block should be skipped) under emulation yields wrong memory ({0:33, 4:22, 12:44}) vs wasmtime ground truth ({0:11, 4:22}— fields 8/12 untouched).Scope
--relocatable(the host-link / native-pointer path) is unaffected.block/br_ifappears to compute against the wrong instruction index (off by a fraction of an instruction → mid-instruction landing).Impact
Any non-relocatable compile of a function with
block/br_if(or other multi-block control flow that routes through this path) can silently miscompile. Belongs to the patch-accreting-codegen class the VCR-* program (#242) is replacing.Notes
Found while gating a separate optimized-path perf change (#468) — that change explicitly declines on any control flow, so it is unaffected and does not depend on this fix. Filing separately so the control-flow miscompile is tracked on its own.