The choose method takes an ExactSizeIterator and returns a randomly chosen item from it. Using this method prevents chosing items with an incorrect upper_bound on the index. Various macros help with defining and implementing repetitive mutation strategies.
This commit is contained in:
parent
cbec59bea8
commit
e65a2f9550
@ -49,6 +49,29 @@ pub trait Rand: Debug + Serialize + DeserializeOwned {
|
|||||||
debug_assert!(lower_bound_incl <= upper_bound_incl);
|
debug_assert!(lower_bound_incl <= upper_bound_incl);
|
||||||
lower_bound_incl + self.below(upper_bound_incl - lower_bound_incl + 1)
|
lower_bound_incl + self.below(upper_bound_incl - lower_bound_incl + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Choose an item at random from the given iterator, sampling uniformly.
|
||||||
|
///
|
||||||
|
/// Note: the runtime cost is bound by the iterator's [`nth`][`Iterator::nth`] implementation
|
||||||
|
/// * For `Vec`, slice, array, this is O(1)
|
||||||
|
/// * For `HashMap`, `HashSet`, this is O(n)
|
||||||
|
fn choose<I, E, T>(&mut self, from: I) -> T
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = T, IntoIter = E>,
|
||||||
|
E: ExactSizeIterator + Iterator<Item = T>,
|
||||||
|
{
|
||||||
|
// create iterator
|
||||||
|
let mut iter = from.into_iter();
|
||||||
|
|
||||||
|
// make sure there is something to choose from
|
||||||
|
debug_assert!(iter.len() > 0, "choosing from an empty iterator");
|
||||||
|
|
||||||
|
// pick a random, valid index
|
||||||
|
let index = self.below(iter.len() as u64) as usize;
|
||||||
|
|
||||||
|
// return the item chosen
|
||||||
|
iter.nth(index).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Has a Rand field, that can be used to get random values
|
/// Has a Rand field, that can be used to get random values
|
||||||
|
@ -86,9 +86,7 @@ where
|
|||||||
size = 1;
|
size = 1;
|
||||||
}
|
}
|
||||||
let printables = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz \t\n!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".as_bytes();
|
let printables = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz \t\n!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".as_bytes();
|
||||||
let random_bytes: Vec<u8> = (0..size)
|
let random_bytes: Vec<u8> = (0..size).map(|_| *rand.choose(printables)).collect();
|
||||||
.map(|_| printables[rand.below(printables.len() as u64) as usize])
|
|
||||||
.collect();
|
|
||||||
Ok(BytesInput::new(random_bytes))
|
Ok(BytesInput::new(random_bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,11 +117,9 @@ where
|
|||||||
if input.bytes().is_empty() {
|
if input.bytes().is_empty() {
|
||||||
Ok(MutationResult::Skipped)
|
Ok(MutationResult::Skipped)
|
||||||
} else {
|
} else {
|
||||||
let bit = state.rand_mut().below((input.bytes().len() << 3) as u64) as usize;
|
let bit = 1 << state.rand_mut().choose(0..8);
|
||||||
unsafe {
|
let byte = state.rand_mut().choose(input.bytes_mut());
|
||||||
// Moar speed, no bound check
|
*byte ^= bit;
|
||||||
*input.bytes_mut().get_unchecked_mut(bit >> 3) ^= (128u8 >> (bit & 7)) as u8;
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,11 +177,7 @@ where
|
|||||||
if input.bytes().is_empty() {
|
if input.bytes().is_empty() {
|
||||||
Ok(MutationResult::Skipped)
|
Ok(MutationResult::Skipped)
|
||||||
} else {
|
} else {
|
||||||
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize;
|
*state.rand_mut().choose(input.bytes_mut()) ^= 0xff;
|
||||||
unsafe {
|
|
||||||
// Moar speed, no bound check
|
|
||||||
*input.bytes_mut().get_unchecked_mut(idx) ^= 0xff;
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,12 +235,8 @@ where
|
|||||||
if input.bytes().is_empty() {
|
if input.bytes().is_empty() {
|
||||||
Ok(MutationResult::Skipped)
|
Ok(MutationResult::Skipped)
|
||||||
} else {
|
} else {
|
||||||
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize;
|
let byte = state.rand_mut().choose(input.bytes_mut());
|
||||||
unsafe {
|
*byte = byte.wrapping_add(1);
|
||||||
// Moar speed, no bound check
|
|
||||||
let ptr = input.bytes_mut().get_unchecked_mut(idx);
|
|
||||||
*ptr = (*ptr).wrapping_add(1);
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -304,12 +294,8 @@ where
|
|||||||
if input.bytes().is_empty() {
|
if input.bytes().is_empty() {
|
||||||
Ok(MutationResult::Skipped)
|
Ok(MutationResult::Skipped)
|
||||||
} else {
|
} else {
|
||||||
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize;
|
let byte = state.rand_mut().choose(input.bytes_mut());
|
||||||
unsafe {
|
*byte = byte.wrapping_sub(1);
|
||||||
// Moar speed, no bound check
|
|
||||||
let ptr = input.bytes_mut().get_unchecked_mut(idx);
|
|
||||||
*ptr = (*ptr).wrapping_sub(1);
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,11 +353,8 @@ where
|
|||||||
if input.bytes().is_empty() {
|
if input.bytes().is_empty() {
|
||||||
Ok(MutationResult::Skipped)
|
Ok(MutationResult::Skipped)
|
||||||
} else {
|
} else {
|
||||||
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize;
|
let byte = state.rand_mut().choose(input.bytes_mut());
|
||||||
unsafe {
|
*byte = !*byte;
|
||||||
// Moar speed, no bound check
|
|
||||||
*input.bytes_mut().get_unchecked_mut(idx) = !(*input.bytes().get_unchecked(idx));
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,11 +412,8 @@ where
|
|||||||
if input.bytes().is_empty() {
|
if input.bytes().is_empty() {
|
||||||
Ok(MutationResult::Skipped)
|
Ok(MutationResult::Skipped)
|
||||||
} else {
|
} else {
|
||||||
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize;
|
let byte = state.rand_mut().choose(input.bytes_mut());
|
||||||
unsafe {
|
*byte = state.rand_mut().next() as u8;
|
||||||
// Moar speed, no bound check
|
|
||||||
*input.bytes_mut().get_unchecked_mut(idx) = state.rand_mut().below(256) as u8;
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -465,9 +445,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Byte add mutation for inputs with a bytes vector
|
// Helper macro that defines the arithmetic addition/subtraction mutations where random slices
|
||||||
|
// within the input are treated as u8, u16, u32, or u64, then mutated in place.
|
||||||
|
macro_rules! add_mutator_impl {
|
||||||
|
($name: ident, $size: ty) => {
|
||||||
|
/// Adds or subtracts a random value up to `ARITH_MAX` to a [`<$size>`] at a random place in the [`Vec`], in random byte order.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ByteAddMutator<I, R, S>
|
pub struct $name<I, R, S>
|
||||||
where
|
where
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
S: HasRand<R>,
|
S: HasRand<R>,
|
||||||
@ -476,7 +460,7 @@ where
|
|||||||
phantom: PhantomData<(I, R, S)>,
|
phantom: PhantomData<(I, R, S)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, R, S> Mutator<I, S> for ByteAddMutator<I, R, S>
|
impl<I, R, S> Mutator<I, S> for $name<I, R, S>
|
||||||
where
|
where
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
S: HasRand<R>,
|
S: HasRand<R>,
|
||||||
@ -488,54 +472,72 @@ where
|
|||||||
input: &mut I,
|
input: &mut I,
|
||||||
_stage_idx: i32,
|
_stage_idx: i32,
|
||||||
) -> Result<MutationResult, Error> {
|
) -> Result<MutationResult, Error> {
|
||||||
if input.bytes().is_empty() {
|
if input.bytes().len() < size_of::<$size>() {
|
||||||
Ok(MutationResult::Skipped)
|
Ok(MutationResult::Skipped)
|
||||||
} else {
|
} else {
|
||||||
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize;
|
// choose a random window of bytes (windows overlap) and convert to $size
|
||||||
unsafe {
|
let (index, bytes) = state
|
||||||
// Moar speed, no bound check
|
.rand_mut()
|
||||||
let ptr = input.bytes_mut().get_unchecked_mut(idx) as *mut u8;
|
.choose(input.bytes().windows(size_of::<$size>()).enumerate());
|
||||||
let num = 1 + state.rand_mut().below(ARITH_MAX) as u8;
|
let val = <$size>::from_ne_bytes(bytes.try_into().unwrap());
|
||||||
match state.rand_mut().below(2) {
|
|
||||||
0 => *ptr = (*ptr).wrapping_add(num),
|
// mutate
|
||||||
_ => *ptr = (*ptr).wrapping_sub(num),
|
let num = 1 + state.rand_mut().below(ARITH_MAX) as $size;
|
||||||
|
let new_val = match state.rand_mut().below(4) {
|
||||||
|
0 => val.wrapping_add(num),
|
||||||
|
1 => val.wrapping_sub(num),
|
||||||
|
2 => val.swap_bytes().wrapping_add(num).swap_bytes(),
|
||||||
|
_ => val.swap_bytes().wrapping_sub(num).swap_bytes(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// set bytes to mutated value
|
||||||
|
let new_bytes = &mut input.bytes_mut()[index..index + size_of::<$size>()];
|
||||||
|
new_bytes.copy_from_slice(&new_val.to_ne_bytes());
|
||||||
|
Ok(MutationResult::Mutated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, R, S> Named for $name<I, R, S>
|
||||||
|
where
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
S: HasRand<R>,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
stringify!($name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, R, S> $name<I, R, S>
|
||||||
|
where
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
S: HasRand<R>,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
/// Creates a new [`$name`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> Named for ByteAddMutator<I, R, S>
|
add_mutator_impl!(ByteAddMutator, u8);
|
||||||
where
|
add_mutator_impl!(WordAddMutator, u16);
|
||||||
I: Input + HasBytesVec,
|
add_mutator_impl!(DwordAddMutator, u32);
|
||||||
S: HasRand<R>,
|
add_mutator_impl!(QwordAddMutator, u64);
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"ByteAddMutator"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> ByteAddMutator<I, R, S>
|
///////////////////////////
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
/// Creates a new [`ByteAddMutator`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Word add mutation for inputs with a bytes vector
|
macro_rules! interesting_mutator_impl {
|
||||||
/// adds or subtracts a random value up to [`ARITH_MAX`] to a [`u16`] at a random place in the [`Vec`].
|
($name: ident, $size: ty, $interesting: ident) => {
|
||||||
|
/// Inserts an interesting value at a random place in the input vector
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct WordAddMutator<I, R, S>
|
pub struct $name<I, R, S>
|
||||||
where
|
where
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
S: HasRand<R>,
|
S: HasRand<R>,
|
||||||
@ -544,221 +546,7 @@ where
|
|||||||
phantom: PhantomData<(I, R, S)>,
|
phantom: PhantomData<(I, R, S)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, R, S> Mutator<I, S> for WordAddMutator<I, R, S>
|
impl<I, R, S> Mutator<I, S> for $name<I, R, S>
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn mutate(
|
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
|
||||||
input: &mut I,
|
|
||||||
_stage_idx: i32,
|
|
||||||
) -> Result<MutationResult, Error> {
|
|
||||||
if input.bytes().len() < size_of::<u16>() {
|
|
||||||
Ok(MutationResult::Skipped)
|
|
||||||
} else {
|
|
||||||
let bytes = input.bytes_mut();
|
|
||||||
let idx = state
|
|
||||||
.rand_mut()
|
|
||||||
.below((bytes.len() - size_of::<u16>() + 1) as u64) as usize;
|
|
||||||
let val = u16::from_ne_bytes(bytes[idx..idx + size_of::<u16>()].try_into().unwrap());
|
|
||||||
let num = 1 + state.rand_mut().below(ARITH_MAX) as u16;
|
|
||||||
let new_bytes = match state.rand_mut().below(4) {
|
|
||||||
0 => val.wrapping_add(num),
|
|
||||||
1 => val.wrapping_sub(num),
|
|
||||||
2 => val.swap_bytes().wrapping_add(num).swap_bytes(),
|
|
||||||
_ => val.swap_bytes().wrapping_sub(num).swap_bytes(),
|
|
||||||
}
|
|
||||||
.to_ne_bytes();
|
|
||||||
bytes[idx..idx + size_of::<u16>()].copy_from_slice(&new_bytes);
|
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> Named for WordAddMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"WordAddMutator"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> WordAddMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
/// Creates a new [`WordAddMutator`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Dword add mutation for inputs with a bytes vector.
|
|
||||||
/// Adds a random value up to `ARITH_MAX` to a [`u32`] at a random place in the [`Vec`], in random byte order.
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct DwordAddMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
phantom: PhantomData<(I, R, S)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> Mutator<I, S> for DwordAddMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn mutate(
|
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
|
||||||
input: &mut I,
|
|
||||||
_stage_idx: i32,
|
|
||||||
) -> Result<MutationResult, Error> {
|
|
||||||
if input.bytes().len() < size_of::<u32>() {
|
|
||||||
Ok(MutationResult::Skipped)
|
|
||||||
} else {
|
|
||||||
let bytes = input.bytes_mut();
|
|
||||||
let idx = state
|
|
||||||
.rand_mut()
|
|
||||||
.below((bytes.len() - size_of::<u32>() + 1) as u64) as usize;
|
|
||||||
let val = u32::from_ne_bytes(bytes[idx..idx + size_of::<u32>()].try_into().unwrap());
|
|
||||||
let num = 1 + state.rand_mut().below(ARITH_MAX) as u32;
|
|
||||||
let new_bytes = match state.rand_mut().below(4) {
|
|
||||||
0 => val.wrapping_add(num),
|
|
||||||
1 => val.wrapping_sub(num),
|
|
||||||
2 => val.swap_bytes().wrapping_add(num).swap_bytes(),
|
|
||||||
_ => val.swap_bytes().wrapping_sub(num).swap_bytes(),
|
|
||||||
}
|
|
||||||
.to_ne_bytes();
|
|
||||||
bytes[idx..idx + size_of::<u32>()].copy_from_slice(&new_bytes);
|
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> Named for DwordAddMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"DwordAddMutator"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> DwordAddMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
/// Creates a new [`DwordAddMutator`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Qword add mutation for inputs with a bytes vector
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct QwordAddMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
phantom: PhantomData<(I, R, S)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> Mutator<I, S> for QwordAddMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn mutate(
|
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
|
||||||
input: &mut I,
|
|
||||||
_stage_idx: i32,
|
|
||||||
) -> Result<MutationResult, Error> {
|
|
||||||
if input.bytes().len() < 8 {
|
|
||||||
Ok(MutationResult::Skipped)
|
|
||||||
} else {
|
|
||||||
let bytes = input.bytes_mut();
|
|
||||||
let idx = state
|
|
||||||
.rand_mut()
|
|
||||||
.below((bytes.len() - size_of::<u64>() + 1) as u64) as usize;
|
|
||||||
let val = u64::from_ne_bytes(bytes[idx..idx + size_of::<u64>()].try_into().unwrap());
|
|
||||||
let num = 1 + state.rand_mut().below(ARITH_MAX) as u64;
|
|
||||||
let new_bytes = match state.rand_mut().below(4) {
|
|
||||||
0 => val.wrapping_add(num),
|
|
||||||
1 => val.wrapping_sub(num),
|
|
||||||
2 => val.swap_bytes().wrapping_add(num).swap_bytes(),
|
|
||||||
_ => val.swap_bytes().wrapping_sub(num).swap_bytes(),
|
|
||||||
}
|
|
||||||
.to_ne_bytes();
|
|
||||||
bytes[idx..idx + size_of::<u64>()].copy_from_slice(&new_bytes);
|
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> Named for QwordAddMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"QwordAddMutator"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> QwordAddMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
/// Creates a new [`QwordAddMutator`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Byte interesting mutation for inputs with a bytes vector
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct ByteInterestingMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
phantom: PhantomData<(I, R, S)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> Mutator<I, S> for ByteInterestingMutator<I, R, S>
|
|
||||||
where
|
where
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
S: HasRand<R>,
|
S: HasRand<R>,
|
||||||
@ -771,107 +559,41 @@ where
|
|||||||
input: &mut I,
|
input: &mut I,
|
||||||
_stage_idx: i32,
|
_stage_idx: i32,
|
||||||
) -> Result<MutationResult, Error> {
|
) -> Result<MutationResult, Error> {
|
||||||
if input.bytes().is_empty() {
|
if input.bytes().len() < size_of::<$size>() {
|
||||||
Ok(MutationResult::Skipped)
|
|
||||||
} else {
|
|
||||||
let idx = state.rand_mut().below(input.bytes().len() as u64) as usize;
|
|
||||||
let val =
|
|
||||||
INTERESTING_8[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u8;
|
|
||||||
unsafe {
|
|
||||||
// Moar speed, no bound check
|
|
||||||
*input.bytes_mut().get_unchecked_mut(idx) = val;
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> Named for ByteInterestingMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"ByteInterestingMutator"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> ByteInterestingMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
/// Creates a new [`ByteInterestingMutator`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Word interesting mutation for inputs with a bytes vector
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct WordInterestingMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
phantom: PhantomData<(I, R, S)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> Mutator<I, S> for WordInterestingMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
#[allow(clippy::cast_sign_loss)]
|
|
||||||
fn mutate(
|
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
|
||||||
input: &mut I,
|
|
||||||
_stage_idx: i32,
|
|
||||||
) -> Result<MutationResult, Error> {
|
|
||||||
if input.bytes().len() < 2 {
|
|
||||||
Ok(MutationResult::Skipped)
|
Ok(MutationResult::Skipped)
|
||||||
} else {
|
} else {
|
||||||
let bytes = input.bytes_mut();
|
let bytes = input.bytes_mut();
|
||||||
let idx = state.rand_mut().below(bytes.len() as u64 - 1) as usize;
|
let upper_bound = (bytes.len() + 1 - size_of::<$size>()) as u64;
|
||||||
let val =
|
let idx = state.rand_mut().below(upper_bound) as usize;
|
||||||
INTERESTING_16[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u16;
|
let val = *state.rand_mut().choose(&$interesting) as $size;
|
||||||
let new_bytes = if state.rand_mut().below(2) == 0 {
|
let new_bytes = match state.rand_mut().choose(&[0, 1]) {
|
||||||
val.to_be_bytes()
|
0 => val.to_be_bytes(),
|
||||||
} else {
|
_ => val.to_le_bytes(),
|
||||||
val.to_le_bytes()
|
|
||||||
};
|
};
|
||||||
bytes[idx..idx + size_of::<u16>()].copy_from_slice(&new_bytes);
|
bytes[idx..idx + size_of::<$size>()].copy_from_slice(&new_bytes);
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, R, S> Named for WordInterestingMutator<I, R, S>
|
impl<I, R, S> Named for $name<I, R, S>
|
||||||
where
|
where
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
S: HasRand<R>,
|
S: HasRand<R>,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"WordInterestingMutator"
|
stringify!($name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, R, S> WordInterestingMutator<I, R, S>
|
impl<I, R, S> $name<I, R, S>
|
||||||
where
|
where
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
S: HasRand<R>,
|
S: HasRand<R>,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Creates a new [`WordInterestingMutator`].
|
/// Creates a new [`$name`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -879,74 +601,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dword interesting mutation for inputs with a bytes vector
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct DwordInterestingMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
phantom: PhantomData<(I, R, S)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> Mutator<I, S> for DwordInterestingMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
#[allow(clippy::cast_sign_loss)]
|
|
||||||
fn mutate(
|
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
|
||||||
input: &mut I,
|
|
||||||
_stage_idx: i32,
|
|
||||||
) -> Result<MutationResult, Error> {
|
|
||||||
if input.bytes().len() < 4 {
|
|
||||||
Ok(MutationResult::Skipped)
|
|
||||||
} else {
|
|
||||||
let bytes = input.bytes_mut();
|
|
||||||
let idx = state.rand_mut().below(bytes.len() as u64 - 3) as usize;
|
|
||||||
let val =
|
|
||||||
INTERESTING_32[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u32;
|
|
||||||
let new_bytes = if state.rand_mut().below(2) == 0 {
|
|
||||||
val.to_be_bytes()
|
|
||||||
} else {
|
|
||||||
val.to_le_bytes()
|
|
||||||
};
|
};
|
||||||
bytes[idx..idx + new_bytes.len()].copy_from_slice(&new_bytes);
|
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, R, S> Named for DwordInterestingMutator<I, R, S>
|
interesting_mutator_impl!(ByteInterestingMutator, u8, INTERESTING_8);
|
||||||
where
|
interesting_mutator_impl!(WordInterestingMutator, u16, INTERESTING_16);
|
||||||
I: Input + HasBytesVec,
|
interesting_mutator_impl!(DwordInterestingMutator, u32, INTERESTING_32);
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"DwordInterestingMutator"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, R, S> DwordInterestingMutator<I, R, S>
|
|
||||||
where
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
/// Creates a new [`DwordInterestingMutator`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Bytes delete mutation for inputs with a bytes vector
|
/// Bytes delete mutation for inputs with a bytes vector
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -1190,7 +850,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let val = state.rand_mut().below(256) as u8;
|
let val = state.rand_mut().next() as u8;
|
||||||
|
|
||||||
input.bytes_mut().resize(size + len, 0);
|
input.bytes_mut().resize(size + len, 0);
|
||||||
buffer_self_copy(input.bytes_mut(), off, off + len, size - off);
|
buffer_self_copy(input.bytes_mut(), off, off + len, size - off);
|
||||||
@ -1256,7 +916,7 @@ where
|
|||||||
let off = state.rand_mut().below(size as u64) as usize;
|
let off = state.rand_mut().below(size as u64) as usize;
|
||||||
let len = 1 + state.rand_mut().below(min(16, size - off) as u64) as usize;
|
let len = 1 + state.rand_mut().below(min(16, size - off) as u64) as usize;
|
||||||
|
|
||||||
let val = input.bytes()[state.rand_mut().below(size as u64) as usize];
|
let val = *state.rand_mut().choose(input.bytes());
|
||||||
|
|
||||||
buffer_set(input.bytes_mut(), off, len, val);
|
buffer_set(input.bytes_mut(), off, len, val);
|
||||||
|
|
||||||
@ -1320,7 +980,7 @@ where
|
|||||||
let off = state.rand_mut().below(size as u64) as usize;
|
let off = state.rand_mut().below(size as u64) as usize;
|
||||||
let len = 1 + state.rand_mut().below(min(16, size - off) as u64) as usize;
|
let len = 1 + state.rand_mut().below(min(16, size - off) as u64) as usize;
|
||||||
|
|
||||||
let val = state.rand_mut().below(256) as u8;
|
let val = state.rand_mut().next() as u8;
|
||||||
|
|
||||||
buffer_set(input.bytes_mut(), off, len, val);
|
buffer_set(input.bytes_mut(), off, len, val);
|
||||||
|
|
||||||
@ -1782,16 +1442,12 @@ where
|
|||||||
|
|
||||||
// Converts a hex u8 to its u8 value: 'A' -> 10 etc.
|
// Converts a hex u8 to its u8 value: 'A' -> 10 etc.
|
||||||
fn from_hex(hex: u8) -> Result<u8, Error> {
|
fn from_hex(hex: u8) -> Result<u8, Error> {
|
||||||
if (48..=57).contains(&hex) {
|
match hex {
|
||||||
return Ok(hex - 48);
|
48..=57 => Ok(hex - 48),
|
||||||
|
65..=70 => Ok(hex - 55),
|
||||||
|
97..=102 => Ok(hex - 87),
|
||||||
|
_ => Err(Error::IllegalArgument("Invalid hex character".to_owned())),
|
||||||
}
|
}
|
||||||
if (65..=70).contains(&hex) {
|
|
||||||
return Ok(hex - 55);
|
|
||||||
}
|
|
||||||
if (97..=102).contains(&hex) {
|
|
||||||
return Ok(hex - 87);
|
|
||||||
}
|
|
||||||
Err(Error::IllegalArgument("".to_owned()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decodes a dictionary token: 'foo\x41\\and\"bar' -> 'fooA\and"bar'
|
/// Decodes a dictionary token: 'foo\x41\\and\"bar' -> 'fooA\and"bar'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user