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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions