From 5d70216cc73d332796b8efbd1d08f9288679fe50 Mon Sep 17 00:00:00 2001 From: Valentin Huber Date: Thu, 19 Dec 2024 14:35:17 +0100 Subject: [PATCH] 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 --- MIGRATION.md | 18 +- .../baby_fuzzer_custom_input/src/input.rs | 20 +- .../baby_fuzzer_custom_input/src/main.rs | 16 +- libafl/src/inputs/bytes.rs | 2 +- libafl/src/inputs/bytessub.rs | 14 +- libafl/src/inputs/mod.rs | 59 ++-- libafl/src/inputs/value.rs | 108 +------ libafl/src/mutators/havoc_mutations.rs | 150 +++++---- libafl/src/mutators/mapping.rs | 286 ++++-------------- libafl/src/mutators/mutations.rs | 46 +-- libafl/src/mutators/numeric.rs | 66 ++-- libafl_bolts/src/lib.rs | 6 + 12 files changed, 263 insertions(+), 528 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 392bc577ba..38c27d6041 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,12 +1,16 @@ -# Pre 0.9 -> 0.9 -- [Migrating from LibAFL <0.9 to 0.9](https://aflplus.plus/libafl-book/design/migration-0.9.html) - -# 0.14.0 -> 0.14.1 -- Removed `with_observers` from `Executor` trait. -- `MmapShMemProvider::new_shmem_persistent` has been removed in favour of `MmapShMem::persist`. You probably want to do something like this: `let shmem = MmapShMemProvider::new()?.new_shmem(size)?.persist()?;` # 0.14.1 -> 0.15.0 - `MmapShMem::new` and `MmapShMemProvider::new_shmem_with_id` now take `AsRef` 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` -- \ No newline at end of file +- 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` + - 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) \ No newline at end of file diff --git a/fuzzers/structure_aware/baby_fuzzer_custom_input/src/input.rs b/fuzzers/structure_aware/baby_fuzzer_custom_input/src/input.rs index 557a51d1ba..184f27f7b3 100644 --- a/fuzzers/structure_aware/baby_fuzzer_custom_input/src/input.rs +++ b/fuzzers/structure_aware/baby_fuzzer_custom_input/src/input.rs @@ -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 { + &mut self.byte_array } /// Returns an immutable reference to the byte array - pub fn byte_array(&self) -> &[u8] { + pub fn byte_array(&self) -> &Vec { &self.byte_array } /// Returns a mutable reference to the optional byte array - pub fn optional_byte_array_mut(&mut self) -> Option> { - self.optional_byte_array.as_mut().map(|e| e.into()) + pub fn optional_byte_array_mut(&mut self) -> &mut Option> { + &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> { + &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 diff --git a/fuzzers/structure_aware/baby_fuzzer_custom_input/src/main.rs b/fuzzers/structure_aware/baby_fuzzer_custom_input/src/main.rs index 3102ddc0f2..5e85ecf321 100644 --- a/fuzzers/structure_aware/baby_fuzzer_custom_input/src/main.rs +++ b/fuzzers/structure_aware/baby_fuzzer_custom_input/src/main.rs @@ -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) }; diff --git a/libafl/src/inputs/bytes.rs b/libafl/src/inputs/bytes.rs index 55bf30b35c..3cfe0ec45b 100644 --- a/libafl/src/inputs/bytes.rs +++ b/libafl/src/inputs/bytes.rs @@ -37,7 +37,7 @@ impl HasMutatorBytes for BytesInput { } fn extend<'a, I: IntoIterator>(&mut self, iter: I) { - self.as_mut().extend(iter); + as Extend>::extend(self.as_mut(), iter); } fn splice(&mut self, range: R, replace_with: I) -> vec::Splice<'_, I::IntoIter> diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index 0dcd104a59..c0280a9ec8 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -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 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); diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index dc7a3e5b99..055e2fb407 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -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 { + 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) { + >::resize(self, new_len, value); + } + + fn extend<'a, I: IntoIterator>(&mut self, iter: I) { + as Extend>::extend(self, iter); + } + + fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter> where - Self: 'a; -} + R: RangeBounds, + I: IntoIterator, + { + >::splice(self, range, replace_with) + } -impl MappedInput for Option -where - T: MappedInput, -{ - type Type<'a> - = Option> + fn drain(&mut self, range: R) -> Drain<'_, u8> where - T: 'a; + R: RangeBounds, + { + >::drain(self, range) + } } /// A wrapper type that allows us to use mutators for Mutators for `&mut `[`Vec`]. -pub type MutVecInput<'a> = ValueMutRefInput<'a, Vec>; - -impl HasLen for MutVecInput<'_> { - fn len(&self) -> usize { - self.deref().len() - } -} +#[deprecated(since = "0.15.0", note = "Use &mut Vec directly")] +pub type MutVecInput<'a> = &'a mut Vec; -impl HasMutatorBytes for MutVecInput<'_> { +impl HasMutatorBytes for &mut Vec { fn bytes(&self) -> &[u8] { self } @@ -241,7 +248,7 @@ impl HasMutatorBytes for MutVecInput<'_> { } fn extend<'b, I: IntoIterator>(&mut self, iter: I) { - self.deref_mut().extend(iter); + as Extend>::extend(self, iter); } fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter> diff --git a/libafl/src/inputs/value.rs b/libafl/src/inputs/value.rs index 06922c5f95..f2db679831 100644 --- a/libafl/src/inputs/value.rs +++ b/libafl/src/inputs/value.rs @@ -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` -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 Deref for ValueMutRefInput<'_, I> { - type Target = I; - - fn deref(&self) -> &Self::Target { - self.0 - } -} - -impl 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> for ValueMutRefInput<'a, I> { - fn from(value: &'a mut ValueInput) -> Self { - Self(value.as_mut()) - } -} - -impl MappedInput for ValueMutRefInput<'_, I> { - type Type<'a> - = ValueMutRefInput<'a, I> - where - Self: 'a; -} - -impl 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(&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: &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 ); } diff --git a/libafl/src/mutators/havoc_mutations.rs b/libafl/src/mutators/havoc_mutations.rs index 0e278e0475..7399ba7930 100644 --- a/libafl/src/mutators/havoc_mutations.rs +++ b/libafl/src/mutators/havoc_mutations.rs @@ -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 = tuple_list_type!( - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, +pub type MappedHavocMutationsType = tuple_list_type!( + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, F1>, + MappingMutator, F1>, ); /// Tuple type of the mutations that compose the Havoc mutator for mapped input types, for optional byte array input parts -pub type OptionMappedHavocMutationsType = tuple_list_type!( - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator, F1, II>, - MappedInputFunctionMappingMutator< - OptionMappingMutator>, - F1, - II, - >, - MappedInputFunctionMappingMutator< - OptionMappingMutator>, - F1, - II, - >, +pub type OptionMappedHavocMutationsType = tuple_list_type!( + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator, F1>, + MappingMutator>, F1>, + MappingMutator>, 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( input_mapper: F, ) -> MappedHavocCrossoverType 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( current_input_mapper: F1, input_from_corpus_mapper: F2, -) -> MappedHavocMutationsType +) -> MappedHavocMutationsType 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( current_input_mapper: F1, input_from_corpus_mapper: F2, -) -> OptionMappedHavocMutationsType +) -> OptionMappedHavocMutationsType 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)) } diff --git a/libafl/src/mutators/mapping.rs b/libafl/src/mutators/mapping.rs index 27dc7990d5..2d5a6d1ebe 100644 --- a/libafl/src/mutators/mapping.rs +++ b/libafl/src/mutators/mapping.rs @@ -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,); -/// fn extract_to_ref(input: &mut CustomInput) -> &mut Vec { -/// &mut input.0 -/// } +/// #[derive(Debug, PartialEq)] +/// struct CustomInput(Vec); /// -/// fn extract_from_ref(input: &mut Vec) -> MutVecInput<'_> { -/// input.into() +/// impl CustomInput { +/// pub fn vec_mut(&mut self) -> &mut Vec { +/// &mut self.0 +/// } /// } /// -/// // construct a mapper that works on &mut Vec -/// let inner: MappedInputFunctionMappingMutator<_, _, MutVecInput<'_>> = -/// MappedInputFunctionMappingMutator::new(extract_from_ref, ByteIncMutator::new()); -/// let mut outer = FunctionMappingMutator::new(extract_to_ref, inner); +/// // construct a mutator that works on &mut Vec (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); /// -/// let mut input: CustomInput = (vec![1],); +/// let mut input = CustomInput(vec![1]); /// /// let mut state: NopState = 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 { +pub struct MappingMutator { mapper: F, inner: M, name: Cow<'static, str>, } -impl FunctionMappingMutator { - /// Creates a new [`FunctionMappingMutator`] +impl MappingMutator { + /// 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 FunctionMappingMutator { } } -impl Mutator for FunctionMappingMutator +impl Mutator for MappingMutator where - F: for<'a> FnMut(&'a mut IO) -> &'a mut II, + F: FnMut(&mut IO) -> &mut II, M: Mutator, { fn mutate(&mut self, state: &mut S, input: &mut IO) -> Result { @@ -81,15 +75,15 @@ where } } -impl Named for FunctionMappingMutator { +impl Named for MappingMutator { 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 Named for FunctionMappingMutator { /// 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,); -/// fn extract_to_ref(input: &mut CustomInput) -> &mut Vec { -/// &mut input.0 +/// +/// #[derive(Debug, PartialEq)] +/// struct CustomInput(Vec); +/// +/// impl CustomInput { +/// pub fn vec_mut(&mut self) -> &mut Vec { +/// &mut self.0 +/// } /// } -/// -/// fn extract_from_ref(input: &mut Vec) -> MutVecInput<'_> { -/// input.into() -/// } -/// -/// // construct a mapper that works on &mut Vec -/// 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 (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 = 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 { +pub struct ToMappingMutator { mapper: F, } -impl ToFunctionMappingMutatorMapper { - /// Creates a new [`ToFunctionMappingMutatorMapper`] +impl ToMappingMutator { + /// Creates a new [`ToMappingMutator`] pub fn new(mapper: F) -> Self { Self { mapper } } } -impl MappingFunctor for ToFunctionMappingMutatorMapper -where - F: Clone, - M: Named, -{ - type Output = FunctionMappingMutator; - - 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,); -/// 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 = 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 { - mapper: F, - inner: M, - name: Cow<'static, str>, - phantom: PhantomData, -} - -impl MappedInputFunctionMappingMutator { - /// 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 Mutator for MappedInputFunctionMappingMutator -where - for<'a> M: Mutator, 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 { - let mapped = &mut (self.mapper)(input); - self.inner.mutate(state, mapped) - } -} - -impl Named for MappedInputFunctionMappingMutator { - 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,); -/// 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 = 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 { - mapper: F, - phantom: PhantomData, -} - -impl ToMappedInputFunctionMappingMutatorMapper { - /// Creates a new [`ToMappedInputFunctionMappingMutatorMapper`] - pub fn new(mapper: F) -> Self - where - F: FnMut(IO) -> II, - { - Self { - mapper, - phantom: PhantomData, - } - } -} - -impl MappingFunctor for ToMappedInputFunctionMappingMutatorMapper +impl MappingFunctor for ToMappingMutator where F: Clone, M: Named, { - type Output = MappedInputFunctionMappingMutator; + type Output = MappingMutator; 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 { +pub struct OptionalMutator { inner: M, name: Cow<'static, str>, } -impl OptionMappingMutator { - /// Creates a new [`OptionMappingMutator`] +impl OptionalMutator { + /// 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 Mutator, S> for OptionMappingMutator +impl Mutator, S> for OptionalMutator where M: Mutator, { @@ -360,7 +204,7 @@ where } } -impl Named for OptionMappingMutator +impl Named for OptionalMutator 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 MappingFunctor for ToOptionMappingMutatorMapper +impl MappingFunctor for ToOptionalMutator where M: Named, { - type Output = OptionMappingMutator; + type Output = OptionalMutator; fn apply(&mut self, from: M) -> Self::Output { - OptionMappingMutator::new(from) + OptionalMutator::new(from) } } diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index c44cabb2ac..6cf41e1b37 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -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>; } -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 { + fn map_to_option_bytes(&self) -> Option<&Vec> { 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> { + fn map_to_option_bytes(&self) -> Option<&Vec> { + self.as_ref() } } @@ -1330,9 +1316,8 @@ impl Mutator for MappedCrossoverInsertMutator where S: HasCorpus + HasMaxSize + HasRand, I: HasMutatorBytes, - for<'a> O: IntoOptionBytes, - for<'a> O::Type<'a>: IntoOptionBytes, - for<'a> F: Fn(&'a ::Input) -> ::Type<'a>, + O: IntoOptionBytes, + F: Fn(&::Input) -> &O, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { 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, >::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 ::Input) -> ::Type<'a>, + F: Fn(&::Input) -> &O, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { 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, >::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); } diff --git a/libafl/src/mutators/numeric.rs b/libafl/src/mutators/numeric.rs index d226f2ce4b..748fd64faf 100644 --- a/libafl/src/mutators/numeric.rs +++ b/libafl/src/mutators/numeric.rs @@ -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 = tuple_list_type!( - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator, - MappedInputFunctionMappingMutator,F1,I> +pub type MappedIntMutatorsType = tuple_list_type!( + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator, + MappingMutator,F1> ); /// Mapped mutators for integer-like inputs @@ -91,15 +87,13 @@ pub type MappedIntMutatorsType = tuple_list_type!( pub fn mapped_int_mutators( current_input_mapper: F1, input_from_corpus_mapper: F2, -) -> MappedIntMutatorsType +) -> MappedIntMutatorsType 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 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(&mut self, rand: &mut R) { + (*self).randomize(rand); + } +} + /// Bitflip mutation for integer-like inputs #[derive(Debug)] pub struct BitFlipMutator; @@ -374,17 +394,13 @@ impl MappedCrossoverMutator { } } -impl Mutator, S> for MappedCrossoverMutator +impl Mutator for MappedCrossoverMutator where S: HasRand + HasCorpus, for<'b> F: Fn(&'b ::Input) -> &'b I, I: Clone, { - fn mutate( - &mut self, - state: &mut S, - input: &mut ValueMutRefInput<'_, I>, - ) -> Result { + fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { 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) } } diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index b29139c0c2..79b27e7d05 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -850,6 +850,12 @@ impl HasLen for Vec { } } +impl HasLen for &mut T { + fn len(&self) -> usize { + self.deref().len() + } +} + /// Has a ref count pub trait HasRefCnt { /// The ref count