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:
Valentin Huber 2024-12-19 14:35:17 +01:00 committed by GitHub
parent e46cf8a851
commit 5d70216cc7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 265 additions and 530 deletions

View File

@ -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)

View File

@ -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

View File

@ -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)
}; };

View File

@ -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>

View File

@ -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);

View File

@ -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>

View File

@ -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
); );
} }

View File

@ -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,
))
} }

View File

@ -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)
} }
} }

View File

@ -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);
} }

View File

@ -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)
} }
} }

View File

@ -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