Skip to content

Optimized (non-relocatable) path miscompiles block/br_if: branch target lands mid-instruction #483

Description

@avrabe

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.

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