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

fix: avoid returning None for library addresses during fuzzing #9771

Merged
merged 8 commits into from
Jan 29, 2025
6 changes: 6 additions & 0 deletions crates/evm/evm/src/executors/invariant/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,12 @@ impl<'a> InvariantExecutor<'a> {
current_run.executor.commit(&mut call_result);

// Collect data for fuzzing from the state changeset.
// This step updates the state dictionary and therefore invalidates the
// ValueTree in use by the current run. This manifestsitself in proptest
// observing a different input case than what it was called with, and creates
// inconsistencies whenever proptest tries to use the input case after test
// execution.
// See <https://github.com/foundry-rs/foundry/issues/9764>.
let mut state_changeset = call_result.state_changeset.clone();
if !call_result.reverted {
collect_data(
Expand Down
20 changes: 12 additions & 8 deletions crates/evm/fuzz/src/strategies/param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::state::EvmFuzzState;
use alloy_dyn_abi::{DynSolType, DynSolValue};
use alloy_primitives::{Address, B256, I256, U256};
use proptest::prelude::*;
use rand::{rngs::StdRng, SeedableRng};

/// The max length of arrays we fuzz for is 256.
const MAX_ARRAY_LEN: usize = 256;
Expand Down Expand Up @@ -132,15 +133,18 @@ pub fn fuzz_param_from_state(
DynSolType::Address => {
let deployed_libs = state.deployed_libs.clone();
value()
.prop_filter_map("filter address fuzzed from state", move |value| {
let fuzzed_addr = Address::from_word(value);
// Do not use addresses of deployed libraries as fuzz input.
// See <https://github.com/foundry-rs/foundry/issues/8639>.
if !deployed_libs.contains(&fuzzed_addr) {
Some(DynSolValue::Address(fuzzed_addr))
} else {
None
.prop_map(move |value| {
let mut fuzzed_addr = Address::from_word(value);
nbaztec marked this conversation as resolved.
Show resolved Hide resolved
let mut rng = StdRng::seed_from_u64(0x1337); // use deterministic rng

// Do not use addresses of deployed libraries as fuzz input, instead return a
// deterministically random address. We cannot filter out this value (via
// `prop_filter_map`) as proptest can invoke this closure after test execution,
// and returning a `None` will cause it to panic. See <https://github.com/foundry-rs/foundry/issues/9764> and <https://github.com/foundry-rs/foundry/issues/8639>.
while deployed_libs.contains(&fuzzed_addr) {
fuzzed_addr.randomize_with(&mut rng);
}
DynSolValue::Address(fuzzed_addr)
})
.boxed()
}
Expand Down