Skip to content

End symbolic jump targets above two bytes in an invalid-jump error - #1203

Merged
msooseth merged 2 commits into
mainfrom
symbolic-jump-high-bytes
Oct 19, 2026
Merged

msooseth merged 2 commits into
mainfrom
symbolic-jump-high-bytes

Conversation

@msooseth

@msooseth msooseth commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Description

For a symbolic JUMP/JUMPI target, hevm asks the solver only for the values of its low two bytes. Each resulting path then constrained the whole target to equal one of them, so targets with any higher byte set were on no path. The symbolic-execution fuzzer found this: a concrete input reached none of the leaves.

JUMP and JUMPI now first branch on the target being below 2^16. Below that, the two-byte enumeration is exact. Above it, the path ends in a BadJumpDestination error; for JUMPI, only if the jump is taken.

Such a target is invalid because a jump destination has to be inside the code, and code is at most 49,152 bytes (EIP-3860 for initcode; EIP-170 caps deployed code at 24,576). hevm doesn't enforce these limits when it is given raw bytecode. Code longer than 64KB could have a valid destination at or above 2^16, which this treats as invalid; before, it was missed.

This PR also fixes eq-fuzz running out of memory. Each counterexample replay result was a thunk over both final VMs. Their traces held the stubs' return and revert data, up to 16MB per call, so the VMs of all replays were kept alive until the results were shown. eq-fuzz now also writes the programs it checks to HEVM_FUZZ_CASE_FILE, to find such cases.

Checklist

  • tested locally
  • added automated tests
  • updated the docs
  • updated the changelog

@msooseth msooseth changed the title Explore symbolic jump targets above two bytes as invalid jumps End symbolic jump targets above two bytes in an invalid-jump error Oct 19, 2026
msooseth and others added 2 commits October 19, 2026 19:49
Solutions for a symbolic jump target cover its low two bytes only, and
each path then fixed the whole target to one of them, so targets with
higher bytes set, all past the end of the code, were on no path. JUMP
and JUMPI now first branch on the target being below 2^16; above it,
the path ends in a BadJumpDestination error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each CexReplay was a thunk over both final VMs, whose traces held the
stubs' return and revert data, so replaying many counterexamples with
16MB returndata exhausted memory. eq-fuzz writes the programs it checks
to HEVM_FUZZ_CASE_FILE, to find such cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@msooseth
msooseth force-pushed the symbolic-jump-high-bytes branch from 07de533 to ffebbf4 Compare October 19, 2026 17:54
@msooseth
msooseth merged commit e62794b into main Oct 19, 2026
9 checks passed
@msooseth
msooseth deleted the symbolic-jump-high-bytes branch October 19, 2026 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant