Skip to content

Commit bacc004

Browse files
fix(fuzz): preserve string fixtures (#16319)
1 parent 5d8de82 commit bacc004

2 files changed

Lines changed: 37 additions & 4 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
forge: patch
3+
foundry-evm-fuzz: patch
4+
---
5+
6+
Preserve leading whitespace and trailing null bytes in string fuzz fixtures.

crates/evm/fuzz/src/strategies/param.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,24 @@ fn fuzz_param_inner(
8484
DynSolType::Function | DynSolType::Bool => DynSolValue::type_strategy(param).boxed(),
8585
DynSolType::Bytes => value(),
8686
DynSolType::FixedBytes(_size @ 1..=32) => value(),
87-
DynSolType::String => value()
88-
.prop_map(move |value| {
87+
DynSolType::String => {
88+
let default_strategy = DynSolValue::type_strategy(param).prop_map(move |value| {
8989
DynSolValue::String(
9090
value.as_str().unwrap().trim().trim_end_matches('\0').to_string(),
9191
)
92-
})
93-
.boxed(),
92+
});
93+
if let Some(fixtures) = fuzz_fixtures {
94+
let fixtures = fixtures.to_vec();
95+
proptest::prop_oneof![
96+
50 => any::<prop::sample::Index>()
97+
.prop_map(move |index| index.get(&fixtures).clone()),
98+
50 => default_strategy,
99+
]
100+
.boxed()
101+
} else {
102+
default_strategy.boxed()
103+
}
104+
}
94105
DynSolType::Tuple(ref params) => params
95106
.iter()
96107
.map(|param| fuzz_param_inner(param, None))
@@ -598,6 +609,22 @@ mod tests {
598609
);
599610
}
600611

612+
#[test]
613+
fn string_fixtures_are_emitted_verbatim() {
614+
let fixture = DynSolValue::String(" padded fixture \0".to_string());
615+
let strategy = super::fuzz_param_with_fixtures(
616+
&DynSolType::String,
617+
Some(std::slice::from_ref(&fixture)),
618+
"value",
619+
);
620+
let mut runner = TestRunner::deterministic();
621+
622+
let emitted =
623+
(0..1000).any(|_| strategy.new_tree(&mut runner).unwrap().current() == fixture);
624+
625+
assert!(emitted, "string fixture was never emitted verbatim");
626+
}
627+
601628
#[test]
602629
fn can_fuzz_string_and_bytes_with_ast_literals_and_hashes() {
603630
use super::fuzz_param_from_state;

0 commit comments

Comments
 (0)