Skip to content

Commit 6ae6a60

Browse files
committed
Fix min_complexity() for RecurToMutator
1 parent b4a1c57 commit 6ae6a60

33 files changed

+331
-125
lines changed

fuzzcheck/src/builder.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,8 @@ where
640640
_phantom,
641641
} = self;
642642

643+
mutator.initialize();
644+
643645
crate::fuzzer::launch(
644646
Box::new(test_function),
645647
mutator,

fuzzcheck/src/fuzzer.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,10 +441,17 @@ where
441441
let generation = Generation(fuzzer_stats.total_number_of_runs);
442442
let input = input.new_source(mutator, generation);
443443
// check that the mutator's handling of the complexity is correct
444+
let serialised = String::from_utf8(serializer.to_data(&input.value)).unwrap();
444445
assert!(
445446
(input.complexity(mutator) - cplx).abs() < 0.01,
446447
"The mutator used by the fuzz test does not evaluate the complexity of the test cases consistently.
447-
This is a bug in the implementation of {}",
448+
This is a bug in the implementation of {}
449+
=============
450+
451+
{serialised}
452+
453+
=============
454+
",
448455
std::any::type_name::<M>()
449456
);
450457

fuzzcheck/src/mutators/alternation.rs

Lines changed: 71 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::any::Any;
2+
use std::cell::Cell;
23
use std::cmp::Ordering;
34
use std::marker::PhantomData;
45

@@ -26,10 +27,11 @@ where
2627
{
2728
mutators: Vec<M>,
2829
rng: fastrand::Rng,
29-
search_space_complexity: f64,
3030
added_complexity: f64,
31-
min_complexity: f64,
32-
max_complexity: f64,
31+
initialized: Cell<bool>,
32+
min_complexity: Cell<f64>,
33+
max_complexity: Cell<f64>,
34+
search_space_complexity: Cell<f64>,
3335
_phantom: PhantomData<T>,
3436
}
3537

@@ -41,57 +43,15 @@ where
4143
#[no_coverage]
4244
pub fn new(mutators: Vec<M>, added_complexity: f64) -> Self {
4345
assert!(!mutators.is_empty());
44-
let complexity_from_choice = crate::mutators::size_to_cplxity(mutators.len());
45-
46-
let search_space_complexity = mutators
47-
.iter()
48-
.map(
49-
#[no_coverage]
50-
|m| {
51-
let cplx = m.global_search_space_complexity();
52-
if cplx == 0. {
53-
complexity_from_choice
54-
} else {
55-
cplx
56-
}
57-
},
58-
)
59-
.max_by(
60-
#[no_coverage]
61-
|x, y| x.partial_cmp(y).unwrap_or(Ordering::Equal),
62-
)
63-
.unwrap();
64-
65-
let max_complexity = mutators
66-
.iter()
67-
.map(
68-
#[no_coverage]
69-
|m| m.max_complexity() + added_complexity,
70-
)
71-
.max_by(
72-
#[no_coverage]
73-
|x1, x2| x1.partial_cmp(x2).unwrap_or(Ordering::Equal),
74-
)
75-
.unwrap();
76-
let min_complexity = mutators
77-
.iter()
78-
.map(
79-
#[no_coverage]
80-
|m| m.min_complexity() + added_complexity,
81-
)
82-
.min_by(
83-
#[no_coverage]
84-
|x1, x2| x1.partial_cmp(x2).unwrap_or(Ordering::Equal),
85-
)
86-
.unwrap();
8746

8847
Self {
8948
mutators,
90-
search_space_complexity,
9149
rng: fastrand::Rng::default(),
9250
added_complexity,
93-
min_complexity,
94-
max_complexity,
51+
initialized: Cell::new(false),
52+
min_complexity: Cell::new(std::f64::INFINITY),
53+
max_complexity: Cell::default(),
54+
search_space_complexity: Cell::default(),
9555
_phantom: PhantomData,
9656
}
9757
}
@@ -152,6 +112,65 @@ where
152112
#[doc(hidden)]
153113
type UnmutateToken = UnmutateToken<T, M::UnmutateToken>;
154114

115+
#[doc(hidden)]
116+
#[no_coverage]
117+
fn initialize(&self) {
118+
for mutator in self.mutators.iter() {
119+
mutator.initialize();
120+
}
121+
122+
let complexity_from_choice = crate::mutators::size_to_cplxity(self.mutators.len());
123+
124+
let search_space_complexity = self
125+
.mutators
126+
.iter()
127+
.map(
128+
#[no_coverage]
129+
|m| {
130+
let cplx = m.global_search_space_complexity();
131+
if cplx == 0. {
132+
complexity_from_choice
133+
} else {
134+
cplx
135+
}
136+
},
137+
)
138+
.max_by(
139+
#[no_coverage]
140+
|x, y| x.partial_cmp(y).unwrap_or(Ordering::Equal),
141+
)
142+
.unwrap();
143+
144+
let max_complexity = self
145+
.mutators
146+
.iter()
147+
.map(
148+
#[no_coverage]
149+
|m| m.max_complexity() + self.added_complexity,
150+
)
151+
.max_by(
152+
#[no_coverage]
153+
|x1, x2| x1.partial_cmp(x2).unwrap_or(Ordering::Equal),
154+
)
155+
.unwrap();
156+
let min_complexity = self
157+
.mutators
158+
.iter()
159+
.map(
160+
#[no_coverage]
161+
|m| m.min_complexity() + self.added_complexity,
162+
)
163+
.min_by(
164+
#[no_coverage]
165+
|x1, x2| x1.partial_cmp(x2).unwrap_or(Ordering::Equal),
166+
)
167+
.unwrap();
168+
self.min_complexity.set(min_complexity);
169+
self.max_complexity.set(max_complexity);
170+
self.search_space_complexity.set(search_space_complexity);
171+
self.initialized.set(true);
172+
}
173+
155174
#[doc(hidden)]
156175
#[no_coverage]
157176
fn default_arbitrary_step(&self) -> Self::ArbitraryStep {
@@ -226,19 +245,19 @@ where
226245
#[doc(hidden)]
227246
#[no_coverage]
228247
fn global_search_space_complexity(&self) -> f64 {
229-
self.search_space_complexity
248+
self.search_space_complexity.get()
230249
}
231250

232251
#[doc(hidden)]
233252
#[no_coverage]
234253
fn max_complexity(&self) -> f64 {
235-
self.max_complexity
254+
self.max_complexity.get()
236255
}
237256

238257
#[doc(hidden)]
239258
#[no_coverage]
240259
fn min_complexity(&self) -> f64 {
241-
self.min_complexity
260+
self.min_complexity.get()
242261
}
243262

244263
#[doc(hidden)]

fuzzcheck/src/mutators/arc.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ impl<T: Clone + 'static, M: Mutator<T>> Mutator<Arc<T>> for ArcMutator<M> {
4141
#[doc(hidden)]
4242
type UnmutateToken = UnmutateToken<T, M::UnmutateToken>;
4343

44+
#[doc(hidden)]
45+
#[no_coverage]
46+
fn initialize(&self) {
47+
self.mutator.initialize();
48+
}
49+
4450
#[doc(hidden)]
4551
#[no_coverage]
4652
fn default_arbitrary_step(&self) -> Self::ArbitraryStep {

fuzzcheck/src/mutators/array.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
use std::any::Any;
2+
use std::cell::Cell;
23
use std::marker::PhantomData;
34

45
use fastrand::Rng;
56

67
use crate::{DefaultMutator, Mutator};
78

89
/// A mutator for fixed-size arrays `[T; N]`.
9-
///
10-
/// A different mutator can be used for each element of the array.
1110
pub struct ArrayMutator<M, T, const N: usize>
1211
where
1312
T: Clone + 'static,
1413
M: Mutator<T>,
1514
{
1615
mutator: M,
17-
min_complexity: f64,
18-
max_complexity: f64,
16+
initialized: Cell<bool>,
17+
min_complexity: Cell<f64>,
18+
max_complexity: Cell<f64>,
1919
pub rng: Rng,
2020
_phantom: PhantomData<T>,
2121
}
@@ -27,12 +27,11 @@ where
2727
{
2828
#[no_coverage]
2929
pub fn new(mutator: M) -> Self {
30-
let max_complexity = mutator.max_complexity() * N as f64;
31-
let min_complexity = mutator.min_complexity() * N as f64;
3230
Self {
3331
mutator,
34-
min_complexity,
35-
max_complexity,
32+
initialized: Cell::new(false),
33+
min_complexity: Cell::new(std::f64::INFINITY),
34+
max_complexity: Cell::default(),
3635
rng: Rng::default(),
3736
_phantom: PhantomData,
3837
}
@@ -171,6 +170,18 @@ impl<M: Mutator<T>, T: Clone + 'static, const N: usize> Mutator<[T; N]> for Arra
171170
#[doc(hidden)]
172171
type UnmutateToken = UnmutateArrayToken<M, T, N>;
173172

173+
#[doc(hidden)]
174+
#[no_coverage]
175+
fn initialize(&self) {
176+
self.mutator.initialize();
177+
178+
let max_complexity = self.mutator.max_complexity() * N as f64;
179+
let min_complexity = self.mutator.min_complexity() * N as f64;
180+
self.min_complexity.set(min_complexity);
181+
self.max_complexity.set(max_complexity);
182+
self.initialized.set(true);
183+
}
184+
174185
#[doc(hidden)]
175186
#[no_coverage]
176187
fn default_arbitrary_step(&self) -> Self::ArbitraryStep {}
@@ -234,13 +245,13 @@ impl<M: Mutator<T>, T: Clone + 'static, const N: usize> Mutator<[T; N]> for Arra
234245
#[doc(hidden)]
235246
#[no_coverage]
236247
fn max_complexity(&self) -> f64 {
237-
self.max_complexity
248+
self.max_complexity.get()
238249
}
239250

240251
#[doc(hidden)]
241252
#[no_coverage]
242253
fn min_complexity(&self) -> f64 {
243-
self.min_complexity
254+
self.min_complexity.get()
244255
}
245256

246257
#[doc(hidden)]
@@ -377,6 +388,7 @@ mod tests {
377388
#[no_coverage]
378389
fn test_array_mutator() {
379390
let m = ArrayMutator::<U8Mutator, u8, 32>::new(U8Mutator::default());
391+
m.initialize();
380392
for _ in 0..100 {
381393
let (x, _) = m.ordered_arbitrary(&mut (), 800.0).unwrap();
382394
eprintln!("{:?}", x);

fuzzcheck/src/mutators/bool.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ impl Mutator<bool> for BoolMutator {
4343
#[doc(hidden)]
4444
type UnmutateToken = bool;
4545

46+
#[doc(hidden)]
47+
#[no_coverage]
48+
fn initialize(&self) {}
49+
4650
#[doc(hidden)]
4751
#[no_coverage]
4852
fn default_arbitrary_step(&self) -> Self::ArbitraryStep {

fuzzcheck/src/mutators/boxed.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ impl<T: Clone + 'static, M: Mutator<T>> Mutator<Box<T>> for BoxMutator<M> {
3939
#[doc(hidden)]
4040
type UnmutateToken = UnmutateToken<T, M::UnmutateToken>;
4141

42+
#[doc(hidden)]
43+
#[no_coverage]
44+
fn initialize(&self) {
45+
self.mutator.initialize();
46+
}
47+
4248
#[doc(hidden)]
4349
#[no_coverage]
4450
fn default_arbitrary_step(&self) -> Self::ArbitraryStep {

fuzzcheck/src/mutators/char.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ impl Mutator<char> for CharWithinRangeMutator {
8383
#[doc(hidden)]
8484
type UnmutateToken = char; // old value
8585

86+
#[doc(hidden)]
87+
#[no_coverage]
88+
fn initialize(&self) {}
89+
8690
#[doc(hidden)]
8791
#[no_coverage]
8892
fn default_arbitrary_step(&self) -> Self::ArbitraryStep {

fuzzcheck/src/mutators/character_classes.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ impl Mutator<char> for CharacterMutator {
9494
#[doc(hidden)]
9595
type UnmutateToken = char;
9696

97+
#[doc(hidden)]
98+
#[no_coverage]
99+
fn initialize(&self) {}
100+
97101
#[doc(hidden)]
98102
#[no_coverage]
99103
fn default_arbitrary_step(&self) -> Self::ArbitraryStep {

fuzzcheck/src/mutators/either.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ where
2222
#[doc(hidden)]
2323
type UnmutateToken = Either<M1::UnmutateToken, M2::UnmutateToken>;
2424

25+
#[doc(hidden)]
26+
#[inline]
27+
#[no_coverage]
28+
fn initialize(&self) {
29+
match self {
30+
Either::Left(m) => m.initialize(),
31+
Either::Right(m) => m.initialize(),
32+
}
33+
}
34+
2535
#[doc(hidden)]
2636
#[inline]
2737
#[no_coverage]

0 commit comments

Comments
 (0)