Skip to content

Commit 90748f8

Browse files
MathuxNY-73copybara-github
authored andcommitted
No public description
PiperOrigin-RevId: 996388655
1 parent b30b2fe commit 90748f8

9 files changed

Lines changed: 204 additions & 95 deletions

File tree

‎rust/e2e_tests/testdata/fuzz_tests.rs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ impl Domain for ByteVectorDomain {
3232
type UserValue<'user> = Vec<u8>;
3333
type CorpusValue = Vec<u8>;
3434

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

4141
fn mutate(
42-
&self,
42+
&mut self,
4343
val: &mut Self::CorpusValue,
4444
rng: &mut dyn rand::Rng,
4545
only_shrink: bool,
@@ -160,12 +160,12 @@ impl Domain for FallibleDomain {
160160
type UserValue<'user> = u32;
161161
type CorpusValue = u32;
162162

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

167167
fn mutate(
168-
&self,
168+
&mut self,
169169
_val: &mut Self::CorpusValue,
170170
_rng: &mut dyn rand::Rng,
171171
_only_shrink: bool,

‎rust/fuzztest_macro/src/helpers/fuzztest_domain.rs‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@ pub fn generate_fuzztest_domain<'a, 'b: 'a>(
7777
type UserValue<#user_value_lifetime_generic> = #domain_struct_name <#(#user_value_domain_generics),*>;
7878
type CorpusValue = #domain_struct_name <#(#corpus_domain_generics),*>;
7979

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

8686
fn mutate(
87-
&self,
87+
&mut self,
8888
val: &mut Self::CorpusValue,
8989
rng: &mut dyn ::fuzztest::reexports::rand::Rng,
9090
only_shrink: bool,
@@ -98,6 +98,11 @@ pub fn generate_fuzztest_domain<'a, 'b: 'a>(
9898
#(#field_names: self.#field_names.corpus_to_user_value(&corpus_value.#field_names)?),*
9999
})
100100
}
101+
102+
fn validate_corpus_value(&self, corpus_value: &Self::CorpusValue) -> ::fuzztest::reexports::anyhow::Result<()> {
103+
#( self.#field_names.validate_corpus_value(&corpus_value.#field_names)?; )*
104+
Ok(())
105+
}
101106
}
102107
};
103108
(domain_definition_tokens, field_names)
@@ -144,15 +149,15 @@ mod tests {
144149
type UserValue<'user> = __FuzzTestTestFuzzStateWrapper<T0::UserValue<'user>, T1::UserValue<'user> >;
145150
type CorpusValue = __FuzzTestTestFuzzStateWrapper<T0::CorpusValue, T1::CorpusValue>;
146151

147-
fn init(&self, rng: &mut dyn ::fuzztest::reexports::rand::Rng) -> ::fuzztest::reexports::anyhow::Result<Self::CorpusValue> {
152+
fn init(&mut self, rng: &mut dyn ::fuzztest::reexports::rand::Rng) -> ::fuzztest::reexports::anyhow::Result<Self::CorpusValue> {
148153
Ok(__FuzzTestTestFuzzStateWrapper {
149154
a: self.a.init(rng)?,
150155
b: self.b.init(rng)?
151156
})
152157
}
153158

154159
fn mutate(
155-
&self,
160+
&mut self,
156161
val: &mut Self::CorpusValue,
157162
rng: &mut dyn ::fuzztest::reexports::rand::Rng,
158163
only_shrink: bool,
@@ -168,6 +173,12 @@ mod tests {
168173
b: self.b.corpus_to_user_value(&corpus_value.b)?
169174
})
170175
}
176+
177+
fn validate_corpus_value(&self, corpus_value: &Self::CorpusValue) -> ::fuzztest::reexports::anyhow::Result<()> {
178+
self.a.validate_corpus_value(&corpus_value.a)?;
179+
self.b.validate_corpus_value(&corpus_value.b)?;
180+
Ok(())
181+
}
171182
}
172183
}
173184
.to_string())

‎rust/fuzztest_macro/src/helpers/test_registration.rs‎

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,11 @@ impl<'a> FuzzTestRegistrationCtx<'a> {
111111

112112
let fuzz_test_struct_instance_tokens = quote!(
113113
#fuzz_test_struct_name {
114-
domain: #domain_struct_name {
114+
domain: std::sync::Arc::new(std::sync::Mutex::new(
115+
#domain_struct_name {
115116
#(#fuzz_test_domain_field_names: #domain_ctors),*
116-
},
117+
}
118+
)),
117119
test_fn: #prop_fn_ident
118120
}
119121
);
@@ -214,7 +216,7 @@ impl<'a> FuzzTestRegistrationCtx<'a> {
214216
{
215217
where_clauses.predicates.push(
216218
parse_quote! {
217-
for <#user_value_lifetime_generic> #domain_gen: #crate_name::domains::Domain<UserValue<#user_value_lifetime_generic> = #ty >
219+
for <#user_value_lifetime_generic> #domain_gen: #crate_name::domains::Domain<UserValue<#user_value_lifetime_generic> = #ty > + 'static
218220
});
219221
where_clauses.predicates.push(parse_quote! { #corpus_gen: 'static });
220222
}
@@ -229,7 +231,7 @@ impl<'a> FuzzTestRegistrationCtx<'a> {
229231
#fuzz_test_domain_definition
230232

231233
struct #fuzz_test_struct_name #generics {
232-
domain: #domain_struct_name #generics,
234+
domain: std::sync::Arc<std::sync::Mutex<#domain_struct_name #generics>>,
233235
test_fn: #test_fn_type
234236
}
235237

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

253-
let user_value = self.domain.corpus_to_user_value(wrapper).expect("Failed to get user value from corpus value");
255+
let user_value = self.domain.lock()
256+
.expect("Failed to acquire domain lock")
257+
.corpus_to_user_value(wrapper)
258+
.expect("Failed to get user value from corpus value");
254259

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

@@ -259,8 +264,8 @@ impl<'a> FuzzTestRegistrationCtx<'a> {
259264
fn print_finding_report(&self) {
260265
todo!("Not implemented!")
261266
}
262-
fn domains(&self) -> &dyn #crate_name::domains::GenericDomain {
263-
&self.domain
267+
fn domains(&self) -> std::sync::Arc<std::sync::Mutex<dyn #crate_name::domains::GenericDomain>> {
268+
std::sync::Arc::clone(&self.domain) as std::sync::Arc<std::sync::Mutex<dyn #crate_name::domains::GenericDomain>>
264269
}
265270
}
266271

@@ -301,14 +306,14 @@ mod tests {
301306
expect_that!(
302307
fuzztest_object_tokenstream.to_string(), ends_with( quote! {
303308
struct __FuzzTestTestFuzz<T0, T1> {
304-
domain: __FuzzTestTestFuzzStateWrapper<T0, T1>,
309+
domain: std::sync::Arc<std::sync::Mutex<__FuzzTestTestFuzzStateWrapper<T0, T1> >>,
305310
test_fn: fn(i32, std::string::String)
306311
}
307312

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

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

@@ -335,17 +343,19 @@ mod tests {
335343
fn print_finding_report(&self) {
336344
todo!("Not implemented!")
337345
}
338-
fn domains(&self) -> &dyn ::fuzztest::domains::GenericDomain {
339-
&self.domain
346+
fn domains(&self) -> std::sync::Arc<std::sync::Mutex<dyn ::fuzztest::domains::GenericDomain>> {
347+
std::sync::Arc::clone(&self.domain) as std::sync::Arc<std::sync::Mutex<dyn ::fuzztest::domains::GenericDomain>>
340348
}
341349
}
342350

343351
fn __FuzzTestTestFuzz_factory() -> ::fuzztest::internal::BoxedFuzzTest {
344352
::std::boxed::Box::new(__FuzzTestTestFuzz {
345-
domain: __FuzzTestTestFuzzStateWrapper {
346-
a: ::fuzztest::domains::arbitrary::Arbitrary::<i32>::default(),
347-
b: ::fuzztest::domains::arbitrary::Arbitrary::<String>::default()
348-
},
353+
domain: std::sync::Arc::new(std::sync::Mutex::new(
354+
__FuzzTestTestFuzzStateWrapper {
355+
a: ::fuzztest::domains::arbitrary::Arbitrary::<i32>::default(),
356+
b: ::fuzztest::domains::arbitrary::Arbitrary::<String>::default()
357+
}
358+
)),
349359
test_fn: __property_fn__test_fuzz
350360
})
351361
}

‎rust/src/domains.rs‎

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,15 @@ pub trait Domain {
123123
type CorpusValue: Serialize + DeserializeOwned + Clone;
124124

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

128128
/// Mutates the value in `val` to a new value drawn from the domain.
129129
///
130130
/// If `only_shrink` is `true`, then the mutation must not increase the size of the corpus
131131
/// value. Otherwise, the mutation can both shrink and grow the corpus value.
132132
fn mutate(
133-
&self,
134-
val: &mut Self::CorpusValue,
133+
&mut self,
134+
corpus_value: &mut Self::CorpusValue,
135135
rng: &mut dyn rand::Rng,
136136
only_shrink: bool,
137137
) -> anyhow::Result<()>;
@@ -177,6 +177,16 @@ pub trait Domain {
177177
fn serialize_corpus(&self, corpus_value: &Self::CorpusValue) -> anyhow::Result<Vec<u8>> {
178178
postcard::to_stdvec(corpus_value).context("Failed to serialize corpus value to bytes")
179179
}
180+
181+
/// Validates that a corpus value satisfies the domain's constraints.
182+
///
183+
/// This method is called, among other things, after the `CorpusValue` was constructed from a
184+
/// user provided value.
185+
/// For example, when the domain is seeded, this method is used to check that seeds specified by
186+
/// the users are valid given the domain's constraints.
187+
fn validate_corpus_value(&self, _corpus_value: &Self::CorpusValue) -> anyhow::Result<()> {
188+
Ok(())
189+
}
180190
}
181191

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

194204
/// Mutates the value in `val` to a new value drawn from the domain.
195205
///
196206
/// See `Domain::mutate` for more details.
197207
fn mutate(
198-
&self,
199-
val: &mut GenericCorpusValue,
208+
&mut self,
209+
corpus_value: &mut GenericCorpusValue,
200210
rng: &mut dyn rand::Rng,
201211
only_shrink: bool,
202212
) -> anyhow::Result<()>;
@@ -221,7 +231,7 @@ where
221231
D: Domain,
222232
D::CorpusValue: 'static,
223233
{
224-
fn init(&self, rng: &mut dyn rand::Rng) -> anyhow::Result<GenericCorpusValue> {
234+
fn init(&mut self, rng: &mut dyn rand::Rng) -> anyhow::Result<GenericCorpusValue> {
225235
Ok(Box::new(self.init(rng)?))
226236
}
227237

@@ -233,13 +243,13 @@ where
233243
///
234244
/// See `GenericDomain::mutate` for more details.
235245
fn mutate(
236-
&self,
237-
val: &mut GenericCorpusValue,
246+
&mut self,
247+
corpus_value: &mut GenericCorpusValue,
238248
rng: &mut dyn rand::Rng,
239249
only_shrink: bool,
240250
) -> anyhow::Result<()> {
241251
self.mutate(
242-
val.downcast_mut().context("Failed to retrieve the Corpus Value")?,
252+
corpus_value.downcast_mut().context("Failed to retrieve the Corpus Value")?,
243253
rng,
244254
only_shrink,
245255
)

0 commit comments

Comments
 (0)