Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code fastpath scanning for valid jump destinations #348

Merged
merged 24 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
523a7b3
WIP
karmacoma-eth Aug 10, 2024
981fb45
delete unused definitions
karmacoma-eth Aug 14, 2024
fddfc1c
add optional dependencies for benchmarking
karmacoma-eth Aug 14, 2024
8c80246
refactor fast path and insn_len
karmacoma-eth Aug 14, 2024
ca12f87
Contract instances are immutable, avoid copies
karmacoma-eth Aug 15, 2024
a7ff795
cleanup
karmacoma-eth Aug 16, 2024
fca8066
fix tests (since we removed contract iteration)
karmacoma-eth Aug 16, 2024
f891e82
unused import
karmacoma-eth Aug 16, 2024
85d963f
DUPn: avoid resimplifying stack elements
karmacoma-eth Aug 16, 2024
8316f62
stack push: fast path for concrete values, no need to check size of s…
karmacoma-eth Aug 16, 2024
dc85678
use constant ZERO instead of con(0)
karmacoma-eth Aug 16, 2024
b29b766
avoid str(cond) pattern
karmacoma-eth Aug 16, 2024
c878a86
simplify PUSHn execution
karmacoma-eth Aug 19, 2024
4079178
remove spurious simplify call from unbox_int
karmacoma-eth Aug 19, 2024
616a8c4
perf: new method to compute jumpi_id
karmacoma-eth Aug 19, 2024
a292df6
fix tests
karmacoma-eth Aug 19, 2024
de8d7c2
better type annotations
karmacoma-eth Aug 19, 2024
20ea62a
fix type syntax for 3.11
karmacoma-eth Aug 20, 2024
b279253
fix HalmosLogs.bounded_loops
karmacoma-eth Aug 20, 2024
6ebdaaa
fix more uses of HalmosLogs.bounded_loops
karmacoma-eth Aug 20, 2024
61343e2
consistency: con(1) -> ONE
karmacoma-eth Aug 20, 2024
6dd088d
clean up types a bit
karmacoma-eth Aug 21, 2024
af3df48
fix revert condition check
karmacoma-eth Aug 21, 2024
afd5c11
add symbolic revert test
karmacoma-eth Aug 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions requirements-benchmark.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# optional dependencies, for benchmarking
pytest-benchmark
pytest-benchmark[histogram]
42 changes: 21 additions & 21 deletions src/halmos/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@

# Panic(1)
# bytes4(keccak256("Panic(uint256)")) + bytes32(1)
ASSERT_FAIL = 0x4E487B710000000000000000000000000000000000000000000000000000000000000001
ASSERT_FAIL = ByteVec(
bytes.fromhex(
"4E487B710000000000000000000000000000000000000000000000000000000000000001"
)
)

VERBOSITY_TRACE_COUNTEREXAMPLE = 2
VERBOSITY_TRACE_SETUP = 3
Expand Down Expand Up @@ -372,13 +376,13 @@ def run_bytecode(hexcode: str, args: HalmosConfig) -> List[Exec]:
for idx, ex in enumerate(exs):
result_exs.append(ex)
opcode = ex.current_opcode()
error = ex.context.output.error
error_output = ex.context.output.error
returndata = ex.context.output.data

if error:
if error_output:
warn_code(
INTERNAL_ERROR,
f"{mnemonic(opcode)} failed, error={error}, returndata={returndata}",
f"{mnemonic(opcode)} failed, error={error_output}, returndata={returndata}",
)
else:
print(f"Final opcode: {mnemonic(opcode)})")
Expand Down Expand Up @@ -453,10 +457,12 @@ def deploy_test(
print("Constructor trace:")
render_trace(ex.context)

error = ex.context.output.error
error_output = ex.context.output.error
returndata = ex.context.output.data
if error:
raise ValueError(f"constructor failed, error={error} returndata={returndata}")
if error_output:
raise ValueError(
f"constructor failed, error={error_output} returndata={returndata}"
)

deployed_bytecode = Contract(returndata)
ex.code[this] = deployed_bytecode
Expand Down Expand Up @@ -515,13 +521,11 @@ def setup(
print(f"{setup_sig} trace #{idx+1}:")
render_trace(setup_ex.context)

opcode = setup_ex.current_opcode()
error = setup_ex.context.output.error

if error is None:
if not setup_ex.context.output.error:
setup_exs_no_error.append((setup_ex, setup_ex.path.to_smt2(args)))

else:
opcode = setup_ex.current_opcode()
if opcode not in [EVM.REVERT, EVM.INVALID]:
warn_code(
INTERNAL_ERROR,
Expand Down Expand Up @@ -572,7 +576,7 @@ def setup(
f"{setup_sig}: paths have not been fully explored due to the loop unrolling bound: {args.loop}",
)
if args.debug:
print("\n".join(sevm.logs.bounded_loops))
print("\n".join(jumpid_str(x) for x in sevm.logs.bounded_loops))

if args.reset_bytecode:
for assign in [x.split("=") for x in args.reset_bytecode.split(",")]:
Expand Down Expand Up @@ -753,15 +757,11 @@ def future_callback(future_model):
print("\nTrace:")
render_trace(ex.context)

error = ex.context.output.error

if (
isinstance(error, Revert)
and unbox_int(ex.context.output.data) == ASSERT_FAIL
) or is_global_fail_set(ex.context):
error_output = ex.context.output.error
if ex.reverted_with(ASSERT_FAIL) or is_global_fail_set(ex.context):
if args.verbose >= 1:
print(f"Found potential path (id: {idx+1})")
print(f"{ex.context.output.error}")
print(f"{error_output}")

if args.verbose >= VERBOSITY_TRACE_COUNTEREXAMPLE:
traces[idx] = rendered_trace(ex.context)
Expand All @@ -780,7 +780,7 @@ def future_callback(future_model):
if args.print_blocked_states:
traces[idx] = f"{hexify(ex.path)}\n{rendered_trace(ex.context)}"

elif not error:
elif not error_output:
normal += 1

# 0 width is unlimited
Expand Down Expand Up @@ -846,7 +846,7 @@ def future_callback(future_model):
f"{funsig}: paths have not been fully explored due to the loop unrolling bound: {args.loop}",
)
if args.debug:
print("\n".join(logs.bounded_loops))
print("\n".join(jumpid_str(x) for x in logs.bounded_loops))

if logs.unknown_calls:
warn_code(
Expand Down
5 changes: 3 additions & 2 deletions src/halmos/assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from dataclasses import dataclass
from z3 import *

from .utils import *
from halmos.exceptions import HalmosException
from halmos.utils import *


@dataclass(frozen=True)
Expand All @@ -13,7 +14,7 @@ class VmAssertion:
"""

cond: BitVecRef
msg: Optional
msg: str | None


def mk_cond(bop, v1, v2):
Expand Down
9 changes: 2 additions & 7 deletions src/halmos/bytevec.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,14 @@
try_bv_value_to_bytes,
unbox_int,
warn,
Byte,
Word,
)

# concrete or symbolic byte
Byte = UnionType[int, BitVecRef]
UnwrappedBytes = UnionType[bytes, Byte]
WrappedBytes = UnionType["Chunk", "ByteVec"]

# any concrete or symbolic sequence of bytes
Bytes = UnionType[UnwrappedBytes, WrappedBytes]

# concrete or symbolic 32-byte word
Word = UnionType[int, BitVecRef]


def try_concat(lhs: Any, rhs: Any) -> Optional[Any]:
"""Attempt to concatenate two values together if they have the same type"""
Expand Down
2 changes: 1 addition & 1 deletion src/halmos/cheatcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ class hevm_cheat_code:
get_block_nunber_sig: int = 0x42CBB15C

@staticmethod
def handle(sevm, ex, arg: ByteVec, stack, step_id) -> Optional[ByteVec]:
def handle(sevm, ex, arg: ByteVec, stack, step_id) -> ByteVec | None:
funsig: int = int_of(arg[:4].unwrap(), "symbolic hevm cheatcode")
ret = ByteVec()

Expand Down
Loading