Add macros to libafl_bolts tuples for mapping and merging types (#2788)
* Add macros * Use the macros for havoc_mutations * Fix docs * improve merge_tuple_list_type to accept n items
This commit is contained in:
parent
03f7fc93ad
commit
54202c3ef3
@ -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<F, O> = 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<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>,
|
||||
pub type MappedHavocMutationsType<F1, F2, O> = map_tuple_list_type!(
|
||||
merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,O>),
|
||||
ToMappingMutator<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, 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>,
|
||||
pub type OptionMappedHavocMutationsType<F1, F2, O> = map_tuple_list_type!(
|
||||
map_tuple_list_type!(
|
||||
merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,O>),
|
||||
ToOptionalMutator
|
||||
),
|
||||
ToMappingMutator<F1>
|
||||
);
|
||||
|
||||
/// Get the mutations that compose the Havoc mutator (only applied to single inputs)
|
||||
|
@ -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
|
||||
|
@ -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>(T);
|
||||
/// struct MyMapper;
|
||||
///
|
||||
/// impl<T> MappingFunctor<T> for MyMapper {
|
||||
/// type Output = Wrapper<T>;
|
||||
///
|
||||
/// fn apply(&mut self, from: T) -> <Self as MappingFunctor<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<Head, Tail> 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>(T);
|
||||
struct MyMapper;
|
||||
|
||||
impl<T> MappingFunctor<T> for MyMapper {
|
||||
// PhantomData shows how to deal with mappers that have generics
|
||||
struct ExampleMapper<P>(PhantomData<P>);
|
||||
|
||||
impl<T, P> MappingFunctor<T> for ExampleMapper<P> {
|
||||
type Output = W<T>;
|
||||
|
||||
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<usize>);
|
||||
let orig: OrigType = tuple_list!(A, B, C);
|
||||
let _mapped: MappedType = orig.map(ExampleMapper(PhantomData::<usize>));
|
||||
}
|
||||
|
||||
// this won't compile if the mapped type is not correct
|
||||
#[expect(clippy::no_effect_underscore_binding)]
|
||||
let _type_assert: tuple_list_type!(W<A>, W<B>, W<C>) = 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user