use crate::mutator::Mutator;
use crate::rand::seq::SliceRandom;
use crate::rand::Rng;
use crate::traits::*;
use crate::types::*;
use num_traits::Bounded;
use std::fmt::Debug;
use std::mem::MaybeUninit;
use std::{char, cmp};
impl<T> NewFuzzed for Vec<T>
where
T: NewFuzzed + SerializedSize,
{
type RangeType = usize;
default fn new_fuzzed<R: Rng>(
mutator: &mut Mutator<R>,
constraints: Option<&Constraints<Self::RangeType>>,
) -> Vec<T> {
const MAX_NUM_ELEMENTS: usize = 0x1000;
let mut min: Self::RangeType;
let mut max: Self::RangeType;
let weight: Weighted;
let max_size: Option<usize>;
let mut used_size: usize = 0;
let mut output: Vec<T>;
trace!("Generating random Vec with constraints: {:#?}", constraints);
match constraints {
Some(ref constraints) => {
min = constraints.min.unwrap_or(0);
max = constraints.max.unwrap_or(MAX_NUM_ELEMENTS);
if min != max {
if min != 0 && mutator.gen_chance(crate::mutator::CHANCE_TO_IGNORE_MIN_MAX) {
min = 0;
}
if constraints.max.is_some()
&& mutator.gen_chance(crate::mutator::CHANCE_TO_IGNORE_MIN_MAX)
{
max = constraints.max.unwrap() * 2;
}
}
weight = constraints.weighted;
max_size = constraints.max_size;
if let Some(max_size) = max_size {
max = cmp::min(max, max_size / T::min_nonzero_elements_size());
}
}
None => {
min = 0;
max = MAX_NUM_ELEMENTS;
max_size = None;
weight = Weighted::None;
}
}
let num_elements: usize = if min == max {
min
} else {
mutator.gen_weighted_range(min, max, weight)
};
output = Vec::with_capacity(num_elements);
for _i in 0..num_elements {
let element = if let Some(ref max_size) = max_size {
T::new_fuzzed(
mutator,
Some(&Constraints::new().max_size(max_size - used_size).set_base_size_accounted_for()),
)
} else {
T::new_fuzzed(mutator, None)
};
let element_serialized_size = element.serialized_size();
if let Some(ref max_size) = max_size {
if used_size + element_serialized_size > *max_size {
return output;
} else {
used_size += element_serialized_size;
}
}
output.push(element);
}
output
}
}
impl<T> NewFuzzed for Vec<T>
where
T: NewFuzzed + Clone + SerializedSize,
{
fn new_fuzzed<R: Rng>(
mutator: &mut Mutator<R>,
constraints: Option<&Constraints<Self::RangeType>>,
) -> Vec<T> {
const MAX_NUM_ELEMENTS: usize = 0x1000;
let mut min: Self::RangeType;
let mut max: Self::RangeType;
let weight: Weighted;
let max_size: Option<usize>;
let mut used_size: usize = 0;
let mut output: Vec<T>;
trace!("Generating random Vec with constraints: {:#?}", constraints);
match constraints {
Some(constraints) => {
min = constraints.min.unwrap_or(0);
max = constraints.max.unwrap_or(MAX_NUM_ELEMENTS);
if min != max {
if min != 0 && mutator.gen_chance(crate::mutator::CHANCE_TO_IGNORE_MIN_MAX) {
min = 0;
}
if constraints.max.is_some()
&& mutator.gen_chance(crate::mutator::CHANCE_TO_IGNORE_MIN_MAX)
{
max = constraints.max.unwrap() * 2;
}
}
weight = constraints.weighted;
max_size = constraints.max_size;
if let Some(max_size) = constraints.max_size {
max = cmp::min(max, (max_size + (T::min_nonzero_elements_size() * min)) / T::min_nonzero_elements_size());
}
}
None => {
min = 0;
max = MAX_NUM_ELEMENTS;
max_size = None;
weight = Weighted::None;
}
}
let num_elements: usize = if min == max {
min
} else {
mutator.gen_weighted_range(min, max, weight)
};
output = Vec::with_capacity(num_elements);
let should_reuse_array_item =
mutator.gen_chance(crate::mutator::CHANCE_TO_REPEAT_ARRAY_VALUE);
if should_reuse_array_item {
let element: T = if let Some(ref max_size) = max_size {
T::new_fuzzed(
mutator,
Some(&Constraints::new().max_size(max_size - used_size).set_base_size_accounted_for()),
)
} else {
T::new_fuzzed(mutator, None)
};
let element_serialized_size = element.serialized_size();
for _i in 0..num_elements {
if let Some(ref max_size) = max_size {
if used_size + element_serialized_size > *max_size {
return output;
} else {
used_size += T::min_nonzero_elements_size() - element_serialized_size;
}
}
output.push(element.clone());
}
} else {
for _i in 0..num_elements {
let element: T = if let Some(ref max_size) = max_size {
T::new_fuzzed(
mutator,
Some(&Constraints::new().max_size(max_size - used_size).set_base_size_accounted_for()),
)
} else {
T::new_fuzzed(mutator, None)
};
let element_serialized_size = element.serialized_size();
if let Some(ref max_size) = max_size {
if used_size + element_serialized_size > *max_size {
return output;
} else {
used_size += T::min_nonzero_elements_size() - element_serialized_size;
}
}
output.push(element);
}
}
output
}
}
impl<T, I> NewFuzzed for UnsafeEnum<T, I>
where
T: NewFuzzed,
I: NewFuzzed<RangeType = I> + Bounded + Debug + Default,
{
type RangeType = I;
fn new_fuzzed<R: Rng>(
mutator: &mut Mutator<R>,
constraints: Option<&Constraints<Self::RangeType>>,
) -> Self {
trace!(
"Generating random UnsafeEnum with constraints: {:#?}",
constraints
);
if mutator.gen_chance(crate::mutator::CHANCE_TO_PICK_INVALID_ENUM) {
UnsafeEnum::Invalid(I::new_fuzzed(mutator, constraints))
} else {
UnsafeEnum::Valid(T::new_fuzzed(mutator, None))
}
}
}
impl NewFuzzed for Utf8String {
type RangeType = usize;
fn new_fuzzed<R: Rng>(
mutator: &mut Mutator<R>,
constraints: Option<&Constraints<Self::RangeType>>,
) -> Self {
let min: Self::RangeType;
let max: Self::RangeType;
let weight: Weighted;
let mut output: Utf8String;
trace!(
"Generating random UtfString with constraints: {:#?}",
constraints
);
match constraints {
Some(ref constraints) => {
min = constraints.min.unwrap_or(0);
max = constraints.max.unwrap_or(256);
weight = constraints.weighted;
}
None => {
min = 0;
max = 256;
weight = Weighted::None;
}
}
let string_length = mutator.gen_weighted_range(min, max, weight);
output = Utf8String {
inner: Vec::with_capacity(string_length),
};
let mut idx = 0;
let mut chr = Utf8Char::new_fuzzed(mutator, None);
while idx < string_length {
output.inner.push(chr.clone());
idx += 1;
if string_length - idx > 0 {
if mutator.gen_chance(crate::mutator::CHANCE_TO_REPEAT_ARRAY_VALUE) {
let repeat_end_idx = mutator.gen_range(idx, string_length);
while idx < repeat_end_idx {
output.inner.push(chr.clone());
idx += 1;
}
if string_length - idx > 0 {
chr = Utf8Char::new_fuzzed(mutator, None);
}
} else {
chr = Utf8Char::new_fuzzed(mutator, None);
}
}
}
output
}
}
impl NewFuzzed for AsciiString {
type RangeType = usize;
fn new_fuzzed<R: Rng>(
mutator: &mut Mutator<R>,
constraints: Option<&Constraints<Self::RangeType>>,
) -> Self {
let min: Self::RangeType;
let max: Self::RangeType;
let weight: Weighted;
let mut output: AsciiString;
trace!(
"Generating random AsciiString with constraints: {:#?}",
constraints
);
match constraints {
Some(ref constraints) => {
min = constraints.min.unwrap_or(0);
max = constraints.max.unwrap_or(256);
weight = constraints.weighted;
}
None => {
min = 0;
max = 256;
weight = Weighted::None;
}
}
let string_length = mutator.gen_weighted_range(min, max, weight);
output = AsciiString {
inner: Vec::with_capacity(string_length),
};
let mut idx = 0;
let mut chr = AsciiChar::new_fuzzed(mutator, None);
while idx < string_length {
output.inner.push(chr.clone());
idx += 1;
if string_length - idx > 0 {
if mutator.gen_chance(crate::mutator::CHANCE_TO_REPEAT_ARRAY_VALUE) {
let repeat_end_idx = mutator.gen_range(idx, string_length);
while idx < repeat_end_idx {
output.inner.push(chr.clone());
idx += 1;
}
if string_length - idx > 0 {
chr = AsciiChar::new_fuzzed(mutator, None);
}
} else {
chr = AsciiChar::new_fuzzed(mutator, None);
}
}
}
output
}
}
impl NewFuzzed for Utf8Char {
type RangeType = u32;
fn new_fuzzed<R: crate::rand::Rng>(
mutator: &mut crate::mutator::Mutator<R>,
_constraints: Option<&Constraints<Self::RangeType>>,
) -> Self {
trace!("generating random UTF8 char");
let mode_chance = mutator.gen_range(0, 100);
match mode_chance {
0..=49 => Utf8Char(mutator.gen_range(0, 0xB0) as u8 as char),
50..=59 => {
loop {
if let Some(c) = char::from_u32(mutator.gen_range(0, 0x10000)) {
return Utf8Char(c);
}
}
}
60..=84 => {
let c = [
' ', ' ', ' ', '\t', '\n', '~', '`', '!', '@', '#', '$', '%', '^', '&', '*',
'(', ')', '_', '-', '=', '+', '[', ']', '{', '}', ':', ';', '\'', '"', '\\',
'|', ',', '<', '>', '.', '/', '?', '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9',
]
.choose(&mut mutator.rng)
.unwrap()
.to_owned();
Utf8Char(c)
}
85..=89 => {
let c = [
'\u{0149}', '\u{fff0}', '\u{fff1}',
'\u{fff2}',
'\u{fff3}',
'\u{fff4}',
'\u{fff5}',
'\u{fff6}',
'\u{fff7}',
'\u{fff8}',
'\u{fff9}',
'\u{fffA}',
'\u{fffB}',
'\u{fffC}',
'\u{fffD}',
'\u{fffE}',
'\u{fffF}',
'\u{0600}',
'\u{0601}',
'\u{0602}',
'\u{0603}',
'\u{0604}',
'\u{0605}',
'\u{061C}',
'\u{06DD}',
'\u{070F}',
'\u{180E}',
'\u{110BD}',
'\u{1D173}',
'\u{e0001}', '\u{e0020}', '\u{e000}',
'\u{e001}',
'\u{ef8ff}', '\u{f0000}',
'\u{ffffd}',
'\u{ffffe}',
'\u{fffff}',
'\u{100000}',
'\u{10FFFD}',
'\u{10FFFE}',
'\u{10FFFF}',
'\u{3000}', '\u{1680}',
]
.choose(&mut mutator.rng)
.unwrap()
.to_owned();
Utf8Char(c)
}
90..=94 => {
Utf8Char(char::from_u32(mutator.gen_range(0x2000, 0x2070)).unwrap())
}
95..=99 => {
Utf8Char(mutator.gen())
}
_ => unreachable!(),
}
}
}
impl NewFuzzed for AsciiChar {
type RangeType = u8;
fn new_fuzzed<R: crate::rand::Rng>(
mutator: &mut crate::mutator::Mutator<R>,
constraints: Option<&Constraints<Self::RangeType>>,
) -> Self {
trace!("generating random ASCII char");
let min: Self::RangeType;
let max: Self::RangeType;
let weight: Weighted;
match constraints {
Some(ref constraints) => {
min = constraints.min.unwrap_or(0);
max = constraints.max.unwrap_or(0x80);
weight = constraints.weighted;
}
None => {
let mode_chance = mutator.gen_range(0, 100);
match mode_chance {
0..=49 => {
return AsciiChar(mutator.gen_range(0, 0x80) as u8 as char);
}
50..=99 => {
let c = [
' ', ' ', ' ', '\t', '\n', '~', '`', '!', '@', '#', '$', '%', '^', '&',
'*', '(', ')', '_', '-', '=', '+', '[', ']', '{', '}', ':', ';', '\'',
'"', '\\', '|', ',', '<', '>', '.', '/', '?', '0', '1', '2', '3', '4',
'5', '6', '7', '8', '9',
]
.choose(&mut mutator.rng)
.unwrap()
.to_owned();
return AsciiChar(c);
}
_ => unreachable!(),
}
}
}
AsciiChar(
std::char::from_u32(mutator.gen_weighted_range(min as u32, max as u32, weight))
.expect("Invalid codepoint generated for AsciiChar"),
)
}
}
impl NewFuzzed for char {
type RangeType = u32;
fn new_fuzzed<R: crate::rand::Rng>(
mutator: &mut crate::mutator::Mutator<R>,
constraints: Option<&Constraints<Self::RangeType>>,
) -> Self {
Utf8Char::new_fuzzed(mutator, constraints).0
}
}
impl NewFuzzed for bool {
type RangeType = u8;
fn new_fuzzed<R: crate::rand::Rng>(
mutator: &mut crate::mutator::Mutator<R>,
_constraints: Option<&Constraints<Self::RangeType>>,
) -> Self {
trace!("generating random bool");
mutator.gen_range(0u8, 2u8) != 0
}
}
macro_rules! impl_new_fuzzed {
( $($name:ident),* ) => {
$(
impl NewFuzzed for $name {
type RangeType = $name;
fn new_fuzzed<R: Rng>(mutator: &mut Mutator<R>, constraints: Option<&Constraints<Self::RangeType>>) -> Self {
let min: Self::RangeType;
let max: Self::RangeType;
let weight: Weighted;
match constraints {
Some(ref constraints) => {
min = if let Some(ref min) = constraints.min {
if mutator.gen_chance(crate::mutator::CHANCE_TO_IGNORE_MIN_MAX) {
$name::min_value()
} else {
*min
}
} else {
$name::min_value()
};
max = if let Some(ref max) = constraints.max {
if mutator.gen_chance(crate::mutator::CHANCE_TO_IGNORE_MIN_MAX) {
$name::max_value()
} else {
*max
}
} else {
$name::max_value()
};
weight = constraints.weighted;
return mutator.gen_weighted_range(min, max, weight);
}
None => {
return mutator.rng.gen();
}
}
}
}
)*
}
}
impl_new_fuzzed!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
impl<T> NewFuzzed for [T; 0]
where
T: NewFuzzed + Clone,
{
type RangeType = usize;
fn new_fuzzed<R: Rng>(
_mutator: &mut Mutator<R>,
_constraints: Option<&Constraints<Self::RangeType>>,
) -> [T; 0] {
[]
}
}
macro_rules! impl_new_fuzzed_array {
( $($size:expr),* ) => {
$(
impl<T> NewFuzzed for [T; $size]
where T: NewFuzzed + Clone + SerializedSize {
type RangeType = usize;
fn new_fuzzed<R: Rng>(mutator: &mut Mutator<R>, constraints: Option<&Constraints<Self::RangeType>>) -> [T; $size] {
let mut max_size: Option<usize> = None;
if let Some(ref constraints) = constraints {
if let Some(temp_max_size) = constraints.max_size {
if T::min_nonzero_elements_size() * $size > temp_max_size {
warn!("max size provided to array is smaller than the min size of array");
}
max_size = Some(temp_max_size / $size)
}
}
let mut output: MaybeUninit<[T; $size]> = MaybeUninit::uninit();
let arr_ptr = output.as_mut_ptr() as *mut T;
let mut idx = 0;
let mut element: T = if let Some(max_size) = max_size {
T::new_fuzzed(mutator, Some(&Constraints::new().max_size(max_size)))
} else {
T::new_fuzzed(mutator, None)
};
while idx < $size {
unsafe {
arr_ptr.add(idx).write(element.clone());
}
idx += 1;
if $size - idx > 0 {
if mutator.gen_chance(crate::mutator::CHANCE_TO_REPEAT_ARRAY_VALUE) {
let repeat_end_idx = mutator.gen_range(idx, $size);
while idx < repeat_end_idx {
unsafe {
arr_ptr.add(idx).write(element.clone());
}
idx += 1;
}
if $size - idx > 0 {
element = if let Some(max_size) = max_size {
T::new_fuzzed(mutator, Some(&Constraints::new().max_size(max_size)))
} else {
T::new_fuzzed(mutator, None)
};
}
} else {
element = if let Some(max_size) = max_size {
T::new_fuzzed(mutator, Some(&Constraints::new().max_size(max_size)))
} else {
T::new_fuzzed(mutator, None)
};
}
}
}
unsafe { output.assume_init() }
}
}
impl<T> NewFuzzed for [T; $size]
where T: NewFuzzed + SerializedSize {
default type RangeType = usize;
default fn new_fuzzed<R: Rng>(mutator: &mut Mutator<R>, constraints: Option<&Constraints<Self::RangeType>>) -> [T; $size] {
let mut max_size: Option<usize> = None;
if let Some(ref constraints) = constraints {
if let Some(temp_max_size) = constraints.max_size {
if T::min_nonzero_elements_size() * $size > temp_max_size {
warn!("max size provided to array is smaller than the min size of array");
}
max_size = Some(temp_max_size / $size)
}
}
let mut output: MaybeUninit<[T; $size]> = MaybeUninit::uninit();
let arr_ptr = output.as_mut_ptr() as *mut T;
for i in 0..$size {
let element = if let Some(max_size) = max_size {
T::new_fuzzed(mutator, Some(&Constraints::new().max_size(max_size)))
} else {
T::new_fuzzed(mutator, None)
};
unsafe {
arr_ptr.offset(i).write(element);
}
}
unsafe { output.assume_init() }
}
}
)*
}
}
impl_new_fuzzed_array!(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60
);