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
- `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`.
- `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::{
corpus::CorpusId,
generators::{Generator, RandBytesGenerator},
inputs::{value::MutI16Input, BytesInput, HasTargetBytes, Input, MutVecInput},
inputs::{BytesInput, HasTargetBytes, Input},
mutators::{MutationResult, Mutator},
state::HasRand,
Error, SerdeAny,
@ -36,28 +36,28 @@ impl Input for CustomInput {
impl CustomInput {
/// Returns a mutable reference to the byte array
pub fn byte_array_mut(&mut self) -> MutVecInput<'_> {
(&mut self.byte_array).into()
pub fn byte_array_mut(&mut self) -> &mut Vec<u8> {
&mut self.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
}
/// Returns a mutable reference to the optional byte array
pub fn optional_byte_array_mut(&mut self) -> Option<MutVecInput<'_>> {
self.optional_byte_array.as_mut().map(|e| e.into())
pub fn optional_byte_array_mut(&mut self) -> &mut Option<Vec<u8>> {
&mut self.optional_byte_array
}
/// Returns an immutable reference to the optional byte array
pub fn optional_byte_array(&self) -> Option<&[u8]> {
self.optional_byte_array.as_deref()
pub fn optional_byte_array(&self) -> &Option<Vec<u8>> {
&self.optional_byte_array
}
/// Returns a mutable reference to the number
pub fn num_mut(&mut self) -> MutI16Input<'_> {
(&mut self.num).into()
pub fn num_mut(&mut self) -> &mut i16 {
&mut self.num
}
/// Returns an immutable reference to the number

View File

@ -34,7 +34,7 @@ use libafl_bolts::{
use {
libafl::mutators::{
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},
},
libafl_bolts::tuples::Map,
@ -164,26 +164,20 @@ pub fn main() {
// Creating mutators that will operate on input.byte_array
let mapped_mutators = havoc_mutations_no_crossover()
.merge(havoc_crossover_with_corpus_mapper(CustomInput::byte_array))
.map(ToMappedInputFunctionMappingMutatorMapper::new(
CustomInput::byte_array_mut,
));
.map(ToMappingMutator::new(CustomInput::byte_array_mut));
// Creating mutators that will operate on input.optional_byte_array
let optional_mapped_mutators = havoc_mutations_no_crossover()
.merge(havoc_crossover_with_corpus_mapper(
CustomInput::optional_byte_array,
))
.map(ToOptionMappingMutatorMapper)
.map(ToMappedInputFunctionMappingMutatorMapper::new(
CustomInput::optional_byte_array_mut,
));
.map(ToOptionalMutator)
.map(ToMappingMutator::new(CustomInput::optional_byte_array_mut));
// Creating mutators that will operate on input.num
let int_mutators = int_mutators_no_crossover()
.merge(mapped_int_mutators_crossover(CustomInput::num))
.map(ToMappedInputFunctionMappingMutatorMapper::new(
CustomInput::num_mut,
));
.map(ToMappingMutator::new(CustomInput::num_mut));
(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) {
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>

View File

@ -11,7 +11,7 @@ use libafl_bolts::{
HasLen,
};
use crate::inputs::{HasMutatorBytes, MappedInput};
use crate::inputs::HasMutatorBytes;
/// 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.
@ -201,23 +201,14 @@ where
self.range.len()
}
}
impl<I> MappedInput for BytesSubInput<'_, I> {
type Type<'b>
= BytesSubInput<'b, I>
where
Self: 'b;
}
#[cfg(test)]
mod tests {
use alloc::vec::Vec;
use libafl_bolts::HasLen;
use crate::{
inputs::{BytesInput, HasMutatorBytes, MutVecInput, NopInput},
inputs::{BytesInput, HasMutatorBytes, NopInput},
mutators::{havoc_mutations_no_crossover, MutatorsTuple},
state::NopState,
};
@ -346,7 +337,6 @@ mod tests {
#[test]
fn test_bytessubinput_use_vec() {
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);
drop(sub_vec.drain(..));
assert_eq!(test_vec.len(), 4);

View File

@ -35,7 +35,7 @@ use core::{
clone::Clone,
fmt::Debug,
marker::PhantomData,
ops::{Deref, DerefMut, RangeBounds},
ops::{DerefMut, RangeBounds},
};
#[cfg(feature = "std")]
use std::{fs::File, hash::Hash, io::Read, path::Path};
@ -50,7 +50,6 @@ use libafl_bolts::{
#[cfg(feature = "nautilus")]
pub use nautilus::*;
use serde::{Deserialize, Serialize};
use value::ValueMutRefInput;
use crate::corpus::CorpusId;
@ -198,36 +197,44 @@ pub trait HasMutatorBytes: HasLen {
}
}
/// Mapping types to themselves, used to ensure lifetime consistency for mapped mutators.
///
/// 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.
pub trait MappedInput {
/// The type for which this trait is implemented
type Type<'a>
impl HasMutatorBytes for Vec<u8> {
fn bytes(&self) -> &[u8] {
self.as_ref()
}
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
Self: 'a;
}
R: RangeBounds<usize>,
I: IntoIterator<Item = u8>,
{
<Vec<u8>>::splice(self, range, replace_with)
}
impl<T> MappedInput for Option<T>
where
T: MappedInput,
{
type Type<'a>
= Option<T::Type<'a>>
fn drain<R>(&mut self, range: R) -> Drain<'_, u8>
where
T: 'a;
}
/// A wrapper type that allows us to use mutators for Mutators for `&mut `[`Vec`].
pub type MutVecInput<'a> = ValueMutRefInput<'a, Vec<u8>>;
impl HasLen for MutVecInput<'_> {
fn len(&self) -> usize {
self.deref().len()
R: RangeBounds<usize>,
{
<Vec<u8>>::drain(self, range)
}
}
impl HasMutatorBytes for MutVecInput<'_> {
/// A wrapper type that allows us to use mutators for Mutators for `&mut `[`Vec`].
#[deprecated(since = "0.15.0", note = "Use &mut Vec<u8> directly")]
pub type MutVecInput<'a> = &'a mut Vec<u8>;
impl HasMutatorBytes for &mut Vec<u8> {
fn bytes(&self) -> &[u8] {
self
}
@ -241,7 +248,7 @@ impl HasMutatorBytes for MutVecInput<'_> {
}
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>

View File

@ -1,11 +1,7 @@
//! Newtype pattern style wrapper for [`super::Input`]s
use alloc::{string::String, vec::Vec};
use core::{
fmt::Debug,
hash::Hash,
ops::{Deref, DerefMut},
};
use core::{fmt::Debug, hash::Hash};
use libafl_bolts::{generic_hash_std, rands::Rand};
use serde::{Deserialize, Serialize};
@ -15,7 +11,7 @@ use {
std::{fs::File, io::Read, path::Path},
};
use super::{Input, MappedInput};
use super::Input;
use crate::{corpus::CorpusId, mutators::numeric::Numeric};
/// 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)]
mod tests {
#[cfg(feature = "std")]
use {
super::{ValueInput, ValueMutRefInput},
crate::mutators::numeric::Numeric,
alloc::fmt::Debug,
super::ValueInput, crate::mutators::numeric::Numeric, alloc::fmt::Debug,
std::any::type_name,
};
@ -291,6 +194,7 @@ mod tests {
}
#[cfg(feature = "std")]
#[expect(unused_mut)]
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!(
@ -301,8 +205,8 @@ mod tests {
);
apply_all_ops!(
let mut i_clone = i.clone(),
ValueMutRefInput::from(&mut i_clone),
ValueMutRefInput<'_, I>,
&mut i_clone,
&mut I,
check_twos_complement
);
}

View File

@ -3,11 +3,9 @@
use libafl_bolts::tuples::{Map, Merge};
use tuple_list::{tuple_list, tuple_list_type};
use super::{MappingMutator, ToMappingMutator};
use crate::mutators::{
mapping::{
MappedInputFunctionMappingMutator, OptionMappingMutator,
ToMappedInputFunctionMappingMutatorMapper, ToOptionMappingMutatorMapper,
},
mapping::{OptionalMutator, ToOptionalMutator},
mutations::{
BitFlipMutator, ByteAddMutator, ByteDecMutator, ByteFlipMutator, ByteIncMutator,
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
pub type MappedHavocMutationsType<F1, F2, II, O> = tuple_list_type!(
MappedInputFunctionMappingMutator<BitFlipMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteFlipMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteIncMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteDecMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteNegMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteRandMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteAddMutator, F1, II>,
MappedInputFunctionMappingMutator<WordAddMutator, F1, II>,
MappedInputFunctionMappingMutator<DwordAddMutator, F1, II>,
MappedInputFunctionMappingMutator<QwordAddMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteInterestingMutator, F1, II>,
MappedInputFunctionMappingMutator<WordInterestingMutator, F1, II>,
MappedInputFunctionMappingMutator<DwordInterestingMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesExpandMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesInsertMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesRandInsertMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesSetMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesRandSetMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesCopyMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesInsertCopyMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesSwapMutator, F1, II>,
MappedInputFunctionMappingMutator<MappedCrossoverInsertMutator<F2, O>, F1, II>,
MappedInputFunctionMappingMutator<MappedCrossoverReplaceMutator<F2, O>, F1, II>,
pub type MappedHavocMutationsType<F1, F2, O> = tuple_list_type!(
MappingMutator<BitFlipMutator, F1>,
MappingMutator<ByteFlipMutator, F1>,
MappingMutator<ByteIncMutator, F1>,
MappingMutator<ByteDecMutator, F1>,
MappingMutator<ByteNegMutator, F1>,
MappingMutator<ByteRandMutator, F1>,
MappingMutator<ByteAddMutator, F1>,
MappingMutator<WordAddMutator, F1>,
MappingMutator<DwordAddMutator, F1>,
MappingMutator<QwordAddMutator, F1>,
MappingMutator<ByteInterestingMutator, F1>,
MappingMutator<WordInterestingMutator, F1>,
MappingMutator<DwordInterestingMutator, F1>,
MappingMutator<BytesDeleteMutator, F1>,
MappingMutator<BytesDeleteMutator, F1>,
MappingMutator<BytesDeleteMutator, F1>,
MappingMutator<BytesDeleteMutator, F1>,
MappingMutator<BytesExpandMutator, F1>,
MappingMutator<BytesInsertMutator, F1>,
MappingMutator<BytesRandInsertMutator, F1>,
MappingMutator<BytesSetMutator, F1>,
MappingMutator<BytesRandSetMutator, F1>,
MappingMutator<BytesCopyMutator, F1>,
MappingMutator<BytesInsertCopyMutator, F1>,
MappingMutator<BytesSwapMutator, F1>,
MappingMutator<MappedCrossoverInsertMutator<F2, O>, F1>,
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
pub type OptionMappedHavocMutationsType<F1, F2, II, O> = tuple_list_type!(
MappedInputFunctionMappingMutator<OptionMappingMutator<BitFlipMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteFlipMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteIncMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteDecMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteNegMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteRandMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteAddMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<WordAddMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<DwordAddMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<QwordAddMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteInterestingMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<WordInterestingMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<DwordInterestingMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesExpandMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesInsertMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesRandInsertMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesSetMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesRandSetMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesCopyMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesInsertCopyMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesSwapMutator>, F1, II>,
MappedInputFunctionMappingMutator<
OptionMappingMutator<MappedCrossoverInsertMutator<F2, O>>,
F1,
II,
>,
MappedInputFunctionMappingMutator<
OptionMappingMutator<MappedCrossoverReplaceMutator<F2, O>>,
F1,
II,
>,
pub type OptionMappedHavocMutationsType<F1, F2, O> = tuple_list_type!(
MappingMutator<OptionalMutator<BitFlipMutator>, F1>,
MappingMutator<OptionalMutator<ByteFlipMutator>, F1>,
MappingMutator<OptionalMutator<ByteIncMutator>, F1>,
MappingMutator<OptionalMutator<ByteDecMutator>, F1>,
MappingMutator<OptionalMutator<ByteNegMutator>, F1>,
MappingMutator<OptionalMutator<ByteRandMutator>, F1>,
MappingMutator<OptionalMutator<ByteAddMutator>, F1>,
MappingMutator<OptionalMutator<WordAddMutator>, F1>,
MappingMutator<OptionalMutator<DwordAddMutator>, F1>,
MappingMutator<OptionalMutator<QwordAddMutator>, F1>,
MappingMutator<OptionalMutator<ByteInterestingMutator>, F1>,
MappingMutator<OptionalMutator<WordInterestingMutator>, F1>,
MappingMutator<OptionalMutator<DwordInterestingMutator>, F1>,
MappingMutator<OptionalMutator<BytesDeleteMutator>, F1>,
MappingMutator<OptionalMutator<BytesDeleteMutator>, F1>,
MappingMutator<OptionalMutator<BytesDeleteMutator>, F1>,
MappingMutator<OptionalMutator<BytesDeleteMutator>, F1>,
MappingMutator<OptionalMutator<BytesExpandMutator>, F1>,
MappingMutator<OptionalMutator<BytesInsertMutator>, F1>,
MappingMutator<OptionalMutator<BytesRandInsertMutator>, F1>,
MappingMutator<OptionalMutator<BytesSetMutator>, F1>,
MappingMutator<OptionalMutator<BytesRandSetMutator>, F1>,
MappingMutator<OptionalMutator<BytesCopyMutator>, F1>,
MappingMutator<OptionalMutator<BytesInsertCopyMutator>, F1>,
MappingMutator<OptionalMutator<BytesSwapMutator>, F1>,
MappingMutator<OptionalMutator<MappedCrossoverInsertMutator<F2, O>>, F1>,
MappingMutator<OptionalMutator<MappedCrossoverReplaceMutator<F2, O>>, F1>,
);
/// 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,
) -> MappedHavocCrossoverType<F, O>
where
F: Clone + Fn(IO) -> O,
F: Clone + Fn(&IO) -> &O,
{
tuple_list!(
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>(
current_input_mapper: F1,
input_from_corpus_mapper: F2,
) -> MappedHavocMutationsType<F1, F2, II, O>
) -> MappedHavocMutationsType<F1, F2, O>
where
F1: Clone + FnMut(IO1) -> II,
F2: Clone + Fn(IO2) -> O,
F1: Clone + FnMut(&mut IO1) -> &mut II,
F2: Clone + Fn(&IO2) -> &O,
{
havoc_mutations_no_crossover()
.merge(havoc_crossover_with_corpus_mapper(input_from_corpus_mapper))
.map(ToMappedInputFunctionMappingMutatorMapper::new(
current_input_mapper,
))
.map(ToMappingMutator::new(current_input_mapper))
}
/// 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>(
current_input_mapper: F1,
input_from_corpus_mapper: F2,
) -> OptionMappedHavocMutationsType<F1, F2, II, O>
) -> OptionMappedHavocMutationsType<F1, F2, O>
where
F1: Clone + FnMut(IO1) -> II,
F2: Clone + Fn(IO2) -> O,
F1: Clone + FnMut(&mut IO1) -> &mut II,
F2: Clone + Fn(&IO2) -> &O,
{
havoc_mutations_no_crossover()
.merge(havoc_crossover_with_corpus_mapper_optional(
input_from_corpus_mapper,
))
.map(ToOptionMappingMutatorMapper)
.map(ToMappedInputFunctionMappingMutatorMapper::new(
current_input_mapper,
))
.map(ToOptionalMutator)
.map(ToMappingMutator::new(current_input_mapper))
}

View File

@ -1,11 +1,9 @@
//! Allowing mixing and matching between [`Mutator`] and [`crate::inputs::Input`] types.
use alloc::borrow::Cow;
use core::marker::PhantomData;
use libafl_bolts::{tuples::MappingFunctor, Named};
use crate::{
inputs::MappedInput,
mutators::{MutationResult, Mutator},
Error,
};
@ -20,49 +18,45 @@ use crate::{
/// use std::vec::Vec;
///
/// use libafl::{
/// inputs::MutVecInput,
/// mutators::{
/// ByteIncMutator, FunctionMappingMutator, MappedInputFunctionMappingMutator,
/// MutationResult, Mutator,
/// },
/// mutators::{ByteIncMutator, MappingMutator, MutationResult, Mutator},
/// state::NopState,
/// };
///
/// type CustomInput = (Vec<u8>,);
/// fn extract_to_ref(input: &mut CustomInput) -> &mut Vec<u8> {
/// &mut input.0
/// #[derive(Debug, PartialEq)]
/// struct CustomInput(Vec<u8>);
///
/// impl CustomInput {
/// pub fn vec_mut(&mut self) -> &mut Vec<u8> {
/// &mut self.0
/// }
/// }
///
/// fn extract_from_ref(input: &mut Vec<u8>) -> MutVecInput<'_> {
/// input.into()
/// }
/// // construct a mutator that works on &mut Vec<u8> (since it impls `HasMutatorBytes`)
/// 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 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 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],));
/// assert_eq!(input, CustomInput(vec![2],));
/// ```
#[derive(Debug)]
pub struct FunctionMappingMutator<M, F> {
pub struct MappingMutator<M, F> {
mapper: F,
inner: M,
name: Cow<'static, str>,
}
impl<M, F> FunctionMappingMutator<M, F> {
/// Creates a new [`FunctionMappingMutator`]
impl<M, F> MappingMutator<M, F> {
/// Creates a new [`MappingMutator`]
pub fn new(mapper: F, inner: M) -> Self
where
M: Named,
{
let name = Cow::Owned(format!("FunctionMappingMutator<{}>", inner.name()));
let name = Cow::Owned(format!("MappingMutator<{}>", inner.name()));
Self {
mapper,
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
F: for<'a> FnMut(&'a mut IO) -> &'a mut II,
F: FnMut(&mut IO) -> &mut II,
M: Mutator<II, S>,
{
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> {
&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
#[cfg_attr(feature = "std", doc = " ```")]
@ -97,207 +91,57 @@ impl<M, F> Named for FunctionMappingMutator<M, F> {
/// use std::vec::Vec;
///
/// use libafl::{
/// inputs::MutVecInput,
/// mutators::{
/// ByteIncMutator, MappedInputFunctionMappingMutator, MutationResult, Mutator,
/// ToFunctionMappingMutatorMapper,
/// ByteIncMutator, MutationResult, MutatorsTuple, ToMappingMutator,
/// },
/// state::NopState,
/// };
///
///
/// use libafl_bolts::tuples::{tuple_list, Map};
///
/// type CustomInput = (Vec<u8>,);
/// fn extract_to_ref(input: &mut CustomInput) -> &mut Vec<u8> {
/// &mut input.0
///
/// #[derive(Debug, PartialEq)]
/// struct CustomInput(Vec<u8>);
///
/// impl CustomInput {
/// pub fn vec_mut(&mut self) -> &mut Vec<u8> {
/// &mut self.0
/// }
/// }
///
/// fn extract_from_ref(input: &mut Vec<u8>) -> MutVecInput<'_> {
/// input.into()
/// }
///
/// // construct a mapper that works on &mut Vec<u8>
/// 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],);
///
///
/// // construct a mutator that works on &mut Vec<u8> (since it impls `HasMutatorBytes`)
/// 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));
///
/// let mut input = CustomInput(vec![1]);
///
/// 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!(input, (vec![2],));
/// assert_eq!(input, CustomInput(vec![3],));
/// ```
#[derive(Debug)]
pub struct ToFunctionMappingMutatorMapper<F> {
pub struct ToMappingMutator<F> {
mapper: F,
}
impl<F> ToFunctionMappingMutatorMapper<F> {
/// Creates a new [`ToFunctionMappingMutatorMapper`]
impl<F> ToMappingMutator<F> {
/// Creates a new [`ToMappingMutator`]
pub fn new(mapper: F) -> Self {
Self { mapper }
}
}
impl<M, F> MappingFunctor<M> for ToFunctionMappingMutatorMapper<F>
impl<M, F> MappingFunctor<M> for ToMappingMutator<F>
where
F: Clone,
M: Named,
{
type Output = FunctionMappingMutator<M, F>;
type Output = MappingMutator<M, F>;
fn apply(&mut self, from: M) -> Self::Output {
FunctionMappingMutator::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)
MappingMutator::new(self.mapper.clone(), from)
}
}
@ -312,12 +156,12 @@ where
#[cfg_attr(not(feature = "std"), doc = " ```ignore")]
/// use libafl::{
/// inputs::MutVecInput,
/// mutators::{ByteIncMutator, MutationResult, Mutator, OptionMappingMutator},
/// mutators::{ByteIncMutator, MutationResult, Mutator, OptionalMutator},
/// state::NopState,
/// };
///
/// let inner = ByteIncMutator::new();
/// let mut outer = OptionMappingMutator::new(inner);
/// let mut outer = OptionalMutator::new(inner);
///
/// let mut input_raw = vec![1];
/// let input: MutVecInput = (&mut input_raw).into();
@ -332,23 +176,23 @@ where
/// assert_eq!(res2, MutationResult::Skipped);
/// ```
#[derive(Debug)]
pub struct OptionMappingMutator<M> {
pub struct OptionalMutator<M> {
inner: M,
name: Cow<'static, str>,
}
impl<M> OptionMappingMutator<M> {
/// Creates a new [`OptionMappingMutator`]
impl<M> OptionalMutator<M> {
/// Creates a new [`OptionalMutator`]
pub fn new(inner: M) -> Self
where
M: Named,
{
let name = Cow::Owned(format!("OptionMappingMutator<{}>", inner.name()));
let name = Cow::Owned(format!("OptionalMutator<{}>", 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
M: Mutator<I, S>,
{
@ -360,7 +204,7 @@ where
}
}
impl<M> Named for OptionMappingMutator<M>
impl<M> Named for OptionalMutator<M>
where
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
#[cfg_attr(feature = "std", doc = " ```")]
#[cfg_attr(not(feature = "std"), doc = " ```ignore")]
/// use libafl::{
/// inputs::MutVecInput,
/// mutators::{ByteIncMutator, MutationResult, Mutator, ToOptionMappingMutatorMapper},
/// mutators::{ByteIncMutator, MutationResult, Mutator, ToOptionalMutator},
/// state::NopState,
/// };
/// use libafl_bolts::tuples::{tuple_list, Map};
///
/// 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 input_raw = vec![1];
@ -400,15 +244,15 @@ where
/// assert_eq!(res2, MutationResult::Skipped);
/// ```
#[derive(Debug)]
pub struct ToOptionMappingMutatorMapper;
pub struct ToOptionalMutator;
impl<M> MappingFunctor<M> for ToOptionMappingMutatorMapper
impl<M> MappingFunctor<M> for ToOptionalMutator
where
M: Named,
{
type Output = OptionMappingMutator<M>;
type Output = OptionalMutator<M>;
fn apply(&mut self, from: M) -> Self::Output {
OptionMappingMutator::new(from)
OptionalMutator::new(from)
}
}

View File

@ -1280,32 +1280,18 @@ impl CrossoverReplaceMutator {
}
trait IntoOptionBytes {
type Type<'b>;
fn into_option_bytes<'a>(self) -> Option<&'a [u8]>
where
Self: 'a;
fn map_to_option_bytes(&self) -> Option<&Vec<u8>>;
}
impl IntoOptionBytes for &[u8] {
type Type<'b> = &'b [u8];
fn into_option_bytes<'b>(self) -> Option<&'b [u8]>
where
Self: 'b,
{
impl IntoOptionBytes for Vec<u8> {
fn map_to_option_bytes(&self) -> Option<&Vec<u8>> {
Some(self)
}
}
impl IntoOptionBytes for Option<&[u8]> {
type Type<'b> = Option<&'b [u8]>;
fn into_option_bytes<'b>(self) -> Option<&'b [u8]>
where
Self: 'b,
{
self
impl IntoOptionBytes for Option<Vec<u8>> {
fn map_to_option_bytes(&self) -> Option<&Vec<u8>> {
self.as_ref()
}
}
@ -1330,9 +1316,8 @@ impl<S, F, I, O> Mutator<I, S> for MappedCrossoverInsertMutator<F, O>
where
S: HasCorpus + HasMaxSize + HasRand,
I: HasMutatorBytes,
for<'a> O: IntoOptionBytes,
for<'a> O::Type<'a>: IntoOptionBytes,
for<'a> F: Fn(&'a <S::Corpus as Corpus>::Input) -> <O as IntoOptionBytes>::Type<'a>,
O: IntoOptionBytes,
F: Fn(&<S::Corpus as Corpus>::Input) -> &O,
{
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len();
@ -1353,8 +1338,8 @@ where
let other_size = {
let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
let other_input = other_testcase.load_input(state.corpus())?;
let input_mapped = (self.input_mapper)(other_input).into_option_bytes();
input_mapped.map_or(0, <[u8]>::len)
let input_mapped = (self.input_mapper)(other_input).map_to_option_bytes();
input_mapped.map_or(0, <Vec<u8>>::len)
};
if other_size < 2 {
@ -1376,7 +1361,7 @@ where
let other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
// No need to load the input again, it'll still be cached.
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() {
return Ok(MutationResult::Skipped);
}
@ -1421,8 +1406,7 @@ where
S: HasCorpus + HasMaxSize + HasRand,
I: HasMutatorBytes,
O: IntoOptionBytes,
for<'a> O::Type<'a>: IntoOptionBytes,
for<'a> F: Fn(&'a <S::Corpus as Corpus>::Input) -> <O as IntoOptionBytes>::Type<'a>,
F: Fn(&<S::Corpus as Corpus>::Input) -> &O,
{
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len();
@ -1441,8 +1425,8 @@ where
let other_size = {
let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
let other_input = other_testcase.load_input(state.corpus())?;
let input_mapped = (self.input_mapper)(other_input).into_option_bytes();
input_mapped.map_or(0, <[u8]>::len)
let input_mapped = (self.input_mapper)(other_input).map_to_option_bytes();
input_mapped.map_or(0, <Vec<u8>>::len)
};
if other_size < 2 {
@ -1464,7 +1448,7 @@ where
let other_testcase = state.corpus().get_from_all(id)?.borrow_mut();
// No need to load the input again, it'll still be cached.
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() {
return Ok(MutationResult::Skipped);
}

View File

@ -9,13 +9,9 @@ use libafl_bolts::{
};
use tuple_list::{tuple_list, tuple_list_type};
use super::{
MappedInputFunctionMappingMutator, MutationResult, Mutator,
ToMappedInputFunctionMappingMutatorMapper,
};
use super::{MappingMutator, MutationResult, Mutator, ToMappingMutator};
use crate::{
corpus::Corpus,
inputs::value::ValueMutRefInput,
random_corpus_id_with_disabled,
state::{HasCorpus, HasRand},
};
@ -75,14 +71,14 @@ pub fn int_mutators() -> IntMutatorsType {
}
/// Mapped mutators for integer-like inputs
pub type MappedIntMutatorsType<F1, F2, I> = tuple_list_type!(
MappedInputFunctionMappingMutator<BitFlipMutator,F1,I>,
MappedInputFunctionMappingMutator<NegateMutator,F1,I>,
MappedInputFunctionMappingMutator<IncMutator,F1,I>,
MappedInputFunctionMappingMutator<DecMutator,F1,I>,
MappedInputFunctionMappingMutator<TwosComplementMutator,F1,I>,
MappedInputFunctionMappingMutator<RandMutator,F1,I>,
MappedInputFunctionMappingMutator<MappedCrossoverMutator<F2>,F1,I>
pub type MappedIntMutatorsType<F1, F2> = tuple_list_type!(
MappingMutator<BitFlipMutator,F1>,
MappingMutator<NegateMutator,F1>,
MappingMutator<IncMutator,F1>,
MappingMutator<DecMutator,F1>,
MappingMutator<TwosComplementMutator,F1>,
MappingMutator<RandMutator,F1>,
MappingMutator<MappedCrossoverMutator<F2>,F1>
);
/// 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>(
current_input_mapper: F1,
input_from_corpus_mapper: F2,
) -> MappedIntMutatorsType<F1, F2, II>
) -> MappedIntMutatorsType<F1, F2>
where
F1: Clone + FnMut(IO) -> II,
F1: Clone + FnMut(&mut IO) -> &mut II,
{
int_mutators_no_crossover()
.merge(mapped_int_mutators_crossover(input_from_corpus_mapper))
.map(ToMappedInputFunctionMappingMutatorMapper::new(
current_input_mapper,
))
.map(ToMappingMutator::new(current_input_mapper))
}
/// Functionality required for Numeric Mutators (see [`int_mutators`])
pub trait Numeric {
@ -209,6 +203,32 @@ macro_rules! impl_numeric_128_bits_randomize {
// Apply the macro to all desired integer types
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
#[derive(Debug)]
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
S: HasRand + HasCorpus,
for<'b> F: Fn(&'b <S::Corpus as Corpus>::Input) -> &'b I,
I: Clone,
{
fn mutate(
&mut self,
state: &mut S,
input: &mut ValueMutRefInput<'_, I>,
) -> Result<MutationResult, Error> {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let id = random_corpus_id_with_disabled!(state.corpus(), state.rand_mut());
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_input = other_testcase.input().as_ref().unwrap();
let mapped_input = (self.input_mapper)(other_input).clone();
**input = mapped_input;
*input = mapped_input;
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
pub trait HasRefCnt {
/// The ref count