Skip to content

Commit 387cfba

Browse files
figtracerampagent
andcommitted
chore(symexec): fix CI (fmt, clippy, rustdoc)
- rustfmt: reflow long doc/string lines per nightly fmt - clippy: make BranchTrace::{len,is_empty} const, allow too_many_arguments on SymBackend::propose trait method, remove redundant clones in regression tests - rustdoc: replace broken intra-doc link to private super::corpus and wrap SaferMaker URL in angle brackets - private_interfaces: demote 'pub mod symexec' to 'pub(crate)' since callers are all in-crate; trim re-exports to what's actually used (run_symexec_assist, SymExecState, SeedSnapshot) - drop unused MAX_SEEDS_PER_CYCLE constant Amp-Thread-ID: https://ampcode.com/threads/T-019e2bc9-ece8-718f-9279-971e3e982bec Co-authored-by: Amp <amp@ampcode.com>
1 parent 4d61990 commit 387cfba

8 files changed

Lines changed: 29 additions & 39 deletions

File tree

crates/evm/evm/src/executors/fuzz/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,8 +507,7 @@ impl<FEN: FoundryEvmNetwork> FuzzedExecutor<FEN> {
507507
// that flip an unseen branch, validates them via normal coverage,
508508
// and writes accepted candidates into its own `sync/` directory so
509509
// the existing corpus protocol distributes them.
510-
let symexec_active =
511-
worker_id == 0 && self.config.corpus.symexec_assist_active();
510+
let symexec_active = worker_id == 0 && self.config.corpus.symexec_assist_active();
512511
let symexec_interval = self.config.corpus.symexec_assist_interval.max(1);
513512
let mut runs_since_symexec: u32 = 0;
514513
let mut symexec_state = SymExecState::default();

crates/evm/evm/src/executors/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub use invariant::InvariantExecutor;
6363

6464
mod corpus;
6565
mod sancov;
66-
pub mod symexec;
66+
pub(crate) mod symexec;
6767
mod trace;
6868

6969
pub use trace::TracingExecutor;

crates/evm/evm/src/executors/symexec/mod.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22
//!
33
//! Implements the *worker-side* of the architectural plan inspired by
44
//! Echidna's `Echidna.SymExec.Exploration` and the SaferMaker writeup at
5-
//! https://hackmd.io/@SaferMaker/EVM-Sym-Exec.
5+
//! <https://hackmd.io/@SaferMaker/EVM-Sym-Exec>.
66
//!
77
//! It is *not* a full symbolic-execution engine; it is a directed mutation
88
//! assistant that:
99
//!
1010
//! 1. takes a corpus seed (`Vec<BasicTxDetails>`),
1111
//! 2. replays it concretely under a [`crate::inspectors::BranchTraceInspector`],
1212
//! 3. picks the deepest *unseen* opposite-side branch as the "frontier",
13-
//! 4. proposes ABI-aware calldata rewrites that — given the recovered
14-
//! compare operands — would flip the frontier branch,
15-
//! 5. validates each candidate through the normal executor (requiring a real
16-
//! new edge in coverage), and
17-
//! 6. writes accepted candidates to the master worker's `sync/` directory so
18-
//! the existing corpus protocol distributes them.
13+
//! 4. proposes ABI-aware calldata rewrites that — given the recovered compare operands — would flip
14+
//! the frontier branch,
15+
//! 5. validates each candidate through the normal executor (requiring a real new edge in coverage),
16+
//! and
17+
//! 6. writes accepted candidates to the master worker's `sync/` directory so the existing corpus
18+
//! protocol distributes them.
1919
//!
2020
//! v1 is intentionally minimal:
2121
//! - master worker only,
@@ -39,18 +39,18 @@ mod mutate;
3939
mod select;
4040
mod types;
4141

42-
pub use mutate::propose_calldata_rewrites;
43-
pub use select::{SeedSnapshot, pick_frontier, pick_seed, score_seed, unseen_in_history};
44-
pub use types::{
45-
Candidate, FrontierKey, FrontierStats, MAX_CANDIDATES_PER_FRONTIER, MAX_FRONTIER_ATTEMPTS,
46-
MAX_SEEDS_PER_CYCLE, SymExecState,
47-
};
42+
use mutate::propose_calldata_rewrites;
43+
pub use select::SeedSnapshot;
44+
use select::pick_seed;
45+
pub use types::SymExecState;
46+
use types::{Candidate, FrontierKey};
4847

4948
/// Backend abstraction so v2 can swap the heuristic engine for a real SMT
5049
/// solver (or external `hevm`) without touching the assist loop.
5150
pub trait SymBackend {
5251
/// Generate candidate sequences from a seed and its branch trace.
5352
/// `tx_index` identifies the call to mutate (the last one, in v1).
53+
#[allow(clippy::too_many_arguments)]
5454
fn propose(
5555
&self,
5656
seed: &[BasicTxDetails],
@@ -181,9 +181,8 @@ pub fn run_symexec_assist<FEN: FoundryEvmNetwork>(
181181
return Ok(0);
182182
}
183183

184-
// 2. Resolve the ABI of the call slot we're allowed to mutate. For
185-
// invariant tests this is looked up from the targeted contracts;
186-
// for stateless fuzz the caller already supplied it.
184+
// 2. Resolve the ABI of the call slot we're allowed to mutate. For invariant tests this is
185+
// looked up from the targeted contracts; for stateless fuzz the caller already supplied it.
187186
let resolved_function: Option<Function> = match (function, targeted_contracts) {
188187
(Some(f), _) => Some(f.clone()),
189188
(None, Some(targets)) => seed

crates/evm/evm/src/executors/symexec/select.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ pub fn pick_seed(candidates: &[SeedSnapshot]) -> Option<&SeedSnapshot> {
4949
/// Pick a frontier from a replay trace.
5050
///
5151
/// Strategy:
52-
/// - prefer the *deepest* observation whose opposite edge is currently unseen
53-
/// (the seed already satisfies all earlier guards),
52+
/// - prefer the *deepest* observation whose opposite edge is currently unseen (the seed already
53+
/// satisfies all earlier guards),
5454
/// - skip frontiers that have hit `MAX_FRONTIER_ATTEMPTS`,
55-
/// - skip frontiers without a recoverable compare (v1 has no symbolic
56-
/// reasoning beyond ABI rewrites of compare operands).
55+
/// - skip frontiers without a recoverable compare (v1 has no symbolic reasoning beyond ABI rewrites
56+
/// of compare operands).
5757
pub fn pick_frontier<F>(
5858
trace: &BranchTrace,
5959
tx_index: u32,

crates/evm/evm/src/executors/symexec/types.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub struct FrontierKey {
3030
pub selector: [u8; 4],
3131
}
3232

33-
/// Per-frontier attempt bookkeeping, kept separately from [`super::corpus`]
33+
/// Per-frontier attempt bookkeeping, kept separately from the corpus
3434
/// stats so the symbolic worker doesn't pollute the fuzzer's counters.
3535
#[derive(Clone, Debug, Default)]
3636
pub struct FrontierStats {
@@ -46,9 +46,6 @@ pub const MAX_FRONTIER_ATTEMPTS: u16 = 3;
4646
/// Hard cap on candidates evaluated per frontier per cycle.
4747
pub const MAX_CANDIDATES_PER_FRONTIER: usize = 8;
4848

49-
/// Hard cap on seeds processed per assist cycle.
50-
pub const MAX_SEEDS_PER_CYCLE: usize = 1;
51-
5249
/// In-process state for the symbolic worker. Owned by the master worker; not
5350
/// persisted to disk (regenerated fresh each campaign).
5451
#[derive(Clone, Debug, Default)]

crates/evm/evm/src/inspectors/branch_trace.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,11 @@ impl BranchTrace {
121121
self.branches.clear();
122122
}
123123

124-
pub fn len(&self) -> usize {
124+
pub const fn len(&self) -> usize {
125125
self.branches.len()
126126
}
127127

128-
pub fn is_empty(&self) -> bool {
128+
pub const fn is_empty(&self) -> bool {
129129
self.branches.is_empty()
130130
}
131131
}

crates/forge/tests/cli/test_cmd/fuzz.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,17 +1068,14 @@ contract SymExecAssistTest is Test {
10681068
cmd.args(["test", "--mt", "testFuzz_FindMagic"]).assert_success();
10691069

10701070
// Master corpus directory: `<corpus_dir>/<contract>/<test>/worker0/corpus/`.
1071-
let corpus_root = prj
1072-
.root()
1073-
.join("symexec_corpus")
1074-
.join("SymExecAssistTest")
1075-
.join("testFuzz_FindMagic");
1071+
let corpus_root =
1072+
prj.root().join("symexec_corpus").join("SymExecAssistTest").join("testFuzz_FindMagic");
10761073
let master_corpus = corpus_root.join("worker0").join("corpus");
10771074
let master_sync = corpus_root.join("worker0").join("sync");
10781075

10791076
let magic_hex = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
10801077

1081-
let mut search_dirs = vec![master_corpus.clone(), master_sync.clone()];
1078+
let mut search_dirs = vec![master_corpus, master_sync];
10821079
if let Ok(entries) = std::fs::read_dir(&corpus_root) {
10831080
for entry in entries.flatten() {
10841081
let p = entry.path();

crates/forge/tests/cli/test_cmd/invariant/mod.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,10 +1918,8 @@ contract SymExecAssistInvariantTest is Test {
19181918

19191919
let magic_hex = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
19201920

1921-
let mut search_dirs = vec![
1922-
corpus_root.join("worker0").join("corpus"),
1923-
corpus_root.join("worker0").join("sync"),
1924-
];
1921+
let mut search_dirs =
1922+
vec![corpus_root.join("worker0").join("corpus"), corpus_root.join("worker0").join("sync")];
19251923
if let Ok(entries) = std::fs::read_dir(&corpus_root) {
19261924
for entry in entries.flatten() {
19271925
let p = entry.path();

0 commit comments

Comments
 (0)