Skip to content

Commit 68f6657

Browse files
authored
Merge pull request #10 from jma-qb/multifix_lain
fix #1, #2, #7 and #9. Propose solutions for #4 #5 and #6
2 parents 208e927 + 8ee3ffb commit 68f6657

File tree

4 files changed

+154
-59
lines changed

4 files changed

+154
-59
lines changed

lain/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ num-traits = "0.2"
1818
num-derive = "0.3"
1919
num = "0.4"
2020
lazy_static = "1.2"
21-
serde = { version = "1.0" , optional = true, features = ["derive"] }
21+
serde = { version = "1.0", optional = true, features = ["derive"] }
2222
field-offset = "0.3"
2323

2424
[features]
2525
default_features = []
2626
serde_support = ["serde"]
27+
pick_invalid_enum = []
28+
ignore_min_max = []
2729

2830
[profile.release]
2931
debug = true

lain/src/mutatable.rs

Lines changed: 136 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,23 @@ enum VecResizeType {
3838
fn grow_vec<T: NewFuzzed + SerializedSize, R: Rng>(
3939
vec: &mut Vec<T>,
4040
mutator: &mut Mutator<R>,
41+
max_elems: Option<usize>,
4142
mut max_size: Option<usize>,
4243
) {
4344
let resize_count = VecResizeCount::new_fuzzed(mutator, None);
45+
let resize_max = if let Some(max) = max_elems {
46+
max
47+
} else {
48+
9 // old magic value from lain
49+
};
4450
let mut num_elements = if vec.is_empty() {
45-
mutator.gen_range(1, 9)
51+
mutator.gen_range(1, resize_max)
4652
} else {
4753
match resize_count {
4854
VecResizeCount::Quarter => vec.len() / 4,
4955
VecResizeCount::Half => vec.len() / 2,
5056
VecResizeCount::ThreeQuarters => vec.len() - (vec.len() / 4),
51-
VecResizeCount::FixedBytes => mutator.gen_range(1, 9),
57+
VecResizeCount::FixedBytes => mutator.gen_range(1, resize_max),
5258
VecResizeCount::AllBytes => mutator.gen_range(1, vec.len() + 1),
5359
}
5460
};
@@ -58,6 +64,10 @@ fn grow_vec<T: NewFuzzed + SerializedSize, R: Rng>(
5864
num_elements = min(num_elements, max_size / T::max_default_object_size());
5965
}
6066

67+
if let Some(max_elems) = max_elems {
68+
num_elements = min(max_elems - vec.len(), num_elements);
69+
}
70+
6171
if num_elements == 0 {
6272
return;
6373
}
@@ -125,28 +135,30 @@ fn grow_vec<T: NewFuzzed + SerializedSize, R: Rng>(
125135
/// Shrinks a `Vec`.
126136
/// This will randomly select to resize by a factor of 1/4, 1/2, 3/4, or a fixed number of bytes
127137
/// in the range of [1, 8]. Elements may be removed randomly from the beginning or end of the the vec
128-
fn shrink_vec<T, R: Rng>(vec: &mut Vec<T>, mutator: &mut Mutator<R>) {
138+
fn shrink_vec<T, R: Rng>(vec: &mut Vec<T>, mutator: &mut Mutator<R>, min_size: Option<usize>) {
129139
if vec.is_empty() {
130140
return;
131141
}
132142

143+
let min_size = if let Some(min) = min_size { min } else { 0 };
144+
133145
let resize_count = VecResizeCount::new_fuzzed(mutator, None);
134146
let mut num_elements = match resize_count {
135147
VecResizeCount::Quarter => vec.len() / 4,
136148
VecResizeCount::Half => vec.len() / 2,
137149
VecResizeCount::ThreeQuarters => vec.len() - (vec.len() / 4),
138-
VecResizeCount::FixedBytes => mutator.gen_range(1, 9),
139-
VecResizeCount::AllBytes => vec.len(),
150+
VecResizeCount::FixedBytes => min(min(mutator.gen_range(1, 9), vec.len()), min_size),
151+
VecResizeCount::AllBytes => min(vec.len(), min_size),
140152
};
141153

142154
if num_elements == 0 {
143155
num_elements = mutator.gen_range(0, vec.len() + 1);
144156
}
145157

146-
num_elements = std::cmp::min(num_elements, vec.len());
158+
num_elements = std::cmp::min(num_elements, vec.len() - min_size);
147159

148160
// Special case probably isn't required here, but better to be explicit
149-
if num_elements == vec.len() {
161+
if num_elements == vec.len() && min_size == 0 {
150162
vec.drain(..);
151163
return;
152164
}
@@ -177,7 +189,7 @@ where
177189

178190
// 1% chance to resize this vec
179191
if mutator.gen_chance(CHANCE_TO_RESIZE_VEC) {
180-
shrink_vec(self, mutator);
192+
shrink_vec(self, mutator, Some(1));
181193
} else {
182194
// Recreate the constraints so that the min/max types match
183195
let constraints = constraints.and_then(|c| {
@@ -209,44 +221,82 @@ where
209221
constraints: Option<&Constraints<Self::RangeType>>,
210222
) {
211223
const CHANCE_TO_RESIZE_VEC: f64 = 0.01;
224+
const CHANCE_TO_RESIZE_EMPTY_VEC: f64 = 0.33;
212225

213226
if T::max_default_object_size() == 0 {
214227
return;
215228
}
216229

217230
// we can grow the vector if we have no size constraint or the max size quota hasn't
218231
// been fulfilled
219-
let can_grow = constraints
220-
.map(|c| {
221-
c.max_size
222-
.map(|s| s > 0 && s > T::max_default_object_size())
223-
.unwrap_or(true)
224-
})
225-
.unwrap_or(false);
232+
let mut can_grow = true;
233+
if let Some(max_elems) = constraints.and_then(|c| c.max) {
234+
if self.len() >= max_elems {
235+
can_grow = false;
236+
}
237+
}
226238

227-
if mutator.gen_chance(CHANCE_TO_RESIZE_VEC) {
228-
let resize_type = VecResizeType::new_fuzzed(mutator, None);
229-
if resize_type == VecResizeType::Grow && can_grow {
230-
grow_vec(self, mutator, constraints.and_then(|c| c.max_size));
239+
if let Some(max_size) = constraints.and_then(|c| c.max_size) {
240+
if self.len() >= max_size / T::max_default_object_size() {
241+
can_grow = false;
242+
}
243+
}
244+
245+
if self.is_empty() {
246+
if mutator.gen_chance(CHANCE_TO_RESIZE_EMPTY_VEC) {
247+
grow_vec(
248+
self,
249+
mutator,
250+
constraints.and_then(|c| c.max),
251+
constraints.and_then(|c| c.max_size),
252+
);
231253
} else {
232-
shrink_vec(self, mutator);
254+
// Recreate the constraints so that the min/max types match
255+
let constraints = constraints.and_then(|c| {
256+
if c.max_size.is_none() {
257+
None
258+
} else {
259+
let mut new_constraints = Constraints::new();
260+
new_constraints.base_object_size_accounted_for =
261+
c.base_object_size_accounted_for;
262+
new_constraints.max_size = c.max_size;
263+
264+
Some(new_constraints)
265+
}
266+
});
267+
268+
self.as_mut_slice().mutate(mutator, constraints.as_ref());
233269
}
234270
} else {
235-
// Recreate the constraints so that the min/max types match
236-
let constraints = constraints.and_then(|c| {
237-
if c.max_size.is_none() {
238-
None
271+
if mutator.gen_chance(CHANCE_TO_RESIZE_VEC) {
272+
let resize_type = VecResizeType::new_fuzzed(mutator, None);
273+
if resize_type == VecResizeType::Grow && can_grow {
274+
grow_vec(
275+
self,
276+
mutator,
277+
constraints.and_then(|c| c.max),
278+
constraints.and_then(|c| c.max_size),
279+
);
239280
} else {
240-
let mut new_constraints = Constraints::new();
241-
new_constraints.base_object_size_accounted_for =
242-
c.base_object_size_accounted_for;
243-
new_constraints.max_size = c.max_size;
244-
245-
Some(new_constraints)
281+
shrink_vec(self, mutator, constraints.and_then(|c| c.min));
246282
}
247-
});
283+
} else {
284+
// Recreate the constraints so that the min/max types match
285+
let constraints = constraints.and_then(|c| {
286+
if c.max_size.is_none() {
287+
None
288+
} else {
289+
let mut new_constraints = Constraints::new();
290+
new_constraints.base_object_size_accounted_for =
291+
c.base_object_size_accounted_for;
292+
new_constraints.max_size = c.max_size;
248293

249-
self.as_mut_slice().mutate(mutator, constraints.as_ref());
294+
Some(new_constraints)
295+
}
296+
});
297+
298+
self.as_mut_slice().mutate(mutator, constraints.as_ref());
299+
}
250300
}
251301
}
252302
}
@@ -264,6 +314,7 @@ where
264314
constraints: Option<&Constraints<Self::RangeType>>,
265315
) {
266316
const CHANCE_TO_RESIZE_VEC: f64 = 0.01;
317+
const CHANCE_TO_RESIZE_EMPTY_VEC: f64 = 0.33;
267318

268319
if T::max_default_object_size() == 0 {
269320
return;
@@ -275,29 +326,61 @@ where
275326
.map(|c| c.max_size.map(|s| s > 0).unwrap_or(true))
276327
.unwrap_or(false);
277328

278-
if mutator.gen_chance(CHANCE_TO_RESIZE_VEC) {
279-
let resize_type = VecResizeType::new_fuzzed(mutator, None);
280-
if resize_type == VecResizeType::Grow && can_grow {
281-
grow_vec(self, mutator, constraints.and_then(|c| c.max_size));
329+
if self.is_empty() {
330+
if mutator.gen_chance(CHANCE_TO_RESIZE_EMPTY_VEC) {
331+
grow_vec(
332+
self,
333+
mutator,
334+
constraints.and_then(|c| c.max),
335+
constraints.and_then(|c| c.max_size),
336+
);
282337
} else {
283-
shrink_vec(self, mutator);
338+
// Recreate the constraints so that the min/max types match
339+
let constraints = constraints.and_then(|c| {
340+
if c.max_size.is_none() {
341+
None
342+
} else {
343+
let mut new_constraints = Constraints::new();
344+
new_constraints.base_object_size_accounted_for =
345+
c.base_object_size_accounted_for;
346+
new_constraints.max_size = c.max_size;
347+
348+
Some(new_constraints)
349+
}
350+
});
351+
352+
self.as_mut_slice().mutate(mutator, constraints.as_ref());
284353
}
285354
} else {
286-
// Recreate the constraints so that the min/max types match
287-
let constraints = constraints.and_then(|c| {
288-
if c.max_size.is_none() {
289-
None
355+
if mutator.gen_chance(CHANCE_TO_RESIZE_VEC) {
356+
let resize_type = VecResizeType::new_fuzzed(mutator, None);
357+
if resize_type == VecResizeType::Grow && can_grow {
358+
grow_vec(
359+
self,
360+
mutator,
361+
constraints.and_then(|c| c.max),
362+
constraints.and_then(|c| c.max_size),
363+
);
290364
} else {
291-
let mut new_constraints = Constraints::new();
292-
new_constraints.base_object_size_accounted_for =
293-
c.base_object_size_accounted_for;
294-
new_constraints.max_size = c.max_size;
295-
296-
Some(new_constraints)
365+
shrink_vec(self, mutator, constraints.and_then(|c| c.min));
297366
}
298-
});
367+
} else {
368+
// Recreate the constraints so that the min/max types match
369+
let constraints = constraints.and_then(|c| {
370+
if c.max_size.is_none() {
371+
None
372+
} else {
373+
let mut new_constraints = Constraints::new();
374+
new_constraints.base_object_size_accounted_for =
375+
c.base_object_size_accounted_for;
376+
new_constraints.max_size = c.max_size;
299377

300-
self.as_mut_slice().mutate(mutator, constraints.as_ref());
378+
Some(new_constraints)
379+
}
380+
});
381+
382+
self.as_mut_slice().mutate(mutator, constraints.as_ref());
383+
}
301384
}
302385
}
303386
}
@@ -618,18 +701,19 @@ where
618701
mutator: &mut Mutator<R>,
619702
constraints: Option<&Constraints<Self::RangeType>>,
620703
) {
621-
const CHANCE_TO_FLIP_OPTION_STATE: f64 = 0.01;
704+
const CHANCE_TO_FLIP_SOME_STATE: f64 = 0.05;
705+
const CHANCE_TO_FLIP_NONE_STATE: f64 = 0.10;
622706
match self {
623707
Some(inner) => {
624708
// small chance to make this None
625-
if mutator.gen_chance(CHANCE_TO_FLIP_OPTION_STATE) {
709+
if mutator.gen_chance(CHANCE_TO_FLIP_SOME_STATE) {
626710
*self = None;
627711
} else {
628712
inner.mutate(mutator, constraints);
629713
}
630714
}
631715
None => {
632-
if mutator.gen_chance(CHANCE_TO_FLIP_OPTION_STATE) {
716+
if mutator.gen_chance(CHANCE_TO_FLIP_NONE_STATE) {
633717
let new_item = T::new_fuzzed(mutator, constraints);
634718

635719
*self = Some(new_item);

lain/src/mutator.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,14 @@ use serde::{Deserialize, Serialize};
1616

1717
// set these to 0 to disable
1818
pub const CHANCE_TO_REPEAT_ARRAY_VALUE: f64 = 0.05;
19-
pub const CHANCE_TO_PICK_INVALID_ENUM: f64 = 0.10;
20-
pub const CHANCE_TO_IGNORE_MIN_MAX: f64 = 0.05;
19+
#[cfg(feature = "pick_invalid_enum")]
20+
pub const CHANCE_TO_PICK_INVALID_ENUM: f64 = 0.01;
21+
#[cfg(not(feature = "pick_invalid_enum"))]
22+
pub const CHANCE_TO_PICK_INVALID_ENUM: f64 = 0.0;
23+
#[cfg(feature = "ignore_min_max")]
24+
pub const CHANCE_TO_IGNORE_MIN_MAX: f64 = 0.01;
25+
#[cfg(not(feature = "ignore_min_max"))]
26+
pub const CHANCE_TO_IGNORE_MIN_MAX: f64 = 0.0;
2127

2228
#[repr(u8)]
2329
#[derive(Debug, Copy, Clone, NewFuzzed)]
@@ -107,7 +113,7 @@ impl<R: Rng> Mutator<R> {
107113
self.corpus_state.fields_fuzzed += 1;
108114
}
109115

110-
if self.gen_chance(0.10) {
116+
if self.gen_chance(0.01) {
111117
*num = T::select_dangerous_number(&mut self.rng);
112118
return;
113119
}

lain_derive/src/mutations.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -271,13 +271,16 @@ fn mutatable_enum_visitor(variants: &[Variant], cont_ident: &syn::Ident) -> Vec<
271271
fn mutatable_struct_visitor(fields: &[Field]) -> Vec<TokenStream> {
272272
fields
273273
.iter()
274-
.map(|field| {
274+
.filter_map(|field| {
275+
if field.attrs.ignore() {
276+
return None;
277+
}
275278
let (_field_ident, _field_ident_string, initializer) =
276279
field_mutator(field, "self.", false);
277280

278-
quote! {
281+
Some(quote! {
279282
#initializer
280-
}
283+
})
281284
})
282285
.collect()
283286
}

0 commit comments

Comments
 (0)