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
|
//! [`crate::mutators::Mutator`] collection equivalent to AFL++'s havoc mutations
|
||||||
|
|
||||||
use libafl_bolts::tuples::{Map, Merge};
|
use libafl_bolts::{
|
||||||
use tuple_list::{tuple_list, tuple_list_type};
|
map_tuple_list_type, merge_tuple_list_type,
|
||||||
|
tuples::{tuple_list, tuple_list_type, Map, Merge},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{MappingMutator, ToMappingMutator};
|
|
||||||
use crate::mutators::{
|
use crate::mutators::{
|
||||||
mapping::{OptionalMutator, ToOptionalMutator},
|
mapping::{ToMappingMutator, ToOptionalMutator},
|
||||||
mutations::{
|
mutations::{
|
||||||
BitFlipMutator, ByteAddMutator, ByteDecMutator, ByteFlipMutator, ByteIncMutator,
|
BitFlipMutator, ByteAddMutator, ByteDecMutator, ByteFlipMutator, ByteIncMutator,
|
||||||
ByteInterestingMutator, ByteNegMutator, ByteRandMutator, BytesCopyMutator,
|
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
|
/// Tuple type of the mutations that compose the Havoc mutator
|
||||||
pub type HavocMutationsType = tuple_list_type!(
|
pub type HavocMutationsType =
|
||||||
BitFlipMutator,
|
merge_tuple_list_type!(HavocMutationsNoCrossoverType, HavocCrossoverType);
|
||||||
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,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Tuple type of the mutations that compose the Havoc mutator for mapped input types
|
/// Tuple type of the mutations that compose the Havoc mutator for mapped input types
|
||||||
pub type MappedHavocMutationsType<F1, F2, O> = tuple_list_type!(
|
pub type MappedHavocMutationsType<F1, F2, O> = map_tuple_list_type!(
|
||||||
MappingMutator<BitFlipMutator, F1>,
|
merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,O>),
|
||||||
MappingMutator<ByteFlipMutator, F1>,
|
ToMappingMutator<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
|
/// 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!(
|
pub type OptionMappedHavocMutationsType<F1, F2, O> = map_tuple_list_type!(
|
||||||
MappingMutator<OptionalMutator<BitFlipMutator>, F1>,
|
map_tuple_list_type!(
|
||||||
MappingMutator<OptionalMutator<ByteFlipMutator>, F1>,
|
merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,O>),
|
||||||
MappingMutator<OptionalMutator<ByteIncMutator>, F1>,
|
ToOptionalMutator
|
||||||
MappingMutator<OptionalMutator<ByteDecMutator>, F1>,
|
),
|
||||||
MappingMutator<OptionalMutator<ByteNegMutator>, F1>,
|
ToMappingMutator<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)
|
/// Get the mutations that compose the Havoc mutator (only applied to single inputs)
|
||||||
|
@ -624,12 +624,12 @@ where
|
|||||||
/// Is needed on top.
|
/// Is needed on top.
|
||||||
#[cfg(all(unix, feature = "std", not(target_os = "haiku")))]
|
#[cfg(all(unix, feature = "std", not(target_os = "haiku")))]
|
||||||
pub mod unix_shmem {
|
pub mod unix_shmem {
|
||||||
/// Mmap [`ShMem`] for Unix
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
pub use default::MmapShMem;
|
|
||||||
/// Mmap [`ShMemProvider`] for Unix
|
/// Mmap [`ShMemProvider`] for Unix
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
pub use default::MmapShMemProvider;
|
pub use default::MmapShMemProvider;
|
||||||
|
/// Mmap [`ShMem`] for Unix
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
pub use default::{MmapShMem, MAX_MMAP_FILENAME_LEN};
|
||||||
|
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use crate::shmem::{ShMem, ShMemProvider};
|
use crate::shmem::{ShMem, ShMemProvider};
|
||||||
@ -669,7 +669,8 @@ pub mod unix_shmem {
|
|||||||
Error,
|
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`].
|
/// 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
|
/// 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.
|
// Define trait and implement it for several primitive types.
|
||||||
@ -864,11 +939,13 @@ impl<Head, Tail> PlusOne for (Head, Tail) where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use tuple_list::{tuple_list, tuple_list_type};
|
use tuple_list::{tuple_list, tuple_list_type};
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use crate::ownedref::OwnedMutSlice;
|
use crate::ownedref::OwnedMutSlice;
|
||||||
use crate::tuples::{type_eq, Map, MappingFunctor};
|
use crate::tuples::{type_eq, Map, MappingFunctor, Merge};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// for type name tests
|
// for type name tests
|
||||||
@ -916,9 +993,11 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_mapper() {
|
fn test_mapper() {
|
||||||
struct W<T>(T);
|
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>;
|
type Output = W<T>;
|
||||||
|
|
||||||
fn apply(&mut self, from: T) -> Self::Output {
|
fn apply(&mut self, from: T) -> Self::Output {
|
||||||
@ -930,12 +1009,40 @@ mod test {
|
|||||||
struct B;
|
struct B;
|
||||||
struct C;
|
struct C;
|
||||||
|
|
||||||
let orig = tuple_list!(A, B, C);
|
type OrigType = tuple_list_type!(A, B, C);
|
||||||
let mapped = orig.map(MyMapper);
|
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
|
#[test]
|
||||||
#[expect(clippy::no_effect_underscore_binding)]
|
fn test_merge() {
|
||||||
let _type_assert: tuple_list_type!(W<A>, W<B>, W<C>) = mapped;
|
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
|
/// Function that tests the tuple macros
|
||||||
|
Loading…
x
Reference in New Issue
Block a user