foundry_evm_symbolic/
runtime.rs1use super::{abi::*, *};
2
3mod address;
4mod bytes;
5mod calldata;
6mod cheatcodes;
7mod control;
8mod evm;
9mod executor_view;
10mod expr;
11mod memory;
12mod precompiles;
13mod solver;
14mod state;
15mod symbols;
16
17pub(crate) use address::*;
18pub(crate) use bytes::*;
19pub(crate) use calldata::*;
20pub(crate) use cheatcodes::*;
21pub(crate) use control::*;
22pub(crate) use evm::*;
23pub use executor_view::ExecutorView;
24pub(crate) use expr::*;
25pub(crate) use memory::*;
26pub(crate) use precompiles::*;
27pub(crate) use solver::{BranchFeasibility, SmtLibSubprocessSolver};
28pub(crate) use state::*;
29pub(crate) use symbols::*;
30
31#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub struct SymbolicBranchTarget {
34 address: Address,
36 pc: usize,
38 opcode: u8,
40 result: bool,
42}
43
44impl SymbolicBranchTarget {
45 pub const fn new(address: Address, pc: usize, opcode: u8, result: bool) -> Self {
46 Self { address, pc, opcode, result }
47 }
48
49 pub(crate) const fn result(self) -> bool {
50 self.result
51 }
52
53 pub(crate) fn matches(self, address: Address, pc: usize, opcode: u8) -> bool {
54 self.address == address && self.pc == pc && self.opcode == opcode
55 }
56}
57
58pub struct SymbolicRunInput<'a> {
59 pub executor: ExecutorView<'a>,
62 pub target: Address,
64 pub sender: Address,
66 pub function: &'a Function,
68 pub value: U256,
70 pub ffi_enabled: bool,
72 pub collect_success_input: bool,
74 pub corpus_seeds: Vec<SymbolicConcreteInput>,
76 pub branch_target: Option<SymbolicBranchTarget>,
78}
79
80#[derive(Debug, Error)]
86pub enum SymbolicError {
87 #[error("missing account {0}")]
89 MissingAccount(Address),
90 #[error("missing code for account {0}")]
92 MissingCode(Address),
93 #[error("backend error: {0}")]
95 Backend(String),
96 #[error("unsupported ABI type for symbolic execution: {0}")]
98 UnsupportedAbi(String),
99 #[error("symbolic calldata variant limit exceeded ({0})")]
101 CalldataVariantLimit(usize),
102 #[error("unsupported symbolic execution feature: {0}")]
104 Unsupported(&'static str),
105 #[error("unsupported opcode 0x{0:02x}")]
107 UnsupportedOpcode(u8),
108 #[error("invalid bytecode: {0}")]
110 InvalidBytecode(&'static str),
111 #[error("invalid jump destination {0}")]
113 InvalidJump(usize),
114 #[error("stack underflow")]
116 StackUnderflow,
117 #[error("stack overflow")]
119 StackOverflow,
120 #[error("solver error: {0}")]
122 Solver(String),
123 #[error("solver returned unknown")]
125 SolverUnknown,
126 #[error("symbolic execution timeout exceeded ({0}s)")]
128 Timeout(u32),
129 #[error("symbolic solver query limit exceeded ({0})")]
131 SolverQueryLimit(usize),
132 #[error(transparent)]
134 Abi(#[from] alloy_dyn_abi::Error),
135}
136
137impl SymbolicError {
138 pub(super) const fn stop_reason(&self) -> SymbolicStopReason {
139 match self {
140 Self::Unsupported(_)
141 | Self::CalldataVariantLimit(_)
142 | Self::UnsupportedOpcode(_)
143 | Self::SolverQueryLimit(_) => SymbolicStopReason::Stuck,
144 Self::SolverUnknown | Self::Timeout(_) => SymbolicStopReason::Timeout,
145 Self::Solver(_)
146 | Self::MissingAccount(_)
147 | Self::MissingCode(_)
148 | Self::Backend(_)
149 | Self::UnsupportedAbi(_)
150 | Self::InvalidBytecode(_)
151 | Self::InvalidJump(_)
152 | Self::StackUnderflow
153 | Self::StackOverflow
154 | Self::Abi(_) => SymbolicStopReason::Error,
155 }
156 }
157}
158
159impl fmt::Display for SymbolicRunResult {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 match self {
162 Self::Safe { stats, .. } => write!(f, "safe after {} paths", stats.paths),
163 Self::Counterexample { stats, .. } => {
164 write!(f, "counterexample after {} paths", stats.paths)
165 }
166 Self::Incomplete { kind, reason, .. } => {
167 write!(f, "incomplete symbolic execution ({kind:?}): {reason}")
168 }
169 }
170 }
171}