Skip to content

arm encoder: panics (debug_assert) on PC/R15 operand instead of returning Err — fuzz-found, pre-existing #185

@avrabe

Description

@avrabe

Summary

The encoder_no_panic fuzz target found a pre-existing panic (present on main, unrelated to #180): feeding a PC (R15) register as a data operand to a Thumb-2 op that calls the verify_reg_bits contract (SDIV/UDIV/MLS/… — 11 call sites) aborts under -Cdebug-assertions:

```
CONTRACT VIOLATION [encoding::reg]: register 15 exceeds valid range (0-14)
at crates/synth-synthesis/src/contracts.rs:176 (verify_reg_bits debug_assert)
```

Crash input (Base64): `sp6FdW2FKvw=`. The fuzz target has an empty seed corpus, so each 60s run explores different random inputs — which is why this surfaced intermittently rather than on every PR.

Why it matters

The harness contract is "encode() returns Ok or Err on every input, never panics." Synth's own codegen never emits PC for these ops, so this is not a production miscompilation (release builds no-op the debug_assert); it's a totality gap in the encoder surfaced by the fuzzer.

Fix (landed in the #180 PR #183)

Converted the 11 verify_reg_bits debug-assert calls in arm_encoder.rs to a fallible reg_bits_checked(bits) -> Result<()> that returns a typed Error::synthesis for PC/R15, matching the established "return Err, not panic" pattern (#101/#120/#132). Seeded the crash input into fuzz/corpus/encoder_no_panic/ as a regression.

Follow-up

  • The fuzz target should ship a committed seed corpus so the gate is deterministic rather than luck-of-the-draw (separate infra issue).

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