foundry_evm_symbolic/
runtime.rs1use super::{abi::*, *};
2
3mod address;
4mod bytes;
5mod calldata;
6mod cheatcodes;
7mod control;
8mod evm;
9mod expr;
10mod memory;
11mod precompiles;
12mod solver;
13mod state;
14mod symbols;
15
16pub(crate) use address::*;
17pub(crate) use bytes::*;
18pub(crate) use calldata::*;
19pub(crate) use cheatcodes::*;
20pub(crate) use control::*;
21pub(crate) use evm::*;
22pub(crate) use expr::*;
23pub(crate) use memory::*;
24pub(crate) use precompiles::*;
25pub use solver::PortfolioDiagnostics;
26pub(crate) use solver::{
27 SmtLibSubprocessSolver, SymbolicSolver, solver_portfolio_availability_warning,
28};
29#[cfg(test)]
30pub(crate) use solver::{
31 SolverCommand, SolverConfigError, SolverOutcome, SolverRunSummary, fallback_single_var_model,
32 hard_arith_fallback_model, named_solver_command, normalize_bool_for_solver,
33 normalize_constraints_for_solver, normalize_expr_for_solver, parse_model,
34 product_monotonic_unsat, solver_commands_for_config, split_solver_command,
35 validate_solver_model_output,
36};
37pub(crate) use state::*;
38pub(crate) use symbols::*;
39
40#[derive(Clone, Copy, Debug, PartialEq, Eq)]
42pub struct SymbolicBranchTarget {
43 address: Address,
45 pc: usize,
47 opcode: u8,
49 result: bool,
51}
52
53impl SymbolicBranchTarget {
54 pub const fn new(address: Address, pc: usize, opcode: u8, result: bool) -> Self {
55 Self { address, pc, opcode, result }
56 }
57
58 pub(crate) const fn result(self) -> bool {
59 self.result
60 }
61
62 pub(crate) fn matches(self, address: Address, pc: usize, opcode: u8) -> bool {
63 self.address == address && self.pc == pc && self.opcode == opcode
64 }
65}
66
67pub struct SymbolicRunInput<'a, FEN: FoundryEvmNetwork> {
68 pub executor: &'a Executor<FEN>,
70 pub target: Address,
72 pub sender: Address,
74 pub function: &'a Function,
76 pub value: U256,
78 pub ffi_enabled: bool,
80 pub collect_success_input: bool,
82 pub corpus_seeds: Vec<SymbolicConcreteInput>,
84 pub branch_target: Option<SymbolicBranchTarget>,
86}
87
88#[derive(Debug, Error)]
94pub enum SymbolicError {
95 #[error("missing account {0}")]
97 MissingAccount(Address),
98 #[error("missing code for account {0}")]
100 MissingCode(Address),
101 #[error("backend error: {0}")]
103 Backend(String),
104 #[error("unsupported ABI type for symbolic execution: {0}")]
106 UnsupportedAbi(String),
107 #[error("symbolic calldata variant limit exceeded ({0})")]
109 CalldataVariantLimit(usize),
110 #[error("unsupported symbolic execution feature: {0}")]
112 Unsupported(&'static str),
113 #[error("unsupported opcode 0x{0:02x}")]
115 UnsupportedOpcode(u8),
116 #[error("invalid bytecode: {0}")]
118 InvalidBytecode(&'static str),
119 #[error("invalid jump destination {0}")]
121 InvalidJump(usize),
122 #[error("stack underflow")]
124 StackUnderflow,
125 #[error("stack overflow")]
127 StackOverflow,
128 #[error("solver error: {0}")]
130 Solver(String),
131 #[error("solver returned unknown")]
133 SolverUnknown,
134 #[error("symbolic execution timeout exceeded ({0}s)")]
136 Timeout(u32),
137 #[error("symbolic solver query limit exceeded ({0})")]
139 SolverQueryLimit(usize),
140 #[error(transparent)]
142 Abi(#[from] alloy_dyn_abi::Error),
143}
144
145impl SymbolicError {
146 pub(super) const fn stop_reason(&self) -> SymbolicStopReason {
147 match self {
148 Self::Unsupported(_)
149 | Self::CalldataVariantLimit(_)
150 | Self::UnsupportedOpcode(_)
151 | Self::SolverQueryLimit(_) => SymbolicStopReason::Stuck,
152 Self::SolverUnknown | Self::Timeout(_) => SymbolicStopReason::Timeout,
153 Self::Solver(_)
154 | Self::MissingAccount(_)
155 | Self::MissingCode(_)
156 | Self::Backend(_)
157 | Self::UnsupportedAbi(_)
158 | Self::InvalidBytecode(_)
159 | Self::InvalidJump(_)
160 | Self::StackUnderflow
161 | Self::StackOverflow
162 | Self::Abi(_) => SymbolicStopReason::Error,
163 }
164 }
165}
166
167impl fmt::Display for SymbolicRunResult {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 match self {
170 Self::Safe { stats, .. } => write!(f, "safe after {} paths", stats.paths),
171 Self::Counterexample { stats, .. } => {
172 write!(f, "counterexample after {} paths", stats.paths)
173 }
174 Self::Incomplete { kind, reason, .. } => {
175 write!(f, "incomplete symbolic execution ({kind:?}): {reason}")
176 }
177 }
178 }
179}