Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions rust/e2e_tests/testdata/fuzz_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ impl Domain for ByteVectorDomain {
type UserValue<'user> = Vec<u8>;
type CorpusValue = Vec<u8>;

fn init(&mut self, rng: &mut dyn rand::Rng) -> anyhow::Result<Self::CorpusValue> {
fn init(&self, rng: &mut dyn rand::Rng) -> anyhow::Result<Self::CorpusValue> {
let mut val = vec![0u8; rng.random_range(0..100)];
rng.fill(&mut val[..]);
Ok(val)
}

fn mutate(
&mut self,
&self,
val: &mut Self::CorpusValue,
rng: &mut dyn rand::Rng,
only_shrink: bool,
Expand Down Expand Up @@ -160,12 +160,12 @@ impl Domain for FallibleDomain {
type UserValue<'user> = u32;
type CorpusValue = u32;

fn init(&mut self, _rng: &mut dyn rand::Rng) -> anyhow::Result<Self::CorpusValue> {
fn init(&self, _rng: &mut dyn rand::Rng) -> anyhow::Result<Self::CorpusValue> {
Ok(0)
}

fn mutate(
&mut self,
&self,
_val: &mut Self::CorpusValue,
_rng: &mut dyn rand::Rng,
_only_shrink: bool,
Expand Down
19 changes: 4 additions & 15 deletions rust/fuzztest_macro/src/helpers/fuzztest_domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,14 @@ pub fn generate_fuzztest_domain<'a, 'b: 'a>(
type UserValue<#user_value_lifetime_generic> = #domain_struct_name <#(#user_value_domain_generics),*>;
type CorpusValue = #domain_struct_name <#(#corpus_domain_generics),*>;

fn init(&mut self, rng: &mut dyn ::fuzztest::reexports::rand::Rng) -> ::fuzztest::reexports::anyhow::Result<Self::CorpusValue> {
fn init(&self, rng: &mut dyn ::fuzztest::reexports::rand::Rng) -> ::fuzztest::reexports::anyhow::Result<Self::CorpusValue> {
Ok(#domain_struct_name {
#(#field_names: self.#field_names.init(rng)?),*
})
}

fn mutate(
&mut self,
&self,
val: &mut Self::CorpusValue,
rng: &mut dyn ::fuzztest::reexports::rand::Rng,
only_shrink: bool,
Expand All @@ -98,11 +98,6 @@ pub fn generate_fuzztest_domain<'a, 'b: 'a>(
#(#field_names: self.#field_names.corpus_to_user_value(&corpus_value.#field_names)?),*
})
}

fn validate_corpus_value(&self, corpus_value: &Self::CorpusValue) -> ::fuzztest::reexports::anyhow::Result<()> {
#( self.#field_names.validate_corpus_value(&corpus_value.#field_names)?; )*
Ok(())
}
}
};
(domain_definition_tokens, field_names)
Expand Down Expand Up @@ -149,15 +144,15 @@ mod tests {
type UserValue<'user> = __FuzzTestTestFuzzStateWrapper<T0::UserValue<'user>, T1::UserValue<'user> >;
type CorpusValue = __FuzzTestTestFuzzStateWrapper<T0::CorpusValue, T1::CorpusValue>;

fn init(&mut self, rng: &mut dyn ::fuzztest::reexports::rand::Rng) -> ::fuzztest::reexports::anyhow::Result<Self::CorpusValue> {
fn init(&self, rng: &mut dyn ::fuzztest::reexports::rand::Rng) -> ::fuzztest::reexports::anyhow::Result<Self::CorpusValue> {
Ok(__FuzzTestTestFuzzStateWrapper {
a: self.a.init(rng)?,
b: self.b.init(rng)?
})
}

fn mutate(
&mut self,
&self,
val: &mut Self::CorpusValue,
rng: &mut dyn ::fuzztest::reexports::rand::Rng,
only_shrink: bool,
Expand All @@ -173,12 +168,6 @@ mod tests {
b: self.b.corpus_to_user_value(&corpus_value.b)?
})
}

fn validate_corpus_value(&self, corpus_value: &Self::CorpusValue) -> ::fuzztest::reexports::anyhow::Result<()> {
self.a.validate_corpus_value(&corpus_value.a)?;
self.b.validate_corpus_value(&corpus_value.b)?;
Ok(())
}
}
}
.to_string())
Expand Down
44 changes: 17 additions & 27 deletions rust/fuzztest_macro/src/helpers/test_registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,9 @@ impl<'a> FuzzTestRegistrationCtx<'a> {

let fuzz_test_struct_instance_tokens = quote!(
#fuzz_test_struct_name {
domain: std::sync::Arc::new(std::sync::Mutex::new(
#domain_struct_name {
domain: #domain_struct_name {
#(#fuzz_test_domain_field_names: #domain_ctors),*
}
)),
},
test_fn: #prop_fn_ident
}
);
Expand Down Expand Up @@ -216,7 +214,7 @@ impl<'a> FuzzTestRegistrationCtx<'a> {
{
where_clauses.predicates.push(
parse_quote! {
for <#user_value_lifetime_generic> #domain_gen: #crate_name::domains::Domain<UserValue<#user_value_lifetime_generic> = #ty > + 'static
for <#user_value_lifetime_generic> #domain_gen: #crate_name::domains::Domain<UserValue<#user_value_lifetime_generic> = #ty >
});
where_clauses.predicates.push(parse_quote! { #corpus_gen: 'static });
}
Expand All @@ -231,7 +229,7 @@ impl<'a> FuzzTestRegistrationCtx<'a> {
#fuzz_test_domain_definition

struct #fuzz_test_struct_name #generics {
domain: std::sync::Arc<std::sync::Mutex<#domain_struct_name #generics>>,
domain: #domain_struct_name #generics,
test_fn: #test_fn_type
}

Expand All @@ -252,10 +250,7 @@ impl<'a> FuzzTestRegistrationCtx<'a> {
.downcast_ref::<#domain_struct_name<#(#corpus_generics),*>>()
.expect("Attempt to recover user value before testing failed.");

let user_value = self.domain.lock()
.expect("Failed to acquire domain lock")
.corpus_to_user_value(wrapper)
.expect("Failed to get user value from corpus value");
let user_value = self.domain.corpus_to_user_value(wrapper).expect("Failed to get user value from corpus value");

let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| (self.test_fn)(#(user_value.#fuzz_test_domain_field_names),* ) ));

Expand All @@ -264,8 +259,8 @@ impl<'a> FuzzTestRegistrationCtx<'a> {
fn print_finding_report(&self) {
todo!("Not implemented!")
}
fn domains(&self) -> std::sync::Arc<std::sync::Mutex<dyn #crate_name::domains::GenericDomain>> {
std::sync::Arc::clone(&self.domain) as std::sync::Arc<std::sync::Mutex<dyn #crate_name::domains::GenericDomain>>
fn domains(&self) -> &dyn #crate_name::domains::GenericDomain {
&self.domain
}
}

Expand Down Expand Up @@ -306,14 +301,14 @@ mod tests {
expect_that!(
fuzztest_object_tokenstream.to_string(), ends_with( quote! {
struct __FuzzTestTestFuzz<T0, T1> {
domain: std::sync::Arc<std::sync::Mutex<__FuzzTestTestFuzzStateWrapper<T0, T1> >>,
domain: __FuzzTestTestFuzzStateWrapper<T0, T1>,
test_fn: fn(i32, std::string::String)
}

impl<T0, T1> ::fuzztest::internal::FuzzTest for __FuzzTestTestFuzz<T0, T1>
where for <'user> T0: ::fuzztest::domains::Domain<UserValue<'user> = i32> + 'static,
where for <'user> T0: ::fuzztest::domains::Domain<UserValue<'user> = i32>,
T0::CorpusValue: 'static,
for <'user> T1: ::fuzztest::domains::Domain<UserValue<'user> = std::string::String> + 'static,
for <'user> T1: ::fuzztest::domains::Domain<UserValue<'user> = std::string::String>,
T1::CorpusValue: 'static {
fn name(&self) -> &'static str {
"test_fuzz"
Expand All @@ -331,10 +326,7 @@ mod tests {
.downcast_ref::<__FuzzTestTestFuzzStateWrapper<T0::CorpusValue, T1::CorpusValue>>()
.expect("Attempt to recover user value before testing failed.");

let user_value = self.domain.lock()
.expect("Failed to acquire domain lock")
.corpus_to_user_value(wrapper)
.expect("Failed to get user value from corpus value");
let user_value = self.domain.corpus_to_user_value(wrapper).expect("Failed to get user value from corpus value");
// Safety: Data is not reused after the test.
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| (self.test_fn)(user_value.a, user_value.b) ));

Expand All @@ -343,19 +335,17 @@ mod tests {
fn print_finding_report(&self) {
todo!("Not implemented!")
}
fn domains(&self) -> std::sync::Arc<std::sync::Mutex<dyn ::fuzztest::domains::GenericDomain>> {
std::sync::Arc::clone(&self.domain) as std::sync::Arc<std::sync::Mutex<dyn ::fuzztest::domains::GenericDomain>>
fn domains(&self) -> &dyn ::fuzztest::domains::GenericDomain {
&self.domain
}
}

fn __FuzzTestTestFuzz_factory() -> ::fuzztest::internal::BoxedFuzzTest {
::std::boxed::Box::new(__FuzzTestTestFuzz {
domain: std::sync::Arc::new(std::sync::Mutex::new(
__FuzzTestTestFuzzStateWrapper {
a: ::fuzztest::domains::arbitrary::Arbitrary::<i32>::default(),
b: ::fuzztest::domains::arbitrary::Arbitrary::<String>::default()
}
)),
domain: __FuzzTestTestFuzzStateWrapper {
a: ::fuzztest::domains::arbitrary::Arbitrary::<i32>::default(),
b: ::fuzztest::domains::arbitrary::Arbitrary::<String>::default()
},
test_fn: __property_fn__test_fuzz
})
}
Expand Down
30 changes: 10 additions & 20 deletions rust/src/domains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,15 @@ pub trait Domain {
type CorpusValue: Serialize + DeserializeOwned + Clone;

/// Initializes a new value drawn from the domain.
fn init(&mut self, rng: &mut dyn rand::Rng) -> anyhow::Result<Self::CorpusValue>;
fn init(&self, rng: &mut dyn rand::Rng) -> anyhow::Result<Self::CorpusValue>;

/// Mutates the value in `val` to a new value drawn from the domain.
///
/// If `only_shrink` is `true`, then the mutation must not increase the size of the corpus
/// value. Otherwise, the mutation can both shrink and grow the corpus value.
fn mutate(
&mut self,
corpus_value: &mut Self::CorpusValue,
&self,
val: &mut Self::CorpusValue,
rng: &mut dyn rand::Rng,
only_shrink: bool,
) -> anyhow::Result<()>;
Expand Down Expand Up @@ -177,16 +177,6 @@ pub trait Domain {
fn serialize_corpus(&self, corpus_value: &Self::CorpusValue) -> anyhow::Result<Vec<u8>> {
postcard::to_stdvec(corpus_value).context("Failed to serialize corpus value to bytes")
}

/// Validates that a corpus value satisfies the domain's constraints.
///
/// This method is called, among other things, after the `CorpusValue` was constructed from a
/// user provided value.
/// For example, when the domain is seeded, this method is used to check that seeds specified by
/// the users are valid given the domain's constraints.
fn validate_corpus_value(&self, _corpus_value: &Self::CorpusValue) -> anyhow::Result<()> {
Ok(())
}
}

/// A type-erased interface for Domain types.
Expand All @@ -199,14 +189,14 @@ pub trait GenericDomain {
/// Initializes a new value drawn from the domain.
///
/// See `Domain::init` for more details.
fn init(&mut self, rng: &mut dyn rand::Rng) -> anyhow::Result<GenericCorpusValue>;
fn init(&self, rng: &mut dyn rand::Rng) -> anyhow::Result<GenericCorpusValue>;

/// Mutates the value in `val` to a new value drawn from the domain.
///
/// See `Domain::mutate` for more details.
fn mutate(
&mut self,
corpus_value: &mut GenericCorpusValue,
&self,
val: &mut GenericCorpusValue,
rng: &mut dyn rand::Rng,
only_shrink: bool,
) -> anyhow::Result<()>;
Expand All @@ -231,7 +221,7 @@ where
D: Domain,
D::CorpusValue: 'static,
{
fn init(&mut self, rng: &mut dyn rand::Rng) -> anyhow::Result<GenericCorpusValue> {
fn init(&self, rng: &mut dyn rand::Rng) -> anyhow::Result<GenericCorpusValue> {
Ok(Box::new(self.init(rng)?))
}

Expand All @@ -243,13 +233,13 @@ where
///
/// See `GenericDomain::mutate` for more details.
fn mutate(
&mut self,
corpus_value: &mut GenericCorpusValue,
&self,
val: &mut GenericCorpusValue,
rng: &mut dyn rand::Rng,
only_shrink: bool,
) -> anyhow::Result<()> {
self.mutate(
corpus_value.downcast_mut().context("Failed to retrieve the Corpus Value")?,
val.downcast_mut().context("Failed to retrieve the Corpus Value")?,
rng,
only_shrink,
)
Expand Down
Loading
Loading