Remove MutVecInput and MappedInput in Favour of Impls on References (#2783)
* Remove MutVecInput and MappedInput * Rename mapping mutators * Update MIGRATION.md * Fix test in docs * Rename mapping mutators mappers * Fix MIGRATION.md * Fix docs link
This commit is contained in:
parent
e46cf8a851
commit
5d70216cc7
18
MIGRATION.md
18
MIGRATION.md
@ -1,12 +1,16 @@
|
|||||||
# Pre 0.9 -> 0.9
|
|
||||||
- [Migrating from LibAFL <0.9 to 0.9](https://aflplus.plus/libafl-book/design/migration-0.9.html)
|
|
||||||
|
|
||||||
# 0.14.0 -> 0.14.1
|
|
||||||
- Removed `with_observers` from `Executor` trait.
|
|
||||||
- `MmapShMemProvider::new_shmem_persistent` has been removed in favour of `MmapShMem::persist`. You probably want to do something like this: `let shmem = MmapShMemProvider::new()?.new_shmem(size)?.persist()?;`
|
|
||||||
|
|
||||||
# 0.14.1 -> 0.15.0
|
# 0.14.1 -> 0.15.0
|
||||||
- `MmapShMem::new` and `MmapShMemProvider::new_shmem_with_id` now take `AsRef<Path>` instead of a byte array for the filename/id.
|
- `MmapShMem::new` and `MmapShMemProvider::new_shmem_with_id` now take `AsRef<Path>` instead of a byte array for the filename/id.
|
||||||
- The closure passed to a `DumpToDiskStage` now provides the `Testcase` instead of just the `Input`.
|
- The closure passed to a `DumpToDiskStage` now provides the `Testcase` instead of just the `Input`.
|
||||||
- `StatsStage` is deleted, and it is superceded by `AflStatsStage`
|
- `StatsStage` is deleted, and it is superceded by `AflStatsStage`
|
||||||
-
|
- Renamed and changed mapping mutators to take borrows directly instead of `MappedInput`s. See `baby_fuzzer_custom_input` for example usage
|
||||||
|
- Related: `MutVecInput` is deprecated in favor of directly using `&mut Vec<u8>`
|
||||||
|
- Related: `MappedInputFunctionMappingMutator` and `ToMappedInputFunctionMappingMutatorMapper` have been removed as now duplicates of `MappingMutator` (previously `FunctionMappingMutator`) and `ToMappingMutator` (previously `ToFunctionMappingMutatorMapper`)
|
||||||
|
- Related: `ToOptionMappingMutatorMapper` and `ToFunctionMappingMutatorMapper` have been renamed to `ToOptionalMutator` and `ToMappingMutator` respectively
|
||||||
|
|
||||||
|
# 0.14.0 -> 0.14.1
|
||||||
|
- Removed `with_observers` from `Executor` trait.
|
||||||
|
- `MmapShMemProvider::new_shmem_persistent` has been removed in favour of `MmapShMem::persist`. You probably want to do something like this: `let shmem = MmapShMemProvider::new()?.new_shmem(size)?.persist()?;`
|
||||||
|
|
||||||
|
# Pre 0.9 -> 0.9
|
||||||
|
- [Migrating from LibAFL <0.9 to 0.9](https://aflplus.plus/libafl-book/design/migration-0.9.html)
|
@ -4,7 +4,7 @@ use std::{borrow::Cow, hash::Hash};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::CorpusId,
|
corpus::CorpusId,
|
||||||
generators::{Generator, RandBytesGenerator},
|
generators::{Generator, RandBytesGenerator},
|
||||||
inputs::{value::MutI16Input, BytesInput, HasTargetBytes, Input, MutVecInput},
|
inputs::{BytesInput, HasTargetBytes, Input},
|
||||||
mutators::{MutationResult, Mutator},
|
mutators::{MutationResult, Mutator},
|
||||||
state::HasRand,
|
state::HasRand,
|
||||||
Error, SerdeAny,
|
Error, SerdeAny,
|
||||||
@ -36,28 +36,28 @@ impl Input for CustomInput {
|
|||||||
|
|
||||||
impl CustomInput {
|
impl CustomInput {
|
||||||
/// Returns a mutable reference to the byte array
|
/// Returns a mutable reference to the byte array
|
||||||
pub fn byte_array_mut(&mut self) -> MutVecInput<'_> {
|
pub fn byte_array_mut(&mut self) -> &mut Vec<u8> {
|
||||||
(&mut self.byte_array).into()
|
&mut self.byte_array
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an immutable reference to the byte array
|
/// Returns an immutable reference to the byte array
|
||||||
pub fn byte_array(&self) -> &[u8] {
|
pub fn byte_array(&self) -> &Vec<u8> {
|
||||||
&self.byte_array
|
&self.byte_array
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to the optional byte array
|
/// Returns a mutable reference to the optional byte array
|
||||||
pub fn optional_byte_array_mut(&mut self) -> Option<MutVecInput<'_>> {
|
pub fn optional_byte_array_mut(&mut self) -> &mut Option<Vec<u8>> {
|
||||||
self.optional_byte_array.as_mut().map(|e| e.into())
|
&mut self.optional_byte_array
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an immutable reference to the optional byte array
|
/// Returns an immutable reference to the optional byte array
|
||||||
pub fn optional_byte_array(&self) -> Option<&[u8]> {
|
pub fn optional_byte_array(&self) -> &Option<Vec<u8>> {
|
||||||
self.optional_byte_array.as_deref()
|
&self.optional_byte_array
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to the number
|
/// Returns a mutable reference to the number
|
||||||
pub fn num_mut(&mut self) -> MutI16Input<'_> {
|
pub fn num_mut(&mut self) -> &mut i16 {
|
||||||
(&mut self.num).into()
|
&mut self.num
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an immutable reference to the number
|
/// Returns an immutable reference to the number
|
||||||
|
@ -34,7 +34,7 @@ use libafl_bolts::{
|
|||||||
use {
|
use {
|
||||||
libafl::mutators::{
|
libafl::mutators::{
|
||||||
havoc_mutations::{havoc_crossover_with_corpus_mapper, havoc_mutations_no_crossover},
|
havoc_mutations::{havoc_crossover_with_corpus_mapper, havoc_mutations_no_crossover},
|
||||||
mapping::{ToMappedInputFunctionMappingMutatorMapper, ToOptionMappingMutatorMapper},
|
mapping::{ToMappingMutator, ToOptionalMutator},
|
||||||
numeric::{int_mutators_no_crossover, mapped_int_mutators_crossover},
|
numeric::{int_mutators_no_crossover, mapped_int_mutators_crossover},
|
||||||
},
|
},
|
||||||
libafl_bolts::tuples::Map,
|
libafl_bolts::tuples::Map,
|
||||||
@ -164,26 +164,20 @@ pub fn main() {
|
|||||||
// Creating mutators that will operate on input.byte_array
|
// Creating mutators that will operate on input.byte_array
|
||||||
let mapped_mutators = havoc_mutations_no_crossover()
|
let mapped_mutators = havoc_mutations_no_crossover()
|
||||||
.merge(havoc_crossover_with_corpus_mapper(CustomInput::byte_array))
|
.merge(havoc_crossover_with_corpus_mapper(CustomInput::byte_array))
|
||||||
.map(ToMappedInputFunctionMappingMutatorMapper::new(
|
.map(ToMappingMutator::new(CustomInput::byte_array_mut));
|
||||||
CustomInput::byte_array_mut,
|
|
||||||
));
|
|
||||||
|
|
||||||
// Creating mutators that will operate on input.optional_byte_array
|
// Creating mutators that will operate on input.optional_byte_array
|
||||||
let optional_mapped_mutators = havoc_mutations_no_crossover()
|
let optional_mapped_mutators = havoc_mutations_no_crossover()
|
||||||
.merge(havoc_crossover_with_corpus_mapper(
|
.merge(havoc_crossover_with_corpus_mapper(
|
||||||
CustomInput::optional_byte_array,
|
CustomInput::optional_byte_array,
|
||||||
))
|
))
|
||||||
.map(ToOptionMappingMutatorMapper)
|
.map(ToOptionalMutator)
|
||||||
.map(ToMappedInputFunctionMappingMutatorMapper::new(
|
.map(ToMappingMutator::new(CustomInput::optional_byte_array_mut));
|
||||||
CustomInput::optional_byte_array_mut,
|
|
||||||
));
|
|
||||||
|
|
||||||
// Creating mutators that will operate on input.num
|
// Creating mutators that will operate on input.num
|
||||||
let int_mutators = int_mutators_no_crossover()
|
let int_mutators = int_mutators_no_crossover()
|
||||||
.merge(mapped_int_mutators_crossover(CustomInput::num))
|
.merge(mapped_int_mutators_crossover(CustomInput::num))
|
||||||
.map(ToMappedInputFunctionMappingMutatorMapper::new(
|
.map(ToMappingMutator::new(CustomInput::num_mut));
|
||||||
CustomInput::num_mut,
|
|
||||||
));
|
|
||||||
(mapped_mutators, optional_mapped_mutators, int_mutators)
|
(mapped_mutators, optional_mapped_mutators, int_mutators)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ impl HasMutatorBytes for BytesInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn extend<'a, I: IntoIterator<Item = &'a u8>>(&mut self, iter: I) {
|
fn extend<'a, I: IntoIterator<Item = &'a u8>>(&mut self, iter: I) {
|
||||||
self.as_mut().extend(iter);
|
<Vec<u8> as Extend<I::Item>>::extend(self.as_mut(), iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn splice<R, I>(&mut self, range: R, replace_with: I) -> vec::Splice<'_, I::IntoIter>
|
fn splice<R, I>(&mut self, range: R, replace_with: I) -> vec::Splice<'_, I::IntoIter>
|
||||||
|
@ -11,7 +11,7 @@ use libafl_bolts::{
|
|||||||
HasLen,
|
HasLen,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::inputs::{HasMutatorBytes, MappedInput};
|
use crate::inputs::HasMutatorBytes;
|
||||||
|
|
||||||
/// The [`BytesSubInput`] makes it possible to use [`crate::mutators::Mutator`]`s` that work on
|
/// The [`BytesSubInput`] makes it possible to use [`crate::mutators::Mutator`]`s` that work on
|
||||||
/// inputs implementing the [`HasMutatorBytes`] for a sub-range of this input.
|
/// inputs implementing the [`HasMutatorBytes`] for a sub-range of this input.
|
||||||
@ -201,23 +201,14 @@ where
|
|||||||
self.range.len()
|
self.range.len()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> MappedInput for BytesSubInput<'_, I> {
|
|
||||||
type Type<'b>
|
|
||||||
= BytesSubInput<'b, I>
|
|
||||||
where
|
|
||||||
Self: 'b;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use libafl_bolts::HasLen;
|
use libafl_bolts::HasLen;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
inputs::{BytesInput, HasMutatorBytes, MutVecInput, NopInput},
|
inputs::{BytesInput, HasMutatorBytes, NopInput},
|
||||||
mutators::{havoc_mutations_no_crossover, MutatorsTuple},
|
mutators::{havoc_mutations_no_crossover, MutatorsTuple},
|
||||||
state::NopState,
|
state::NopState,
|
||||||
};
|
};
|
||||||
@ -346,7 +337,6 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_bytessubinput_use_vec() {
|
fn test_bytessubinput_use_vec() {
|
||||||
let mut test_vec = vec![0, 1, 2, 3, 4];
|
let mut test_vec = vec![0, 1, 2, 3, 4];
|
||||||
let mut test_vec = MutVecInput::from(&mut test_vec);
|
|
||||||
let mut sub_vec = test_vec.sub_input(1..2);
|
let mut sub_vec = test_vec.sub_input(1..2);
|
||||||
drop(sub_vec.drain(..));
|
drop(sub_vec.drain(..));
|
||||||
assert_eq!(test_vec.len(), 4);
|
assert_eq!(test_vec.len(), 4);
|
||||||
|
@ -35,7 +35,7 @@ use core::{
|
|||||||
clone::Clone,
|
clone::Clone,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
ops::{Deref, DerefMut, RangeBounds},
|
ops::{DerefMut, RangeBounds},
|
||||||
};
|
};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::{fs::File, hash::Hash, io::Read, path::Path};
|
use std::{fs::File, hash::Hash, io::Read, path::Path};
|
||||||
@ -50,7 +50,6 @@ use libafl_bolts::{
|
|||||||
#[cfg(feature = "nautilus")]
|
#[cfg(feature = "nautilus")]
|
||||||
pub use nautilus::*;
|
pub use nautilus::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use value::ValueMutRefInput;
|
|
||||||
|
|
||||||
use crate::corpus::CorpusId;
|
use crate::corpus::CorpusId;
|
||||||
|
|
||||||
@ -198,36 +197,44 @@ pub trait HasMutatorBytes: HasLen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mapping types to themselves, used to ensure lifetime consistency for mapped mutators.
|
impl HasMutatorBytes for Vec<u8> {
|
||||||
///
|
fn bytes(&self) -> &[u8] {
|
||||||
/// Specifically, this is for [`Input`] types that are owned wrappers around a reference. The lifetime of the associated type should be the same as the reference.
|
self.as_ref()
|
||||||
pub trait MappedInput {
|
|
||||||
/// The type for which this trait is implemented
|
|
||||||
type Type<'a>
|
|
||||||
where
|
|
||||||
Self: 'a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> MappedInput for Option<T>
|
fn bytes_mut(&mut self) -> &mut [u8] {
|
||||||
|
self.as_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(&mut self, new_len: usize, value: u8) {
|
||||||
|
<Vec<u8>>::resize(self, new_len, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend<'a, I: IntoIterator<Item = &'a u8>>(&mut self, iter: I) {
|
||||||
|
<Vec<u8> as Extend<I::Item>>::extend(self, iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter>
|
||||||
where
|
where
|
||||||
T: MappedInput,
|
R: RangeBounds<usize>,
|
||||||
|
I: IntoIterator<Item = u8>,
|
||||||
{
|
{
|
||||||
type Type<'a>
|
<Vec<u8>>::splice(self, range, replace_with)
|
||||||
= Option<T::Type<'a>>
|
}
|
||||||
|
|
||||||
|
fn drain<R>(&mut self, range: R) -> Drain<'_, u8>
|
||||||
where
|
where
|
||||||
T: 'a;
|
R: RangeBounds<usize>,
|
||||||
|
{
|
||||||
|
<Vec<u8>>::drain(self, range)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper type that allows us to use mutators for Mutators for `&mut `[`Vec`].
|
/// A wrapper type that allows us to use mutators for Mutators for `&mut `[`Vec`].
|
||||||
pub type MutVecInput<'a> = ValueMutRefInput<'a, Vec<u8>>;
|
#[deprecated(since = "0.15.0", note = "Use &mut Vec<u8> directly")]
|
||||||
|
pub type MutVecInput<'a> = &'a mut Vec<u8>;
|
||||||
|
|
||||||
impl HasLen for MutVecInput<'_> {
|
impl HasMutatorBytes for &mut Vec<u8> {
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.deref().len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasMutatorBytes for MutVecInput<'_> {
|
|
||||||
fn bytes(&self) -> &[u8] {
|
fn bytes(&self) -> &[u8] {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -241,7 +248,7 @@ impl HasMutatorBytes for MutVecInput<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn extend<'b, I: IntoIterator<Item = &'b u8>>(&mut self, iter: I) {
|
fn extend<'b, I: IntoIterator<Item = &'b u8>>(&mut self, iter: I) {
|
||||||
self.deref_mut().extend(iter);
|
<Vec<u8> as Extend<I::Item>>::extend(self, iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter>
|
fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter>
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
//! Newtype pattern style wrapper for [`super::Input`]s
|
//! Newtype pattern style wrapper for [`super::Input`]s
|
||||||
|
|
||||||
use alloc::{string::String, vec::Vec};
|
use alloc::{string::String, vec::Vec};
|
||||||
use core::{
|
use core::{fmt::Debug, hash::Hash};
|
||||||
fmt::Debug,
|
|
||||||
hash::Hash,
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
};
|
|
||||||
|
|
||||||
use libafl_bolts::{generic_hash_std, rands::Rand};
|
use libafl_bolts::{generic_hash_std, rands::Rand};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -15,7 +11,7 @@ use {
|
|||||||
std::{fs::File, io::Read, path::Path},
|
std::{fs::File, io::Read, path::Path},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Input, MappedInput};
|
use super::Input;
|
||||||
use crate::{corpus::CorpusId, mutators::numeric::Numeric};
|
use crate::{corpus::CorpusId, mutators::numeric::Numeric};
|
||||||
|
|
||||||
/// Newtype pattern wrapper around an underlying structure to implement inputs
|
/// Newtype pattern wrapper around an underlying structure to implement inputs
|
||||||
@ -146,104 +142,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Input type that holds a mutable reference to an inner value
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub struct ValueMutRefInput<'a, I>(&'a mut I);
|
|
||||||
|
|
||||||
// Macro to implement the `Input` trait and create type aliases for `WrappingInput<T>`
|
|
||||||
macro_rules! impl_input_for_value_mut_ref_input {
|
|
||||||
($($t:ty => $name:ident),+ $(,)?) => {
|
|
||||||
$( /// Input wrapping a <$t>
|
|
||||||
pub type $name<'a> = ValueMutRefInput<'a, $t>;
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke the macro with type-name pairs
|
|
||||||
impl_input_for_value_mut_ref_input!(
|
|
||||||
u8 => MutU8Input,
|
|
||||||
u16 => MutU16Input,
|
|
||||||
u32 => MutU32Input,
|
|
||||||
u64 => MutU64Input,
|
|
||||||
u128 => MutU128Input,
|
|
||||||
usize => MutUsizeInput,
|
|
||||||
i8 => MutI8Input,
|
|
||||||
i16 => MutI16Input,
|
|
||||||
i32 => MutI32Input,
|
|
||||||
i64 => MutI64Input,
|
|
||||||
i128 => MutI128Input,
|
|
||||||
isize => MutIsizeInput,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<I> Deref for ValueMutRefInput<'_, I> {
|
|
||||||
type Target = I;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I> DerefMut for ValueMutRefInput<'_, I> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, I> From<&'a mut I> for ValueMutRefInput<'a, I> {
|
|
||||||
fn from(value: &'a mut I) -> Self {
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, I> From<&'a mut ValueInput<I>> for ValueMutRefInput<'a, I> {
|
|
||||||
fn from(value: &'a mut ValueInput<I>) -> Self {
|
|
||||||
Self(value.as_mut())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I> MappedInput for ValueMutRefInput<'_, I> {
|
|
||||||
type Type<'a>
|
|
||||||
= ValueMutRefInput<'a, I>
|
|
||||||
where
|
|
||||||
Self: 'a;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I> Numeric for ValueMutRefInput<'_, I>
|
|
||||||
where
|
|
||||||
I: Numeric,
|
|
||||||
{
|
|
||||||
fn flip_all_bits(&mut self) {
|
|
||||||
self.deref_mut().flip_all_bits();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flip_bit_at(&mut self, rhs: usize) {
|
|
||||||
self.deref_mut().flip_bit_at(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wrapping_inc(&mut self) {
|
|
||||||
self.deref_mut().wrapping_inc();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wrapping_dec(&mut self) {
|
|
||||||
self.deref_mut().wrapping_dec();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn twos_complement(&mut self) {
|
|
||||||
self.deref_mut().twos_complement();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn randomize<R: Rand>(&mut self, rand: &mut R) {
|
|
||||||
self.deref_mut().randomize(rand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use {
|
use {
|
||||||
super::{ValueInput, ValueMutRefInput},
|
super::ValueInput, crate::mutators::numeric::Numeric, alloc::fmt::Debug,
|
||||||
crate::mutators::numeric::Numeric,
|
|
||||||
alloc::fmt::Debug,
|
|
||||||
std::any::type_name,
|
std::any::type_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -291,6 +194,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[expect(unused_mut)]
|
||||||
fn take_numeric<I: Numeric + Clone + PartialEq + Debug>(i: &I, check_twos_complement: bool) {
|
fn take_numeric<I: Numeric + Clone + PartialEq + Debug>(i: &I, check_twos_complement: bool) {
|
||||||
apply_all_ops!({}, i.clone(), I, check_twos_complement);
|
apply_all_ops!({}, i.clone(), I, check_twos_complement);
|
||||||
apply_all_ops!(
|
apply_all_ops!(
|
||||||
@ -301,8 +205,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
apply_all_ops!(
|
apply_all_ops!(
|
||||||
let mut i_clone = i.clone(),
|
let mut i_clone = i.clone(),
|
||||||
ValueMutRefInput::from(&mut i_clone),
|
&mut i_clone,
|
||||||
ValueMutRefInput<'_, I>,
|
&mut I,
|
||||||
check_twos_complement
|
check_twos_complement
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,9 @@
|
|||||||
use libafl_bolts::tuples::{Map, Merge};
|
use libafl_bolts::tuples::{Map, Merge};
|
||||||
use tuple_list::{tuple_list, tuple_list_type};
|
use tuple_list::{tuple_list, tuple_list_type};
|
||||||
|
|
||||||
|
use super::{MappingMutator, ToMappingMutator};
|
||||||
use crate::mutators::{
|
use crate::mutators::{
|
||||||
mapping::{
|
mapping::{OptionalMutator, ToOptionalMutator},
|
||||||
MappedInputFunctionMappingMutator, OptionMappingMutator,
|
|
||||||
ToMappedInputFunctionMappingMutatorMapper, ToOptionMappingMutatorMapper,
|
|
||||||
},
|
|
||||||
mutations::{
|
mutations::{
|
||||||
BitFlipMutator, ByteAddMutator, ByteDecMutator, ByteFlipMutator, ByteIncMutator,
|
BitFlipMutator, ByteAddMutator, ByteDecMutator, ByteFlipMutator, ByteIncMutator,
|
||||||
ByteInterestingMutator, ByteNegMutator, ByteRandMutator, BytesCopyMutator,
|
ByteInterestingMutator, ByteNegMutator, ByteRandMutator, BytesCopyMutator,
|
||||||
@ -89,73 +87,65 @@ pub type HavocMutationsType = tuple_list_type!(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// Tuple type of the mutations that compose the Havoc mutator for mapped input types
|
/// Tuple type of the mutations that compose the Havoc mutator for mapped input types
|
||||||
pub type MappedHavocMutationsType<F1, F2, II, O> = tuple_list_type!(
|
pub type MappedHavocMutationsType<F1, F2, O> = tuple_list_type!(
|
||||||
MappedInputFunctionMappingMutator<BitFlipMutator, F1, II>,
|
MappingMutator<BitFlipMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<ByteFlipMutator, F1, II>,
|
MappingMutator<ByteFlipMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<ByteIncMutator, F1, II>,
|
MappingMutator<ByteIncMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<ByteDecMutator, F1, II>,
|
MappingMutator<ByteDecMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<ByteNegMutator, F1, II>,
|
MappingMutator<ByteNegMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<ByteRandMutator, F1, II>,
|
MappingMutator<ByteRandMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<ByteAddMutator, F1, II>,
|
MappingMutator<ByteAddMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<WordAddMutator, F1, II>,
|
MappingMutator<WordAddMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<DwordAddMutator, F1, II>,
|
MappingMutator<DwordAddMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<QwordAddMutator, F1, II>,
|
MappingMutator<QwordAddMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<ByteInterestingMutator, F1, II>,
|
MappingMutator<ByteInterestingMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<WordInterestingMutator, F1, II>,
|
MappingMutator<WordInterestingMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<DwordInterestingMutator, F1, II>,
|
MappingMutator<DwordInterestingMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
|
MappingMutator<BytesDeleteMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
|
MappingMutator<BytesDeleteMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
|
MappingMutator<BytesDeleteMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
|
MappingMutator<BytesDeleteMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesExpandMutator, F1, II>,
|
MappingMutator<BytesExpandMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesInsertMutator, F1, II>,
|
MappingMutator<BytesInsertMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesRandInsertMutator, F1, II>,
|
MappingMutator<BytesRandInsertMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesSetMutator, F1, II>,
|
MappingMutator<BytesSetMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesRandSetMutator, F1, II>,
|
MappingMutator<BytesRandSetMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesCopyMutator, F1, II>,
|
MappingMutator<BytesCopyMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesInsertCopyMutator, F1, II>,
|
MappingMutator<BytesInsertCopyMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<BytesSwapMutator, F1, II>,
|
MappingMutator<BytesSwapMutator, F1>,
|
||||||
MappedInputFunctionMappingMutator<MappedCrossoverInsertMutator<F2, O>, F1, II>,
|
MappingMutator<MappedCrossoverInsertMutator<F2, O>, F1>,
|
||||||
MappedInputFunctionMappingMutator<MappedCrossoverReplaceMutator<F2, O>, F1, II>,
|
MappingMutator<MappedCrossoverReplaceMutator<F2, O>, F1>,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Tuple type of the mutations that compose the Havoc mutator for mapped input types, for optional byte array input parts
|
/// Tuple type of the mutations that compose the Havoc mutator for mapped input types, for optional byte array input parts
|
||||||
pub type OptionMappedHavocMutationsType<F1, F2, II, O> = tuple_list_type!(
|
pub type OptionMappedHavocMutationsType<F1, F2, O> = tuple_list_type!(
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BitFlipMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BitFlipMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteFlipMutator>, F1, II>,
|
MappingMutator<OptionalMutator<ByteFlipMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteIncMutator>, F1, II>,
|
MappingMutator<OptionalMutator<ByteIncMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteDecMutator>, F1, II>,
|
MappingMutator<OptionalMutator<ByteDecMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteNegMutator>, F1, II>,
|
MappingMutator<OptionalMutator<ByteNegMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteRandMutator>, F1, II>,
|
MappingMutator<OptionalMutator<ByteRandMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteAddMutator>, F1, II>,
|
MappingMutator<OptionalMutator<ByteAddMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<WordAddMutator>, F1, II>,
|
MappingMutator<OptionalMutator<WordAddMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<DwordAddMutator>, F1, II>,
|
MappingMutator<OptionalMutator<DwordAddMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<QwordAddMutator>, F1, II>,
|
MappingMutator<OptionalMutator<QwordAddMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteInterestingMutator>, F1, II>,
|
MappingMutator<OptionalMutator<ByteInterestingMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<WordInterestingMutator>, F1, II>,
|
MappingMutator<OptionalMutator<WordInterestingMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<DwordInterestingMutator>, F1, II>,
|
MappingMutator<OptionalMutator<DwordInterestingMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesDeleteMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesDeleteMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesDeleteMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesDeleteMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesExpandMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesExpandMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesInsertMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesInsertMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesRandInsertMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesRandInsertMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesSetMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesSetMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesRandSetMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesRandSetMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesCopyMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesCopyMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesInsertCopyMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesInsertCopyMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesSwapMutator>, F1, II>,
|
MappingMutator<OptionalMutator<BytesSwapMutator>, F1>,
|
||||||
MappedInputFunctionMappingMutator<
|
MappingMutator<OptionalMutator<MappedCrossoverInsertMutator<F2, O>>, F1>,
|
||||||
OptionMappingMutator<MappedCrossoverInsertMutator<F2, O>>,
|
MappingMutator<OptionalMutator<MappedCrossoverReplaceMutator<F2, O>>, F1>,
|
||||||
F1,
|
|
||||||
II,
|
|
||||||
>,
|
|
||||||
MappedInputFunctionMappingMutator<
|
|
||||||
OptionMappingMutator<MappedCrossoverReplaceMutator<F2, O>>,
|
|
||||||
F1,
|
|
||||||
II,
|
|
||||||
>,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Get the mutations that compose the Havoc mutator (only applied to single inputs)
|
/// Get the mutations that compose the Havoc mutator (only applied to single inputs)
|
||||||
@ -204,7 +194,7 @@ pub fn havoc_crossover_with_corpus_mapper<F, IO, O>(
|
|||||||
input_mapper: F,
|
input_mapper: F,
|
||||||
) -> MappedHavocCrossoverType<F, O>
|
) -> MappedHavocCrossoverType<F, O>
|
||||||
where
|
where
|
||||||
F: Clone + Fn(IO) -> O,
|
F: Clone + Fn(&IO) -> &O,
|
||||||
{
|
{
|
||||||
tuple_list!(
|
tuple_list!(
|
||||||
MappedCrossoverInsertMutator::new(input_mapper.clone()),
|
MappedCrossoverInsertMutator::new(input_mapper.clone()),
|
||||||
@ -238,16 +228,14 @@ pub fn havoc_mutations() -> HavocMutationsType {
|
|||||||
pub fn mapped_havoc_mutations<F1, F2, IO1, IO2, II, O>(
|
pub fn mapped_havoc_mutations<F1, F2, IO1, IO2, II, O>(
|
||||||
current_input_mapper: F1,
|
current_input_mapper: F1,
|
||||||
input_from_corpus_mapper: F2,
|
input_from_corpus_mapper: F2,
|
||||||
) -> MappedHavocMutationsType<F1, F2, II, O>
|
) -> MappedHavocMutationsType<F1, F2, O>
|
||||||
where
|
where
|
||||||
F1: Clone + FnMut(IO1) -> II,
|
F1: Clone + FnMut(&mut IO1) -> &mut II,
|
||||||
F2: Clone + Fn(IO2) -> O,
|
F2: Clone + Fn(&IO2) -> &O,
|
||||||
{
|
{
|
||||||
havoc_mutations_no_crossover()
|
havoc_mutations_no_crossover()
|
||||||
.merge(havoc_crossover_with_corpus_mapper(input_from_corpus_mapper))
|
.merge(havoc_crossover_with_corpus_mapper(input_from_corpus_mapper))
|
||||||
.map(ToMappedInputFunctionMappingMutatorMapper::new(
|
.map(ToMappingMutator::new(current_input_mapper))
|
||||||
current_input_mapper,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the mutations that compose the Havoc mutator for mapped input types, for optional input parts
|
/// Get the mutations that compose the Havoc mutator for mapped input types, for optional input parts
|
||||||
@ -257,17 +245,15 @@ where
|
|||||||
pub fn optional_mapped_havoc_mutations<F1, F2, IO1, IO2, II, O>(
|
pub fn optional_mapped_havoc_mutations<F1, F2, IO1, IO2, II, O>(
|
||||||
current_input_mapper: F1,
|
current_input_mapper: F1,
|
||||||
input_from_corpus_mapper: F2,
|
input_from_corpus_mapper: F2,
|
||||||
) -> OptionMappedHavocMutationsType<F1, F2, II, O>
|
) -> OptionMappedHavocMutationsType<F1, F2, O>
|
||||||
where
|
where
|
||||||
F1: Clone + FnMut(IO1) -> II,
|
F1: Clone + FnMut(&mut IO1) -> &mut II,
|
||||||
F2: Clone + Fn(IO2) -> O,
|
F2: Clone + Fn(&IO2) -> &O,
|
||||||
{
|
{
|
||||||
havoc_mutations_no_crossover()
|
havoc_mutations_no_crossover()
|
||||||
.merge(havoc_crossover_with_corpus_mapper_optional(
|
.merge(havoc_crossover_with_corpus_mapper_optional(
|
||||||
input_from_corpus_mapper,
|
input_from_corpus_mapper,
|
||||||
))
|
))
|
||||||
.map(ToOptionMappingMutatorMapper)
|
.map(ToOptionalMutator)
|
||||||
.map(ToMappedInputFunctionMappingMutatorMapper::new(
|
.map(ToMappingMutator::new(current_input_mapper))
|
||||||
current_input_mapper,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
//! Allowing mixing and matching between [`Mutator`] and [`crate::inputs::Input`] types.
|
//! Allowing mixing and matching between [`Mutator`] and [`crate::inputs::Input`] types.
|
||||||
use alloc::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
use core::marker::PhantomData;
|
|
||||||
|
|
||||||
use libafl_bolts::{tuples::MappingFunctor, Named};
|
use libafl_bolts::{tuples::MappingFunctor, Named};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
inputs::MappedInput,
|
|
||||||
mutators::{MutationResult, Mutator},
|
mutators::{MutationResult, Mutator},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -20,49 +18,45 @@ use crate::{
|
|||||||
/// use std::vec::Vec;
|
/// use std::vec::Vec;
|
||||||
///
|
///
|
||||||
/// use libafl::{
|
/// use libafl::{
|
||||||
/// inputs::MutVecInput,
|
/// mutators::{ByteIncMutator, MappingMutator, MutationResult, Mutator},
|
||||||
/// mutators::{
|
|
||||||
/// ByteIncMutator, FunctionMappingMutator, MappedInputFunctionMappingMutator,
|
|
||||||
/// MutationResult, Mutator,
|
|
||||||
/// },
|
|
||||||
/// state::NopState,
|
/// state::NopState,
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// type CustomInput = (Vec<u8>,);
|
/// #[derive(Debug, PartialEq)]
|
||||||
/// fn extract_to_ref(input: &mut CustomInput) -> &mut Vec<u8> {
|
/// struct CustomInput(Vec<u8>);
|
||||||
/// &mut input.0
|
///
|
||||||
|
/// impl CustomInput {
|
||||||
|
/// pub fn vec_mut(&mut self) -> &mut Vec<u8> {
|
||||||
|
/// &mut self.0
|
||||||
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn extract_from_ref(input: &mut Vec<u8>) -> MutVecInput<'_> {
|
/// // construct a mutator that works on &mut Vec<u8> (since it impls `HasMutatorBytes`)
|
||||||
/// input.into()
|
/// let inner = ByteIncMutator::new();
|
||||||
/// }
|
/// // construct a mutator that works on &mut CustomInput
|
||||||
|
/// let mut outer = MappingMutator::new(CustomInput::vec_mut, inner);
|
||||||
///
|
///
|
||||||
/// // construct a mapper that works on &mut Vec<u8>
|
/// let mut input = CustomInput(vec![1]);
|
||||||
/// let inner: MappedInputFunctionMappingMutator<_, _, MutVecInput<'_>> =
|
|
||||||
/// MappedInputFunctionMappingMutator::new(extract_from_ref, ByteIncMutator::new());
|
|
||||||
/// let mut outer = FunctionMappingMutator::new(extract_to_ref, inner);
|
|
||||||
///
|
|
||||||
/// let mut input: CustomInput = (vec![1],);
|
|
||||||
///
|
///
|
||||||
/// let mut state: NopState<CustomInput> = NopState::new();
|
/// let mut state: NopState<CustomInput> = NopState::new();
|
||||||
/// let res = outer.mutate(&mut state, &mut input).unwrap();
|
/// let res = outer.mutate(&mut state, &mut input).unwrap();
|
||||||
/// assert_eq!(res, MutationResult::Mutated);
|
/// assert_eq!(res, MutationResult::Mutated);
|
||||||
/// assert_eq!(input, (vec![2],));
|
/// assert_eq!(input, CustomInput(vec![2],));
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionMappingMutator<M, F> {
|
pub struct MappingMutator<M, F> {
|
||||||
mapper: F,
|
mapper: F,
|
||||||
inner: M,
|
inner: M,
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, F> FunctionMappingMutator<M, F> {
|
impl<M, F> MappingMutator<M, F> {
|
||||||
/// Creates a new [`FunctionMappingMutator`]
|
/// Creates a new [`MappingMutator`]
|
||||||
pub fn new(mapper: F, inner: M) -> Self
|
pub fn new(mapper: F, inner: M) -> Self
|
||||||
where
|
where
|
||||||
M: Named,
|
M: Named,
|
||||||
{
|
{
|
||||||
let name = Cow::Owned(format!("FunctionMappingMutator<{}>", inner.name()));
|
let name = Cow::Owned(format!("MappingMutator<{}>", inner.name()));
|
||||||
Self {
|
Self {
|
||||||
mapper,
|
mapper,
|
||||||
inner,
|
inner,
|
||||||
@ -71,9 +65,9 @@ impl<M, F> FunctionMappingMutator<M, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, S, F, IO, II> Mutator<IO, S> for FunctionMappingMutator<M, F>
|
impl<M, S, F, IO, II> Mutator<IO, S> for MappingMutator<M, F>
|
||||||
where
|
where
|
||||||
F: for<'a> FnMut(&'a mut IO) -> &'a mut II,
|
F: FnMut(&mut IO) -> &mut II,
|
||||||
M: Mutator<II, S>,
|
M: Mutator<II, S>,
|
||||||
{
|
{
|
||||||
fn mutate(&mut self, state: &mut S, input: &mut IO) -> Result<MutationResult, Error> {
|
fn mutate(&mut self, state: &mut S, input: &mut IO) -> Result<MutationResult, Error> {
|
||||||
@ -81,15 +75,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, F> Named for FunctionMappingMutator<M, F> {
|
impl<M, F> Named for MappingMutator<M, F> {
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mapper to use to map a [`tuple_list`] of [`Mutator`]s using [`ToFunctionMappingMutatorMapper`]s.
|
/// Mapper to use to map a [`tuple_list`] of [`Mutator`]s using [`ToMappingMutator`]s.
|
||||||
///
|
///
|
||||||
/// See the explanation of [`ToFunctionMappingMutatorMapper`] for details.
|
/// See the explanation of [`MappingMutator`] for details.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
#[cfg_attr(feature = "std", doc = " ```")]
|
#[cfg_attr(feature = "std", doc = " ```")]
|
||||||
@ -97,207 +91,57 @@ impl<M, F> Named for FunctionMappingMutator<M, F> {
|
|||||||
/// use std::vec::Vec;
|
/// use std::vec::Vec;
|
||||||
///
|
///
|
||||||
/// use libafl::{
|
/// use libafl::{
|
||||||
/// inputs::MutVecInput,
|
|
||||||
/// mutators::{
|
/// mutators::{
|
||||||
/// ByteIncMutator, MappedInputFunctionMappingMutator, MutationResult, Mutator,
|
/// ByteIncMutator, MutationResult, MutatorsTuple, ToMappingMutator,
|
||||||
/// ToFunctionMappingMutatorMapper,
|
|
||||||
/// },
|
/// },
|
||||||
/// state::NopState,
|
/// state::NopState,
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// use libafl_bolts::tuples::{tuple_list, Map};
|
/// use libafl_bolts::tuples::{tuple_list, Map};
|
||||||
///
|
///
|
||||||
/// type CustomInput = (Vec<u8>,);
|
/// #[derive(Debug, PartialEq)]
|
||||||
/// fn extract_to_ref(input: &mut CustomInput) -> &mut Vec<u8> {
|
/// struct CustomInput(Vec<u8>);
|
||||||
/// &mut input.0
|
///
|
||||||
|
/// impl CustomInput {
|
||||||
|
/// pub fn vec_mut(&mut self) -> &mut Vec<u8> {
|
||||||
|
/// &mut self.0
|
||||||
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn extract_from_ref(input: &mut Vec<u8>) -> MutVecInput<'_> {
|
/// // construct a mutator that works on &mut Vec<u8> (since it impls `HasMutatorBytes`)
|
||||||
/// input.into()
|
/// let mutators = tuple_list!(ByteIncMutator::new(), ByteIncMutator::new());
|
||||||
/// }
|
/// // construct a mutator that works on &mut CustomInput
|
||||||
|
/// let mut mapped_mutators =
|
||||||
|
/// mutators.map(ToMappingMutator::new(CustomInput::vec_mut));
|
||||||
///
|
///
|
||||||
/// // construct a mapper that works on &mut Vec<u8>
|
/// let mut input = CustomInput(vec![1]);
|
||||||
/// let inner: MappedInputFunctionMappingMutator<_, _, MutVecInput<'_>> =
|
|
||||||
/// MappedInputFunctionMappingMutator::new(extract_from_ref, ByteIncMutator::new());
|
|
||||||
/// let inner_list = tuple_list!(inner);
|
|
||||||
/// let outer_list = inner_list.map(ToFunctionMappingMutatorMapper::new(extract_to_ref));
|
|
||||||
/// let mut outer = outer_list.0;
|
|
||||||
///
|
|
||||||
/// let mut input: CustomInput = (vec![1],);
|
|
||||||
///
|
///
|
||||||
/// let mut state: NopState<CustomInput> = NopState::new();
|
/// let mut state: NopState<CustomInput> = NopState::new();
|
||||||
/// let res = outer.mutate(&mut state, &mut input).unwrap();
|
/// let res = mapped_mutators.mutate_all(&mut state, &mut input).unwrap();
|
||||||
/// assert_eq!(res, MutationResult::Mutated);
|
/// assert_eq!(res, MutationResult::Mutated);
|
||||||
/// assert_eq!(input, (vec![2],));
|
/// assert_eq!(input, CustomInput(vec![3],));
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ToFunctionMappingMutatorMapper<F> {
|
pub struct ToMappingMutator<F> {
|
||||||
mapper: F,
|
mapper: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> ToFunctionMappingMutatorMapper<F> {
|
impl<F> ToMappingMutator<F> {
|
||||||
/// Creates a new [`ToFunctionMappingMutatorMapper`]
|
/// Creates a new [`ToMappingMutator`]
|
||||||
pub fn new(mapper: F) -> Self {
|
pub fn new(mapper: F) -> Self {
|
||||||
Self { mapper }
|
Self { mapper }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, F> MappingFunctor<M> for ToFunctionMappingMutatorMapper<F>
|
impl<M, F> MappingFunctor<M> for ToMappingMutator<F>
|
||||||
where
|
where
|
||||||
F: Clone,
|
F: Clone,
|
||||||
M: Named,
|
M: Named,
|
||||||
{
|
{
|
||||||
type Output = FunctionMappingMutator<M, F>;
|
type Output = MappingMutator<M, F>;
|
||||||
|
|
||||||
fn apply(&mut self, from: M) -> Self::Output {
|
fn apply(&mut self, from: M) -> Self::Output {
|
||||||
FunctionMappingMutator::new(self.mapper.clone(), from)
|
MappingMutator::new(self.mapper.clone(), from)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mapping [`Mutator`] using a function returning a wrapped reference (see [`MappedInput`]).
|
|
||||||
///
|
|
||||||
/// Allows using [`Mutator`]s for a certain type on (parts of) other input types that can be mapped to this type.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
#[cfg_attr(feature = "std", doc = " ```")]
|
|
||||||
#[cfg_attr(not(feature = "std"), doc = " ```ignore")]
|
|
||||||
/// use std::vec::Vec;
|
|
||||||
///
|
|
||||||
/// use libafl::{
|
|
||||||
/// inputs::MutVecInput,
|
|
||||||
/// mutators::{
|
|
||||||
/// ByteIncMutator, MappedInputFunctionMappingMutator, MutationResult, Mutator,
|
|
||||||
/// },
|
|
||||||
/// state::NopState,
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// type CustomInput = (Vec<u8>,);
|
|
||||||
/// fn extract(input: &mut CustomInput) -> MutVecInput<'_> {
|
|
||||||
/// (&mut input.0).into()
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let inner = ByteIncMutator::new();
|
|
||||||
/// let mut outer: MappedInputFunctionMappingMutator<_, _, MutVecInput<'_>> =
|
|
||||||
/// MappedInputFunctionMappingMutator::new(extract, inner);
|
|
||||||
///
|
|
||||||
/// let mut input: CustomInput = (vec![1],);
|
|
||||||
///
|
|
||||||
/// let mut state: NopState<CustomInput> = NopState::new();
|
|
||||||
/// let res = outer.mutate(&mut state, &mut input).unwrap();
|
|
||||||
/// assert_eq!(res, MutationResult::Mutated);
|
|
||||||
/// assert_eq!(input, (vec![2],));
|
|
||||||
/// ```
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct MappedInputFunctionMappingMutator<M, F, II> {
|
|
||||||
mapper: F,
|
|
||||||
inner: M,
|
|
||||||
name: Cow<'static, str>,
|
|
||||||
phantom: PhantomData<II>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M, F, II> MappedInputFunctionMappingMutator<M, F, II> {
|
|
||||||
/// Creates a new [`MappedInputFunctionMappingMutator`]
|
|
||||||
pub fn new(mapper: F, inner: M) -> Self
|
|
||||||
where
|
|
||||||
M: Named,
|
|
||||||
{
|
|
||||||
let name = Cow::Owned(format!(
|
|
||||||
"MappedInputFunctionMappingMutator<{}>",
|
|
||||||
inner.name()
|
|
||||||
));
|
|
||||||
|
|
||||||
Self {
|
|
||||||
mapper,
|
|
||||||
inner,
|
|
||||||
name,
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M, S, F, IO, II> Mutator<IO, S> for MappedInputFunctionMappingMutator<M, F, II>
|
|
||||||
where
|
|
||||||
for<'a> M: Mutator<II::Type<'a>, S>,
|
|
||||||
for<'a> II: MappedInput + 'a,
|
|
||||||
for<'a> F: FnMut(&'a mut IO) -> II::Type<'a>,
|
|
||||||
{
|
|
||||||
fn mutate(&mut self, state: &mut S, input: &mut IO) -> Result<MutationResult, Error> {
|
|
||||||
let mapped = &mut (self.mapper)(input);
|
|
||||||
self.inner.mutate(state, mapped)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M, F, II> Named for MappedInputFunctionMappingMutator<M, F, II> {
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mapper to use to map a [`tuple_list`] of [`Mutator`]s using [`MappedInputFunctionMappingMutator`]s.
|
|
||||||
///
|
|
||||||
/// See the explanation of [`MappedInputFunctionMappingMutator`] for details.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
#[cfg_attr(feature = "std", doc = " ```")]
|
|
||||||
#[cfg_attr(not(feature = "std"), doc = " ```ignore")]
|
|
||||||
/// use std::vec::Vec;
|
|
||||||
///
|
|
||||||
/// use libafl::{
|
|
||||||
/// inputs::MutVecInput,
|
|
||||||
/// mutators::{
|
|
||||||
/// ByteIncMutator, MappedInputFunctionMappingMutator, MutationResult, Mutator,
|
|
||||||
/// ToMappedInputFunctionMappingMutatorMapper,
|
|
||||||
/// },
|
|
||||||
/// state::NopState,
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// use libafl_bolts::tuples::{tuple_list, Map};
|
|
||||||
///
|
|
||||||
/// type CustomInput = (Vec<u8>,);
|
|
||||||
/// fn extract(input: &mut CustomInput) -> MutVecInput<'_> {
|
|
||||||
/// (&mut input.0).into()
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// let inner = tuple_list!(ByteIncMutator::new());
|
|
||||||
/// let outer_list: (MappedInputFunctionMappingMutator<_, _, MutVecInput<'_>>, _) =
|
|
||||||
/// inner.map(ToMappedInputFunctionMappingMutatorMapper::new(extract));
|
|
||||||
/// let mut outer = outer_list.0;
|
|
||||||
///
|
|
||||||
/// let mut input: CustomInput = (vec![1],);
|
|
||||||
///
|
|
||||||
/// let mut state: NopState<CustomInput> = NopState::new();
|
|
||||||
/// let res = outer.mutate(&mut state, &mut input).unwrap();
|
|
||||||
/// assert_eq!(res, MutationResult::Mutated);
|
|
||||||
/// assert_eq!(input, (vec![2],));
|
|
||||||
/// ```
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ToMappedInputFunctionMappingMutatorMapper<F, II> {
|
|
||||||
mapper: F,
|
|
||||||
phantom: PhantomData<II>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F, II> ToMappedInputFunctionMappingMutatorMapper<F, II> {
|
|
||||||
/// Creates a new [`ToMappedInputFunctionMappingMutatorMapper`]
|
|
||||||
pub fn new<IO>(mapper: F) -> Self
|
|
||||||
where
|
|
||||||
F: FnMut(IO) -> II,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
mapper,
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M, F, II> MappingFunctor<M> for ToMappedInputFunctionMappingMutatorMapper<F, II>
|
|
||||||
where
|
|
||||||
F: Clone,
|
|
||||||
M: Named,
|
|
||||||
{
|
|
||||||
type Output = MappedInputFunctionMappingMutator<M, F, II>;
|
|
||||||
|
|
||||||
fn apply(&mut self, from: M) -> Self::Output {
|
|
||||||
MappedInputFunctionMappingMutator::new(self.mapper.clone(), from)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,12 +156,12 @@ where
|
|||||||
#[cfg_attr(not(feature = "std"), doc = " ```ignore")]
|
#[cfg_attr(not(feature = "std"), doc = " ```ignore")]
|
||||||
/// use libafl::{
|
/// use libafl::{
|
||||||
/// inputs::MutVecInput,
|
/// inputs::MutVecInput,
|
||||||
/// mutators::{ByteIncMutator, MutationResult, Mutator, OptionMappingMutator},
|
/// mutators::{ByteIncMutator, MutationResult, Mutator, OptionalMutator},
|
||||||
/// state::NopState,
|
/// state::NopState,
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// let inner = ByteIncMutator::new();
|
/// let inner = ByteIncMutator::new();
|
||||||
/// let mut outer = OptionMappingMutator::new(inner);
|
/// let mut outer = OptionalMutator::new(inner);
|
||||||
///
|
///
|
||||||
/// let mut input_raw = vec![1];
|
/// let mut input_raw = vec![1];
|
||||||
/// let input: MutVecInput = (&mut input_raw).into();
|
/// let input: MutVecInput = (&mut input_raw).into();
|
||||||
@ -332,23 +176,23 @@ where
|
|||||||
/// assert_eq!(res2, MutationResult::Skipped);
|
/// assert_eq!(res2, MutationResult::Skipped);
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OptionMappingMutator<M> {
|
pub struct OptionalMutator<M> {
|
||||||
inner: M,
|
inner: M,
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> OptionMappingMutator<M> {
|
impl<M> OptionalMutator<M> {
|
||||||
/// Creates a new [`OptionMappingMutator`]
|
/// Creates a new [`OptionalMutator`]
|
||||||
pub fn new(inner: M) -> Self
|
pub fn new(inner: M) -> Self
|
||||||
where
|
where
|
||||||
M: Named,
|
M: Named,
|
||||||
{
|
{
|
||||||
let name = Cow::Owned(format!("OptionMappingMutator<{}>", inner.name()));
|
let name = Cow::Owned(format!("OptionalMutator<{}>", inner.name()));
|
||||||
Self { inner, name }
|
Self { inner, name }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, S, M> Mutator<Option<I>, S> for OptionMappingMutator<M>
|
impl<I, S, M> Mutator<Option<I>, S> for OptionalMutator<M>
|
||||||
where
|
where
|
||||||
M: Mutator<I, S>,
|
M: Mutator<I, S>,
|
||||||
{
|
{
|
||||||
@ -360,7 +204,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> Named for OptionMappingMutator<M>
|
impl<M> Named for OptionalMutator<M>
|
||||||
where
|
where
|
||||||
M: Named,
|
M: Named,
|
||||||
{
|
{
|
||||||
@ -369,22 +213,22 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mapper to use to map a [`tuple_list`] of [`Mutator`]s using [`OptionMappingMutator`]s.
|
/// Mapper to use to map a [`tuple_list`] of [`Mutator`]s using [`OptionalMutator`]s.
|
||||||
///
|
///
|
||||||
/// See the explanation of [`OptionMappingMutator`] for details.
|
/// See the explanation of [`OptionalMutator`] for details.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
#[cfg_attr(feature = "std", doc = " ```")]
|
#[cfg_attr(feature = "std", doc = " ```")]
|
||||||
#[cfg_attr(not(feature = "std"), doc = " ```ignore")]
|
#[cfg_attr(not(feature = "std"), doc = " ```ignore")]
|
||||||
/// use libafl::{
|
/// use libafl::{
|
||||||
/// inputs::MutVecInput,
|
/// inputs::MutVecInput,
|
||||||
/// mutators::{ByteIncMutator, MutationResult, Mutator, ToOptionMappingMutatorMapper},
|
/// mutators::{ByteIncMutator, MutationResult, Mutator, ToOptionalMutator},
|
||||||
/// state::NopState,
|
/// state::NopState,
|
||||||
/// };
|
/// };
|
||||||
/// use libafl_bolts::tuples::{tuple_list, Map};
|
/// use libafl_bolts::tuples::{tuple_list, Map};
|
||||||
///
|
///
|
||||||
/// let inner = tuple_list!(ByteIncMutator::new());
|
/// let inner = tuple_list!(ByteIncMutator::new());
|
||||||
/// let outer_list = inner.map(ToOptionMappingMutatorMapper);
|
/// let outer_list = inner.map(ToOptionalMutator);
|
||||||
/// let mut outer = outer_list.0;
|
/// let mut outer = outer_list.0;
|
||||||
///
|
///
|
||||||
/// let mut input_raw = vec![1];
|
/// let mut input_raw = vec![1];
|
||||||
@ -400,15 +244,15 @@ where
|
|||||||
/// assert_eq!(res2, MutationResult::Skipped);
|
/// assert_eq!(res2, MutationResult::Skipped);
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ToOptionMappingMutatorMapper;
|
pub struct ToOptionalMutator;
|
||||||
|
|
||||||
impl<M> MappingFunctor<M> for ToOptionMappingMutatorMapper
|
impl<M> MappingFunctor<M> for ToOptionalMutator
|
||||||
where
|
where
|
||||||
M: Named,
|
M: Named,
|
||||||
{
|
{
|
||||||
type Output = OptionMappingMutator<M>;
|
type Output = OptionalMutator<M>;
|
||||||
|
|
||||||
fn apply(&mut self, from: M) -> Self::Output {
|
fn apply(&mut self, from: M) -> Self::Output {
|
||||||
OptionMappingMutator::new(from)
|
OptionalMutator::new(from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1280,32 +1280,18 @@ impl CrossoverReplaceMutator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trait IntoOptionBytes {
|
trait IntoOptionBytes {
|
||||||
type Type<'b>;
|
fn map_to_option_bytes(&self) -> Option<&Vec<u8>>;
|
||||||
|
|
||||||
fn into_option_bytes<'a>(self) -> Option<&'a [u8]>
|
|
||||||
where
|
|
||||||
Self: 'a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoOptionBytes for &[u8] {
|
impl IntoOptionBytes for Vec<u8> {
|
||||||
type Type<'b> = &'b [u8];
|
fn map_to_option_bytes(&self) -> Option<&Vec<u8>> {
|
||||||
|
|
||||||
fn into_option_bytes<'b>(self) -> Option<&'b [u8]>
|
|
||||||
where
|
|
||||||
Self: 'b,
|
|
||||||
{
|
|
||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoOptionBytes for Option<&[u8]> {
|
impl IntoOptionBytes for Option<Vec<u8>> {
|
||||||
type Type<'b> = Option<&'b [u8]>;
|
fn map_to_option_bytes(&self) -> Option<&Vec<u8>> {
|
||||||
|
self.as_ref()
|
||||||
fn into_option_bytes<'b>(self) -> Option<&'b [u8]>
|
|
||||||
where
|
|
||||||
Self: 'b,
|
|
||||||
{
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1330,9 +1316,8 @@ impl<S, F, I, O> Mutator<I, S> for MappedCrossoverInsertMutator<F, O>
|
|||||||
where
|
where
|
||||||
S: HasCorpus + HasMaxSize + HasRand,
|
S: HasCorpus + HasMaxSize + HasRand,
|
||||||
I: HasMutatorBytes,
|
I: HasMutatorBytes,
|
||||||
for<'a> O: IntoOptionBytes,
|
O: IntoOptionBytes,
|
||||||
for<'a> O::Type<'a>: IntoOptionBytes,
|
F: Fn(&<S::Corpus as Corpus>::Input) -> &O,
|
||||||
for<'a> F: Fn(&'a <S::Corpus as Corpus>::Input) -> <O as IntoOptionBytes>::Type<'a>,
|
|
||||||
{
|
{
|
||||||
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
|
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
|
||||||
let size = input.bytes().len();
|
let size = input.bytes().len();
|
||||||
@ -1353,8 +1338,8 @@ where
|
|||||||
let other_size = {
|
let other_size = {
|
||||||
let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
|
let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
|
||||||
let other_input = other_testcase.load_input(state.corpus())?;
|
let other_input = other_testcase.load_input(state.corpus())?;
|
||||||
let input_mapped = (self.input_mapper)(other_input).into_option_bytes();
|
let input_mapped = (self.input_mapper)(other_input).map_to_option_bytes();
|
||||||
input_mapped.map_or(0, <[u8]>::len)
|
input_mapped.map_or(0, <Vec<u8>>::len)
|
||||||
};
|
};
|
||||||
|
|
||||||
if other_size < 2 {
|
if other_size < 2 {
|
||||||
@ -1376,7 +1361,7 @@ where
|
|||||||
let other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
|
let other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
|
||||||
// No need to load the input again, it'll still be cached.
|
// No need to load the input again, it'll still be cached.
|
||||||
let other_input = &mut other_testcase.input().as_ref().unwrap();
|
let other_input = &mut other_testcase.input().as_ref().unwrap();
|
||||||
let wrapped_mapped_other_input = (self.input_mapper)(other_input).into_option_bytes();
|
let wrapped_mapped_other_input = (self.input_mapper)(other_input).map_to_option_bytes();
|
||||||
if wrapped_mapped_other_input.is_none() {
|
if wrapped_mapped_other_input.is_none() {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
@ -1421,8 +1406,7 @@ where
|
|||||||
S: HasCorpus + HasMaxSize + HasRand,
|
S: HasCorpus + HasMaxSize + HasRand,
|
||||||
I: HasMutatorBytes,
|
I: HasMutatorBytes,
|
||||||
O: IntoOptionBytes,
|
O: IntoOptionBytes,
|
||||||
for<'a> O::Type<'a>: IntoOptionBytes,
|
F: Fn(&<S::Corpus as Corpus>::Input) -> &O,
|
||||||
for<'a> F: Fn(&'a <S::Corpus as Corpus>::Input) -> <O as IntoOptionBytes>::Type<'a>,
|
|
||||||
{
|
{
|
||||||
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
|
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
|
||||||
let size = input.bytes().len();
|
let size = input.bytes().len();
|
||||||
@ -1441,8 +1425,8 @@ where
|
|||||||
let other_size = {
|
let other_size = {
|
||||||
let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
|
let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
|
||||||
let other_input = other_testcase.load_input(state.corpus())?;
|
let other_input = other_testcase.load_input(state.corpus())?;
|
||||||
let input_mapped = (self.input_mapper)(other_input).into_option_bytes();
|
let input_mapped = (self.input_mapper)(other_input).map_to_option_bytes();
|
||||||
input_mapped.map_or(0, <[u8]>::len)
|
input_mapped.map_or(0, <Vec<u8>>::len)
|
||||||
};
|
};
|
||||||
|
|
||||||
if other_size < 2 {
|
if other_size < 2 {
|
||||||
@ -1464,7 +1448,7 @@ where
|
|||||||
let other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
|
let other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
|
||||||
// No need to load the input again, it'll still be cached.
|
// No need to load the input again, it'll still be cached.
|
||||||
let other_input = &mut other_testcase.input().as_ref().unwrap();
|
let other_input = &mut other_testcase.input().as_ref().unwrap();
|
||||||
let wrapped_mapped_other_input = (self.input_mapper)(other_input).into_option_bytes();
|
let wrapped_mapped_other_input = (self.input_mapper)(other_input).map_to_option_bytes();
|
||||||
if wrapped_mapped_other_input.is_none() {
|
if wrapped_mapped_other_input.is_none() {
|
||||||
return Ok(MutationResult::Skipped);
|
return Ok(MutationResult::Skipped);
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,9 @@ use libafl_bolts::{
|
|||||||
};
|
};
|
||||||
use tuple_list::{tuple_list, tuple_list_type};
|
use tuple_list::{tuple_list, tuple_list_type};
|
||||||
|
|
||||||
use super::{
|
use super::{MappingMutator, MutationResult, Mutator, ToMappingMutator};
|
||||||
MappedInputFunctionMappingMutator, MutationResult, Mutator,
|
|
||||||
ToMappedInputFunctionMappingMutatorMapper,
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::Corpus,
|
||||||
inputs::value::ValueMutRefInput,
|
|
||||||
random_corpus_id_with_disabled,
|
random_corpus_id_with_disabled,
|
||||||
state::{HasCorpus, HasRand},
|
state::{HasCorpus, HasRand},
|
||||||
};
|
};
|
||||||
@ -75,14 +71,14 @@ pub fn int_mutators() -> IntMutatorsType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Mapped mutators for integer-like inputs
|
/// Mapped mutators for integer-like inputs
|
||||||
pub type MappedIntMutatorsType<F1, F2, I> = tuple_list_type!(
|
pub type MappedIntMutatorsType<F1, F2> = tuple_list_type!(
|
||||||
MappedInputFunctionMappingMutator<BitFlipMutator,F1,I>,
|
MappingMutator<BitFlipMutator,F1>,
|
||||||
MappedInputFunctionMappingMutator<NegateMutator,F1,I>,
|
MappingMutator<NegateMutator,F1>,
|
||||||
MappedInputFunctionMappingMutator<IncMutator,F1,I>,
|
MappingMutator<IncMutator,F1>,
|
||||||
MappedInputFunctionMappingMutator<DecMutator,F1,I>,
|
MappingMutator<DecMutator,F1>,
|
||||||
MappedInputFunctionMappingMutator<TwosComplementMutator,F1,I>,
|
MappingMutator<TwosComplementMutator,F1>,
|
||||||
MappedInputFunctionMappingMutator<RandMutator,F1,I>,
|
MappingMutator<RandMutator,F1>,
|
||||||
MappedInputFunctionMappingMutator<MappedCrossoverMutator<F2>,F1,I>
|
MappingMutator<MappedCrossoverMutator<F2>,F1>
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Mapped mutators for integer-like inputs
|
/// Mapped mutators for integer-like inputs
|
||||||
@ -91,15 +87,13 @@ pub type MappedIntMutatorsType<F1, F2, I> = tuple_list_type!(
|
|||||||
pub fn mapped_int_mutators<F1, F2, IO, II>(
|
pub fn mapped_int_mutators<F1, F2, IO, II>(
|
||||||
current_input_mapper: F1,
|
current_input_mapper: F1,
|
||||||
input_from_corpus_mapper: F2,
|
input_from_corpus_mapper: F2,
|
||||||
) -> MappedIntMutatorsType<F1, F2, II>
|
) -> MappedIntMutatorsType<F1, F2>
|
||||||
where
|
where
|
||||||
F1: Clone + FnMut(IO) -> II,
|
F1: Clone + FnMut(&mut IO) -> &mut II,
|
||||||
{
|
{
|
||||||
int_mutators_no_crossover()
|
int_mutators_no_crossover()
|
||||||
.merge(mapped_int_mutators_crossover(input_from_corpus_mapper))
|
.merge(mapped_int_mutators_crossover(input_from_corpus_mapper))
|
||||||
.map(ToMappedInputFunctionMappingMutatorMapper::new(
|
.map(ToMappingMutator::new(current_input_mapper))
|
||||||
current_input_mapper,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
/// Functionality required for Numeric Mutators (see [`int_mutators`])
|
/// Functionality required for Numeric Mutators (see [`int_mutators`])
|
||||||
pub trait Numeric {
|
pub trait Numeric {
|
||||||
@ -209,6 +203,32 @@ macro_rules! impl_numeric_128_bits_randomize {
|
|||||||
// Apply the macro to all desired integer types
|
// Apply the macro to all desired integer types
|
||||||
impl_numeric_128_bits_randomize! { u128 i128 }
|
impl_numeric_128_bits_randomize! { u128 i128 }
|
||||||
|
|
||||||
|
impl<I: Numeric> Numeric for &mut I {
|
||||||
|
fn flip_all_bits(&mut self) {
|
||||||
|
(*self).flip_all_bits();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flip_bit_at(&mut self, offset: usize) {
|
||||||
|
(*self).flip_bit_at(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrapping_inc(&mut self) {
|
||||||
|
(*self).wrapping_inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrapping_dec(&mut self) {
|
||||||
|
(*self).wrapping_dec();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn twos_complement(&mut self) {
|
||||||
|
(*self).twos_complement();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn randomize<R: Rand>(&mut self, rand: &mut R) {
|
||||||
|
(*self).randomize(rand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Bitflip mutation for integer-like inputs
|
/// Bitflip mutation for integer-like inputs
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BitFlipMutator;
|
pub struct BitFlipMutator;
|
||||||
@ -374,17 +394,13 @@ impl<F> MappedCrossoverMutator<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, S, F> Mutator<ValueMutRefInput<'_, I>, S> for MappedCrossoverMutator<F>
|
impl<I, S, F> Mutator<I, S> for MappedCrossoverMutator<F>
|
||||||
where
|
where
|
||||||
S: HasRand + HasCorpus,
|
S: HasRand + HasCorpus,
|
||||||
for<'b> F: Fn(&'b <S::Corpus as Corpus>::Input) -> &'b I,
|
for<'b> F: Fn(&'b <S::Corpus as Corpus>::Input) -> &'b I,
|
||||||
I: Clone,
|
I: Clone,
|
||||||
{
|
{
|
||||||
fn mutate(
|
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
|
||||||
input: &mut ValueMutRefInput<'_, I>,
|
|
||||||
) -> Result<MutationResult, Error> {
|
|
||||||
let id = random_corpus_id_with_disabled!(state.corpus(), state.rand_mut());
|
let id = random_corpus_id_with_disabled!(state.corpus(), state.rand_mut());
|
||||||
|
|
||||||
if state.corpus().current().is_some_and(|cur| cur == id) {
|
if state.corpus().current().is_some_and(|cur| cur == id) {
|
||||||
@ -394,7 +410,7 @@ where
|
|||||||
let other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
|
let other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
|
||||||
let other_input = other_testcase.input().as_ref().unwrap();
|
let other_input = other_testcase.input().as_ref().unwrap();
|
||||||
let mapped_input = (self.input_mapper)(other_input).clone();
|
let mapped_input = (self.input_mapper)(other_input).clone();
|
||||||
**input = mapped_input;
|
*input = mapped_input;
|
||||||
Ok(MutationResult::Mutated)
|
Ok(MutationResult::Mutated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -850,6 +850,12 @@ impl<T> HasLen for Vec<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: HasLen> HasLen for &mut T {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.deref().len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Has a ref count
|
/// Has a ref count
|
||||||
pub trait HasRefCnt {
|
pub trait HasRefCnt {
|
||||||
/// The ref count
|
/// The ref count
|
||||||
|
Loading…
x
Reference in New Issue
Block a user