diff --git a/libafl/src/mutators/havoc_mutations.rs b/libafl/src/mutators/havoc_mutations.rs index 7399ba7930..f2d1c512e3 100644 --- a/libafl/src/mutators/havoc_mutations.rs +++ b/libafl/src/mutators/havoc_mutations.rs @@ -1,11 +1,12 @@ //! [`crate::mutators::Mutator`] collection equivalent to AFL++'s havoc mutations -use libafl_bolts::tuples::{Map, Merge}; -use tuple_list::{tuple_list, tuple_list_type}; +use libafl_bolts::{ + map_tuple_list_type, merge_tuple_list_type, + tuples::{tuple_list, tuple_list_type, Map, Merge}, +}; -use super::{MappingMutator, ToMappingMutator}; use crate::mutators::{ - mapping::{OptionalMutator, ToOptionalMutator}, + mapping::{ToMappingMutator, ToOptionalMutator}, mutations::{ BitFlipMutator, ByteAddMutator, ByteDecMutator, ByteFlipMutator, ByteIncMutator, ByteInterestingMutator, ByteNegMutator, ByteRandMutator, BytesCopyMutator, @@ -56,96 +57,22 @@ pub type MappedHavocCrossoverType = tuple_list_type!( ); /// Tuple type of the mutations that compose the Havoc mutator -pub type HavocMutationsType = tuple_list_type!( - BitFlipMutator, - ByteFlipMutator, - ByteIncMutator, - ByteDecMutator, - ByteNegMutator, - ByteRandMutator, - ByteAddMutator, - WordAddMutator, - DwordAddMutator, - QwordAddMutator, - ByteInterestingMutator, - WordInterestingMutator, - DwordInterestingMutator, - BytesDeleteMutator, - BytesDeleteMutator, - BytesDeleteMutator, - BytesDeleteMutator, - BytesExpandMutator, - BytesInsertMutator, - BytesRandInsertMutator, - BytesSetMutator, - BytesRandSetMutator, - BytesCopyMutator, - BytesInsertCopyMutator, - BytesSwapMutator, - CrossoverInsertMutator, - CrossoverReplaceMutator, -); +pub type HavocMutationsType = + merge_tuple_list_type!(HavocMutationsNoCrossoverType, HavocCrossoverType); /// Tuple type of the mutations that compose the Havoc mutator for mapped input types -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>, +pub type MappedHavocMutationsType = map_tuple_list_type!( + merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType), + ToMappingMutator ); /// 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!( - 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>, +pub type OptionMappedHavocMutationsType = map_tuple_list_type!( + map_tuple_list_type!( + merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType), + ToOptionalMutator + ), + ToMappingMutator ); /// Get the mutations that compose the Havoc mutator (only applied to single inputs) diff --git a/libafl_bolts/src/shmem.rs b/libafl_bolts/src/shmem.rs index 5f1c00e7f2..7df2bbe154 100644 --- a/libafl_bolts/src/shmem.rs +++ b/libafl_bolts/src/shmem.rs @@ -624,12 +624,12 @@ where /// Is needed on top. #[cfg(all(unix, feature = "std", not(target_os = "haiku")))] pub mod unix_shmem { - /// Mmap [`ShMem`] for Unix - #[cfg(not(target_os = "android"))] - pub use default::MmapShMem; /// Mmap [`ShMemProvider`] for Unix #[cfg(not(target_os = "android"))] pub use default::MmapShMemProvider; + /// Mmap [`ShMem`] for Unix + #[cfg(not(target_os = "android"))] + pub use default::{MmapShMem, MAX_MMAP_FILENAME_LEN}; #[cfg(doc)] use crate::shmem::{ShMem, ShMemProvider}; @@ -669,7 +669,8 @@ pub mod unix_shmem { Error, }; - const MAX_MMAP_FILENAME_LEN: usize = 20; + /// The size of the buffer of the filename of mmap mapped memory regions + pub const MAX_MMAP_FILENAME_LEN: usize = 20; /// Mmap-based The sharedmap impl for unix using [`shm_open`] and [`mmap`]. /// Default on `MacOS` and `iOS`, where we need a central point to unmap diff --git a/libafl_bolts/src/tuples.rs b/libafl_bolts/src/tuples.rs index f9497799a7..4c9b5c78aa 100644 --- a/libafl_bolts/src/tuples.rs +++ b/libafl_bolts/src/tuples.rs @@ -833,6 +833,81 @@ macro_rules! tuple_for_each_mut { }; } +/// Maps the types of a mapping with a [`MappingFunctor`] +/// +/// ```rust +/// use libafl_bolts::{ +/// map_tuple_list_type, +/// tuples::{MappingFunctor, Map, tuple_list, tuple_list_type} +/// }; +/// +/// struct Wrapper(T); +/// struct MyMapper; +/// +/// impl MappingFunctor for MyMapper { +/// type Output = Wrapper; +/// +/// fn apply(&mut self, from: T) -> >::Output { +/// Wrapper(from) +/// } +/// } +/// +/// struct A; +/// struct B; +/// struct C; +/// +/// type OrigType = tuple_list_type!(A, B, C); +/// type MappedType = map_tuple_list_type!(OrigType, MyMapper); +/// let orig: OrigType = tuple_list!(A, B, C); +/// let _mapped: MappedType = orig.map(MyMapper); +/// ``` +#[macro_export] +macro_rules! map_tuple_list_type { + ($Tuple:ty, $Mapper:ty) => { + <$Tuple as $crate::tuples::Map<$Mapper>>::MapResult + }; +} + +/// Merges the types of two merged [`tuple_list!`]s +/// +/// ```rust +/// use libafl_bolts::{merge_tuple_list_type, tuples::{Merge, tuple_list, tuple_list_type}}; +/// +/// struct A; +/// struct B; +/// struct C; +/// struct D; +/// struct E; +/// +/// type Lhs = tuple_list_type!(A, B, C); +/// type Rhs = tuple_list_type!(D, E); +/// type Merged = merge_tuple_list_type!(Lhs, Rhs); +/// +/// let lhs: Lhs = tuple_list!(A, B, C); +/// let rhs: Rhs = tuple_list!(D, E); +/// let _merged: Merged = lhs.merge(rhs); +/// ``` +#[macro_export] +macro_rules! merge_tuple_list_type { + // Base case: when only two types are provided, apply the Merge trait directly + ($Type1:ty) => { + $Type1 + }; + + // Base case: when only two types are provided, apply the Merge trait directly + ($Type1:ty, $Type2:ty) => { + <$Type1 as $crate::tuples::Merge<$Type2>>::MergeResult + }; + + // Recursive case: when more than two types are provided + ($Type1:ty, $Type2:ty, $( $rest:ty ),+) => { + merge_tuple_list_type!( + <$Type1 as $crate::tuples::Merge<$Type2>>::MergeResult, + $( $rest ),+ + ) + }; +} + /* // Define trait and implement it for several primitive types. @@ -864,11 +939,13 @@ impl PlusOne for (Head, Tail) where #[cfg(test)] mod test { + use core::marker::PhantomData; + use tuple_list::{tuple_list, tuple_list_type}; #[cfg(feature = "alloc")] use crate::ownedref::OwnedMutSlice; - use crate::tuples::{type_eq, Map, MappingFunctor}; + use crate::tuples::{type_eq, Map, MappingFunctor, Merge}; #[test] // for type name tests @@ -916,9 +993,11 @@ mod test { #[test] fn test_mapper() { struct W(T); - struct MyMapper; - impl MappingFunctor for MyMapper { + // PhantomData shows how to deal with mappers that have generics + struct ExampleMapper

(PhantomData

); + + impl MappingFunctor for ExampleMapper

{ type Output = W; fn apply(&mut self, from: T) -> Self::Output { @@ -930,12 +1009,40 @@ mod test { struct B; struct C; - let orig = tuple_list!(A, B, C); - let mapped = orig.map(MyMapper); + type OrigType = tuple_list_type!(A, B, C); + type MappedType = map_tuple_list_type!(OrigType, ExampleMapper); + let orig: OrigType = tuple_list!(A, B, C); + let _mapped: MappedType = orig.map(ExampleMapper(PhantomData::)); + } - // this won't compile if the mapped type is not correct - #[expect(clippy::no_effect_underscore_binding)] - let _type_assert: tuple_list_type!(W, W, W) = mapped; + #[test] + fn test_merge() { + struct A; + struct B; + struct C; + struct D; + struct E; + + type Lhs = tuple_list_type!(A, B, C); + type Rhs = tuple_list_type!(D, E); + type Merged = merge_tuple_list_type!(Lhs, Rhs); + type IndividuallyMergedPre = merge_tuple_list_type!( + tuple_list_type!(A), + tuple_list_type!(B), + tuple_list_type!(C), + Rhs + ); + type IndividuallyMergedPost = + merge_tuple_list_type!(Lhs, tuple_list_type!(D), tuple_list_type!(E)); + type MergedCloned = merge_tuple_list_type!(Merged); + + let lhs: Lhs = tuple_list!(A, B, C); + let rhs: Rhs = tuple_list!(D, E); + let merged: Merged = lhs.merge(rhs); + let merged: IndividuallyMergedPre = merged; + let merged: IndividuallyMergedPost = merged; + #[allow(clippy::no_effect_underscore_binding)] + let _merged: MergedCloned = merged; } /// Function that tests the tuple macros