From 502929d967a55dc203077e1e6fff395cc985dacd Mon Sep 17 00:00:00 2001 From: "Dongjia \"toka\" Zhang" Date: Sat, 4 May 2024 23:11:00 +0200 Subject: [PATCH] Separate map observers (#2143) * rename * rename * fmt * fix * fmt * separate observers * doc fx --- libafl/src/observers/map.rs | 2675 ---------------------- libafl/src/observers/map/const_map.rs | 313 +++ libafl/src/observers/map/hitcount_map.rs | 583 +++++ libafl/src/observers/map/mod.rs | 932 ++++++++ libafl/src/observers/map/multi_map.rs | 356 +++ libafl/src/observers/map/owned_map.rs | 251 ++ libafl/src/observers/map/variable_map.rs | 349 +++ libafl/src/observers/mod.rs | 7 +- 8 files changed, 2786 insertions(+), 2680 deletions(-) delete mode 100644 libafl/src/observers/map.rs create mode 100644 libafl/src/observers/map/const_map.rs create mode 100644 libafl/src/observers/map/hitcount_map.rs create mode 100644 libafl/src/observers/map/mod.rs create mode 100644 libafl/src/observers/map/multi_map.rs create mode 100644 libafl/src/observers/map/owned_map.rs create mode 100644 libafl/src/observers/map/variable_map.rs diff --git a/libafl/src/observers/map.rs b/libafl/src/observers/map.rs deleted file mode 100644 index c62fc61a04..0000000000 --- a/libafl/src/observers/map.rs +++ /dev/null @@ -1,2675 +0,0 @@ -//! The `MapObserver` provides access a map, usually injected into the target - -use alloc::{borrow::Cow, vec::Vec}; -use core::{ - fmt::Debug, - hash::{Hash, Hasher}, - iter::Flatten, - mem::size_of, - ops::{Deref, DerefMut}, - slice::{self, Iter, IterMut}, -}; - -use ahash::RandomState; -use libafl_bolts::{ - ownedref::{OwnedMutPtr, OwnedMutSlice}, - AsIter, AsIterMut, AsSlice, AsSliceMut, HasLen, Named, Truncate, -}; -use meminterval::IntervalTree; -use num_traits::Bounded; -use serde::{Deserialize, Serialize}; - -use crate::{ - executors::ExitKind, - inputs::UsesInput, - observers::{DifferentialObserver, Observer, ObserversTuple}, - Error, -}; - -/// Hitcounts class lookup -static COUNT_CLASS_LOOKUP: [u8; 256] = [ - 0, 1, 2, 4, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, -]; - -/// Hitcounts class lookup for 16-byte values -static mut COUNT_CLASS_LOOKUP_16: Vec = vec![]; - -/// Initialize the 16-byte hitcounts map -/// -/// # Safety -/// -/// Calling this from multiple threads may be racey and hence leak 65k mem -fn init_count_class_16() { - unsafe { - if !COUNT_CLASS_LOOKUP_16.is_empty() { - return; - } - - COUNT_CLASS_LOOKUP_16 = vec![0; 65536]; - for i in 0..256 { - for j in 0..256 { - COUNT_CLASS_LOOKUP_16[(i << 8) + j] = - (u16::from(COUNT_CLASS_LOOKUP[i]) << 8) | u16::from(COUNT_CLASS_LOOKUP[j]); - } - } - } -} - -/// Trait marker which indicates that this [`MapObserver`] is tracked for indices or novelties. -/// Implementors of feedbacks similar to [`crate::feedbacks::MapFeedback`] may wish to use this to -/// ensure that edge metadata is recorded as is appropriate for the provided observer. -/// -/// If you get a type constraint failure for your map due to this type being unfulfilled, you must -/// call [`CanTrack::track_indices`] or [`CanTrack::track_novelties`] **at -/// the initialisation site of your map**. -/// -/// This trait allows various components which interact with map metadata to ensure that the -/// information they need is actually recorded by the map feedback. -/// For example, if you are using [`crate::schedulers::MinimizerScheduler`]: -/// ``` -/// # use libafl::corpus::InMemoryCorpus; -/// # use libafl::feedbacks::{Feedback, MapFeedbackMetadata}; -/// use libafl::feedbacks::MaxMapFeedback; -/// # use libafl::inputs::BytesInput; -/// use libafl::observers::{StdMapObserver, CanTrack}; -/// use libafl::schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}; -/// # use libafl::state::StdState; -/// # use libafl_bolts::serdeany::RegistryBuilder; -/// # -/// # #[cfg(any(not(feature = "serdeany_autoreg"), miri))] -/// # unsafe { MapFeedbackMetadata::::register() } -/// # #[cfg(not(feature = "std"))] -/// # #[no_mangle] -/// # pub extern "C" fn external_current_millis() -> u64 { 0 } -/// -/// use libafl_bolts::ownedref::OwnedMutSlice; -/// # use libafl_bolts::rands::StdRand; -/// -/// // initialise your map as necessary -/// let edges_observer = StdMapObserver::from_ownedref("edges", OwnedMutSlice::from(vec![0u8; 16])); -/// // inform the feedback to track indices (required by IndexesLenTimeMinimizerScheduler), but not novelties -/// // this *MUST* be done before it is passed to MaxMapFeedback! -/// let edges_observer = edges_observer.track_indices(); -/// -/// // init the feedback -/// let mut feedback = MaxMapFeedback::new(&edges_observer); -/// # -/// # // init the state -/// # let mut state = StdState::new( -/// # StdRand::with_seed(0), -/// # InMemoryCorpus::::new(), -/// # InMemoryCorpus::new(), -/// # &mut feedback, -/// # &mut () -/// # ).unwrap(); -/// # feedback.init_state(&mut state).unwrap(); -/// -/// let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); -/// # scheduler.cull(&state).unwrap(); -/// ``` -/// -/// [`MapObserver`] implementors: see [`StdMapObserver`] for an example implementation. -pub trait CanTrack { - /// The resulting type of enabling index tracking. - type WithIndexTracking: CanTrack; - /// The resulting type of enabling novelty tracking. - type WithNoveltiesTracking: CanTrack; - - /// Whether indices should be tracked for this [`MapObserver`]. - const INDICES: bool; - /// Whether novelties should be tracked for this [`MapObserver`]. - const NOVELTIES: bool; - - /// Convert this map observer into one that tracks indices. - fn track_indices(self) -> Self::WithIndexTracking; - /// Convert this map observer into one that tracks novelties. - fn track_novelties(self) -> Self::WithNoveltiesTracking; -} - -/// Struct which wraps [`MapObserver`] instances to explicitly give them tracking data. -/// -/// # Safety -/// -/// This is a bit of a magic structure. We pass it to the observer tuple as itself, but when its -/// referred to with `match_name`, there is a cast from this type to its inner type. This is -/// *guaranteed to be safe* by `#[repr(transparent)]`. -#[derive(Copy, Clone, Debug, Deserialize, Serialize)] -pub struct ExplicitTracking(T); - -impl CanTrack for ExplicitTracking { - type WithIndexTracking = ExplicitTracking; - type WithNoveltiesTracking = ExplicitTracking; - const INDICES: bool = ITH; - const NOVELTIES: bool = NTH; - - fn track_indices(self) -> Self::WithIndexTracking { - ExplicitTracking::(self.0) - } - - fn track_novelties(self) -> Self::WithNoveltiesTracking { - ExplicitTracking::(self.0) - } -} - -impl AsRef for ExplicitTracking { - fn as_ref(&self) -> &T { - &self.0 - } -} - -impl AsMut for ExplicitTracking { - fn as_mut(&mut self) -> &mut T { - &mut self.0 - } -} - -impl Named for ExplicitTracking -where - T: Named, -{ - fn name(&self) -> &Cow<'static, str> { - self.0.name() - } -} - -impl Observer for ExplicitTracking -where - S: UsesInput, - T: Observer, -{ - fn flush(&mut self) -> Result<(), Error> { - self.0.flush() - } - - fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { - self.0.pre_exec(state, input) - } - - fn post_exec( - &mut self, - state: &mut S, - input: &S::Input, - exit_kind: &ExitKind, - ) -> Result<(), Error> { - self.0.post_exec(state, input, exit_kind) - } - - fn pre_exec_child(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { - self.0.pre_exec_child(state, input) - } - - fn post_exec_child( - &mut self, - state: &mut S, - input: &S::Input, - exit_kind: &ExitKind, - ) -> Result<(), Error> { - self.0.post_exec_child(state, input, exit_kind) - } - - fn observes_stdout(&self) -> bool { - self.0.observes_stdout() - } - - fn observes_stderr(&self) -> bool { - self.0.observes_stderr() - } - - fn observe_stdout(&mut self, stdout: &[u8]) { - self.0.observe_stdout(stdout); - } - - fn observe_stderr(&mut self, stderr: &[u8]) { - self.0.observe_stderr(stderr); - } -} - -impl DifferentialObserver - for ExplicitTracking -where - OTA: ObserversTuple, - OTB: ObserversTuple, - S: UsesInput, - T: DifferentialObserver, -{ - fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { - self.as_mut().pre_observe_first(observers) - } - - fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { - self.as_mut().post_observe_first(observers) - } - - fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { - self.as_mut().pre_observe_second(observers) - } - - fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { - self.as_mut().post_observe_second(observers) - } -} - -/// Module which holds the necessary functions and types for map-relevant macros, namely -/// [`crate::require_index_tracking`] and [`crate::require_novelties_tracking`]. -pub mod macros { - pub use const_format::{concatcp, str_repeat}; - pub use const_panic::{concat_panic, FmtArg}; - - /// Use in the constructor of your component which requires index tracking of a - /// [`super::MapObserver`]. See [`super::CanTrack`] for details. - /// - /// As an example, if you are developing the type `MyCustomScheduler` which requires novelty - /// tracking, use this in your constructor: - /// ``` - /// # use libafl::observers::{MapObserver, CanTrack}; - /// # use libafl::require_index_tracking; - /// # use core::marker::PhantomData; - /// # - /// # struct MyCustomScheduler { - /// # phantom: PhantomData<(C, O)>, - /// # } - /// # - /// impl MyCustomScheduler where O: MapObserver, C: CanTrack + AsRef { - /// pub fn new(obs: &C) -> Self { - /// require_index_tracking!("MyCustomScheduler", C); - /// todo!("Construct your type") - /// } - /// } - /// ``` - #[macro_export] - macro_rules! require_index_tracking { - ($name: literal, $obs: ident) => { - struct SanityCheck { - phantom: ::core::marker::PhantomData, - } - - impl SanityCheck { - #[rustfmt::skip] - const MESSAGE: &'static str = { - const LINE_OFFSET: usize = line!().ilog10() as usize + 2; - const SPACING: &str = $crate::observers::map::macros::str_repeat!(" ", LINE_OFFSET); - $crate::observers::map::macros::concatcp!( - "\n", - SPACING, "|\n", - SPACING, "= note: index tracking is required by ", $name, "\n", - SPACING, "= note: see the documentation of CanTrack for details\n", - SPACING, "|\n", - SPACING, "= hint: call `.track_indices()` on the map observer passed to ", $name, " at the point where it is defined\n", - SPACING, "|\n", - SPACING, "| ", - ) - }; - const TRACKING_SANITY: bool = { - if !O::INDICES { - panic!("{}", Self::MESSAGE) - } else { - true - } - }; - - #[inline(always)] - fn check_sanity() { - if !Self::TRACKING_SANITY { - unreachable!("{}", Self::MESSAGE); - } - } - } - SanityCheck::<$obs>::check_sanity(); // check that tracking is enabled for this map - }; - } - - /// Use in the constructor of your component which requires novelties tracking of a - /// [`super::MapObserver`]. See [`super::CanTrack`] for details on the concept. - /// - /// As an example, if you are developing the type `MyCustomScheduler` which requires novelty - /// tracking, use this in your constructor: - /// ``` - /// # use libafl::observers::{MapObserver, CanTrack}; - /// # use libafl::require_novelties_tracking; - /// # use core::marker::PhantomData; - /// # - /// # struct MyCustomScheduler { - /// # phantom: PhantomData<(C, O)>, - /// # } - /// # - /// impl MyCustomScheduler where O: MapObserver, C: CanTrack + AsRef { - /// pub fn new(obs: &C) -> Self { - /// require_novelties_tracking!("MyCustomScheduler", C); - /// todo!("Construct your type") - /// } - /// } - /// ``` - #[macro_export] - macro_rules! require_novelties_tracking { - ($name: literal, $obs: ident) => { - struct SanityCheck { - phantom: ::core::marker::PhantomData, - } - - impl SanityCheck { - #[rustfmt::skip] - const MESSAGE: &'static str = { - const LINE_OFFSET: usize = line!().ilog10() as usize + 2; - const SPACING: &str = - $crate::observers::map::macros::str_repeat!(" ", LINE_OFFSET); - $crate::observers::map::macros::concatcp!( - "\n", - SPACING, "|\n", - SPACING, "= note: novelty tracking is required by ", $name, "\n", - SPACING, "= note: see the documentation of CanTrack for details\n", - SPACING, "|\n", - SPACING, "= hint: call `.track_novelties()` on the map observer passed to ", $name, " at the point where it is defined\n", - SPACING, "|\n", - SPACING, "| ", - ) - }; - const TRACKING_SANITY: bool = { - if !O::NOVELTIES { - panic!("{}", Self::MESSAGE) - } else { - true - } - }; - - #[inline(always)] - fn check_sanity() { - if !Self::TRACKING_SANITY { - unreachable!("{}", Self::MESSAGE); - } - } - } - SanityCheck::<$obs>::check_sanity(); // check that tracking is enabled for this map - }; - } -} - -/// A [`MapObserver`] observes the static map, as oftentimes used for AFL-like coverage information -/// -/// When referring to this type in a constraint (e.g. `O: MapObserver`), ensure that you only refer -/// to instances of a second type, e.g. `C: AsRef` or `A: AsMut`. Map observer instances are -/// passed around in a way that may be potentially wrapped by e.g. [`ExplicitTracking`] as a way to -/// encode metadata into the type. This is an unfortunate additional requirement that we can't get -/// around without specialization. -/// -/// See [`crate::require_index_tracking`] for an example of how to do so. -/// -/// TODO: enforce `iter() -> AssociatedTypeIter` when generic associated types stabilize -pub trait MapObserver: - HasLen + Named + Serialize + serde::de::DeserializeOwned + AsRef + AsMut + Hash -// where -// for<'it> &'it Self: IntoIterator -{ - /// Type of each entry in this map - type Entry: Bounded + PartialEq + Default + Copy + Debug + Hash + 'static; - - /// Get the value at `idx` - fn get(&self, idx: usize) -> Self::Entry; - - /// Set the value at `idx` - fn set(&mut self, idx: usize, val: Self::Entry); - - /// Get the number of usable entries in the map (all by default) - fn usable_count(&self) -> usize; - - /// Count the set bytes in the map - fn count_bytes(&self) -> u64; - - /// Compute the hash of the map without needing to provide a hasher - fn hash_simple(&self) -> u64; - - /// Get the initial value for `reset()` - fn initial(&self) -> Self::Entry; - - /// Reset the map - fn reset_map(&mut self) -> Result<(), Error>; - - /// Get these observer's contents as [`Vec`] - fn to_vec(&self) -> Vec; - - /// Get the number of set entries with the specified indexes - fn how_many_set(&self, indexes: &[usize]) -> usize; -} - -impl CanTrack for M -where - M: MapObserver, -{ - type WithIndexTracking = ExplicitTracking; - type WithNoveltiesTracking = ExplicitTracking; - const INDICES: bool = false; - const NOVELTIES: bool = false; - - fn track_indices(self) -> Self::WithIndexTracking { - ExplicitTracking::(self) - } - - fn track_novelties(self) -> Self::WithNoveltiesTracking { - ExplicitTracking::(self) - } -} - -/// The Map Observer retrieves the state of a map, -/// that will get updated by the target. -/// A well-known example is the AFL-Style coverage map. -#[derive(Clone, Serialize, Deserialize, Debug)] -#[serde(bound = "T: serde::de::DeserializeOwned")] -#[allow(clippy::unsafe_derive_deserialize)] -pub struct StdMapObserver<'a, T, const DIFFERENTIAL: bool> -where - T: Default + Copy + 'static + Serialize, -{ - map: OwnedMutSlice<'a, T>, - initial: T, - name: Cow<'static, str>, -} - -impl<'a, S, T> Observer for StdMapObserver<'a, T, false> -where - S: UsesInput, - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - #[inline] - fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { - self.reset_map() - } -} - -impl<'a, S, T> Observer for StdMapObserver<'a, T, true> -where - S: UsesInput, - T: Bounded - + PartialEq - + Default - + Copy - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ -} - -impl<'a, T, const DIFFERENTIAL: bool> Named for StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, -{ - #[inline] - fn name(&self) -> &Cow<'static, str> { - &self.name - } -} - -impl<'a, T, const DIFFERENTIAL: bool> HasLen for StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, -{ - #[inline] - fn len(&self) -> usize { - self.map.as_slice().len() - } -} - -impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator for &'it StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Item = as Iterator>::Item; - type IntoIter = Iter<'it, T>; - - fn into_iter(self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice()[..cnt].iter() - } -} - -impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator - for &'it mut StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Item = as Iterator>::Item; - type IntoIter = IterMut<'it, T>; - - fn into_iter(self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice_mut()[..cnt].iter_mut() - } -} - -impl<'a, T, const DIFFERENTIAL: bool> StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - /// Returns an iterator over the map. - pub fn iter(&self) -> Iter<'_, T> { - <&Self as IntoIterator>::into_iter(self) - } - - /// Returns a mutable iterator over the map. - pub fn iter_mut(&mut self) -> IterMut<'_, T> { - <&mut Self as IntoIterator>::into_iter(self) - } -} - -impl<'a, T, const DIFFERENTIAL: bool> Hash for StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - #[inline] - fn hash(&self, hasher: &mut H) { - self.as_slice().hash(hasher); - } -} - -impl<'a, T, const DIFFERENTIAL: bool> AsRef for StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Default + Copy + 'static + Serialize, -{ - fn as_ref(&self) -> &Self { - self - } -} - -impl<'a, T, const DIFFERENTIAL: bool> AsMut for StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Default + Copy + 'static + Serialize, -{ - fn as_mut(&mut self) -> &mut Self { - self - } -} - -impl<'a, T, const DIFFERENTIAL: bool> MapObserver for StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Entry = T; - - #[inline] - fn get(&self, pos: usize) -> T { - self.as_slice()[pos] - } - - fn set(&mut self, pos: usize, val: T) { - self.map.as_slice_mut()[pos] = val; - } - - /// Count the set bytes in the map - fn count_bytes(&self) -> u64 { - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice(); - let mut res = 0; - for x in &map[0..cnt] { - if *x != initial { - res += 1; - } - } - res - } - - #[inline] - fn usable_count(&self) -> usize { - self.as_slice().len() - } - - #[inline] - fn hash_simple(&self) -> u64 { - RandomState::with_seeds(0, 0, 0, 0).hash_one(self) - } - - #[inline] - fn initial(&self) -> T { - self.initial - } - - fn to_vec(&self) -> Vec { - self.as_slice().to_vec() - } - - /// Reset the map - #[inline] - fn reset_map(&mut self) -> Result<(), Error> { - // Normal memset, see https://rust.godbolt.org/z/Trs5hv - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice_mut(); - for x in &mut map[0..cnt] { - *x = initial; - } - Ok(()) - } - - fn how_many_set(&self, indexes: &[usize]) -> usize { - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice(); - let mut res = 0; - for i in indexes { - if *i < cnt && map[*i] != initial { - res += 1; - } - } - res - } -} - -impl<'a, T, const DIFFERENTIAL: bool> Truncate for StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Bounded - + PartialEq - + Default - + Copy - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - fn truncate(&mut self, new_len: usize) { - self.map.truncate(new_len); - } -} - -impl<'a, T, const DIFFERENTIAL: bool> Deref for StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, -{ - type Target = [T]; - fn deref(&self) -> &[T] { - &self.map - } -} - -impl<'a, T, const DIFFERENTIAL: bool> DerefMut for StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, -{ - fn deref_mut(&mut self) -> &mut [T] { - &mut self.map - } -} - -impl<'a, T, const DIFFERENTIAL: bool> StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, -{ - /// Creates a new [`MapObserver`] - /// - /// # Safety - /// Will get a pointer to the map and dereference it at any point in time. - /// The map must not move in memory! - #[must_use] - unsafe fn maybe_differential(name: S, map: &'a mut [T]) -> Self - where - S: Into>, - { - let len = map.len(); - let ptr = map.as_mut_ptr(); - Self::maybe_differential_from_mut_ptr(name, ptr, len) - } - - /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] - #[must_use] - fn maybe_differential_from_mut_slice(name: S, map: OwnedMutSlice<'a, T>) -> Self - where - S: Into>, - { - StdMapObserver { - name: name.into(), - map, - initial: T::default(), - } - } - - /// Creates a new [`MapObserver`] with an owned map - #[must_use] - fn maybe_differential_owned(name: S, map: Vec) -> Self - where - S: Into>, - { - Self { - map: OwnedMutSlice::from(map), - name: name.into(), - initial: T::default(), - } - } - - /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] map. - /// - /// # Safety - /// Will dereference the owned slice with up to len elements. - #[must_use] - fn maybe_differential_from_ownedref(name: S, map: OwnedMutSlice<'a, T>) -> Self - where - S: Into>, - { - Self { - map, - name: name.into(), - initial: T::default(), - } - } - - /// Creates a new [`MapObserver`] from a raw pointer - /// - /// # Safety - /// Will dereference the `map_ptr` with up to len elements. - unsafe fn maybe_differential_from_mut_ptr(name: S, map_ptr: *mut T, len: usize) -> Self - where - S: Into>, - { - Self::maybe_differential_from_mut_slice( - name, - OwnedMutSlice::from_raw_parts_mut(map_ptr, len), - ) - } - - /// Gets the initial value for this map, mutably - pub fn initial_mut(&mut self) -> &mut T { - &mut self.initial - } - - /// Gets the backing for this map - pub fn map(&self) -> &OwnedMutSlice<'a, T> { - &self.map - } - - /// Gets the backing for this map mutably - pub fn map_mut(&mut self) -> &mut OwnedMutSlice<'a, T> { - &mut self.map - } -} - -impl<'a, T> StdMapObserver<'a, T, false> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, -{ - /// Creates a new [`MapObserver`] - /// - /// # Safety - /// The observer will keep a pointer to the map. - /// Hence, the map may never move in memory. - #[must_use] - pub unsafe fn new(name: S, map: &'a mut [T]) -> Self - where - S: Into>, - { - Self::maybe_differential(name, map) - } - - /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] - pub fn from_mut_slice(name: S, map: OwnedMutSlice<'a, T>) -> Self - where - S: Into>, - { - Self::maybe_differential_from_mut_slice(name, map) - } - - /// Creates a new [`MapObserver`] with an owned map - #[must_use] - pub fn owned(name: S, map: Vec) -> Self - where - S: Into>, - { - Self::maybe_differential_owned(name, map) - } - - /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] map. - /// - /// # Note - /// Will dereference the owned slice with up to len elements. - #[must_use] - pub fn from_ownedref(name: S, map: OwnedMutSlice<'a, T>) -> Self - where - S: Into>, - { - Self::maybe_differential_from_ownedref(name, map) - } - - /// Creates a new [`MapObserver`] from a raw pointer - /// - /// # Safety - /// Will dereference the `map_ptr` with up to len elements. - pub unsafe fn from_mut_ptr(name: S, map_ptr: *mut T, len: usize) -> Self - where - S: Into>, - { - Self::maybe_differential_from_mut_ptr(name, map_ptr, len) - } -} - -impl<'a, T> StdMapObserver<'a, T, true> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, -{ - /// Creates a new [`MapObserver`] in differential mode - /// - /// # Safety - /// Will get a pointer to the map and dereference it at any point in time. - /// The map must not move in memory! - #[must_use] - pub unsafe fn differential(name: S, map: &'a mut [T]) -> Self - where - S: Into>, - { - Self::maybe_differential(name, map) - } - - /// Creates a new [`MapObserver`] with an owned map in differential mode - #[must_use] - pub fn differential_owned(name: S, map: Vec) -> Self - where - S: Into>, - { - Self::maybe_differential_owned(name, map) - } - - /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] map in differential mode. - /// - /// # Note - /// Will dereference the owned slice with up to len elements. - #[must_use] - pub fn differential_from_ownedref(name: S, map: OwnedMutSlice<'a, T>) -> Self - where - S: Into>, - { - Self::maybe_differential_from_ownedref(name, map) - } - - /// Creates a new [`MapObserver`] from a raw pointer in differential mode - /// - /// # Safety - /// Will dereference the `map_ptr` with up to len elements. - pub unsafe fn differential_from_mut_ptr(name: S, map_ptr: *mut T, len: usize) -> Self - where - S: Into>, - { - Self::maybe_differential_from_mut_ptr(name, map_ptr, len) - } -} - -impl<'a, OTA, OTB, S, T> DifferentialObserver for StdMapObserver<'a, T, true> -where - OTA: ObserversTuple, - OTB: ObserversTuple, - S: UsesInput, - T: Bounded - + PartialEq - + Default - + Copy - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ -} - -/// Use a const size to speedup `Feedback::is_interesting` when the user can -/// know the size of the map at compile time. -#[derive(Serialize, Deserialize, Debug)] -#[serde(bound = "T: serde::de::DeserializeOwned")] -#[allow(clippy::unsafe_derive_deserialize)] -pub struct ConstMapObserver<'a, T, const N: usize> -where - T: Default + Copy + 'static + Serialize, -{ - map: OwnedMutSlice<'a, T>, - initial: T, - name: Cow<'static, str>, -} - -impl<'a, S, T, const N: usize> Observer for ConstMapObserver<'a, T, N> -where - S: UsesInput, - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, - Self: MapObserver, -{ - #[inline] - fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { - self.reset_map() - } -} - -impl<'a, T, const N: usize> Named for ConstMapObserver<'a, T, N> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, -{ - #[inline] - fn name(&self) -> &Cow<'static, str> { - &self.name - } -} - -impl<'a, T, const N: usize> HasLen for ConstMapObserver<'a, T, N> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, -{ - #[inline] - fn len(&self) -> usize { - N - } -} - -impl<'a, 'it, T, const N: usize> IntoIterator for &'it ConstMapObserver<'a, T, N> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Item = as Iterator>::Item; - type IntoIter = Iter<'it, T>; - - fn into_iter(self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice()[..cnt].iter() - } -} - -impl<'a, 'it, T, const N: usize> IntoIterator for &'it mut ConstMapObserver<'a, T, N> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Item = as Iterator>::Item; - type IntoIter = IterMut<'it, T>; - - fn into_iter(self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice_mut()[..cnt].iter_mut() - } -} - -impl<'a, T, const N: usize> ConstMapObserver<'a, T, N> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - /// Returns an iterator over the map. - pub fn iter(&self) -> Iter<'_, T> { - <&Self as IntoIterator>::into_iter(self) - } - - /// Returns a mutable iterator over the map. - pub fn iter_mut(&mut self) -> IterMut<'_, T> { - <&mut Self as IntoIterator>::into_iter(self) - } -} - -impl<'a, T, const N: usize> Hash for ConstMapObserver<'a, T, N> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - #[inline] - fn hash(&self, hasher: &mut H) { - self.as_slice().hash(hasher); - } -} -impl<'a, T, const N: usize> AsRef for ConstMapObserver<'a, T, N> -where - T: Default + Copy + 'static + Serialize, -{ - fn as_ref(&self) -> &Self { - self - } -} - -impl<'a, T, const N: usize> AsMut for ConstMapObserver<'a, T, N> -where - T: Default + Copy + 'static + Serialize, -{ - fn as_mut(&mut self) -> &mut Self { - self - } -} - -impl<'a, T, const N: usize> MapObserver for ConstMapObserver<'a, T, N> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Entry = T; - - #[inline] - fn initial(&self) -> T { - self.initial - } - - #[inline] - fn get(&self, idx: usize) -> T { - self.as_slice()[idx] - } - - #[inline] - fn set(&mut self, idx: usize, val: T) { - self.map.as_slice_mut()[idx] = val; - } - - /// Count the set bytes in the map - fn count_bytes(&self) -> u64 { - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice(); - let mut res = 0; - for x in &map[0..cnt] { - if *x != initial { - res += 1; - } - } - res - } - - fn usable_count(&self) -> usize { - self.as_slice().len() - } - - #[inline] - fn hash_simple(&self) -> u64 { - RandomState::with_seeds(0, 0, 0, 0).hash_one(self) - } - - /// Reset the map - #[inline] - fn reset_map(&mut self) -> Result<(), Error> { - // Normal memset, see https://rust.godbolt.org/z/Trs5hv - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice_mut(); - for x in &mut map[0..cnt] { - *x = initial; - } - Ok(()) - } - - fn to_vec(&self) -> Vec { - self.as_slice().to_vec() - } - - /// Get the number of set entries with the specified indexes - fn how_many_set(&self, indexes: &[usize]) -> usize { - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice(); - let mut res = 0; - for i in indexes { - if *i < cnt && map[*i] != initial { - res += 1; - } - } - res - } -} - -impl<'a, T, const N: usize> Deref for ConstMapObserver<'a, T, N> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, -{ - type Target = [T]; - fn deref(&self) -> &[T] { - &self.map - } -} - -impl<'a, T, const N: usize> DerefMut for ConstMapObserver<'a, T, N> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, -{ - fn deref_mut(&mut self) -> &mut [T] { - &mut self.map - } -} - -impl<'a, T, const N: usize> ConstMapObserver<'a, T, N> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, -{ - /// Creates a new [`MapObserver`] - /// - /// # Note - /// Will get a pointer to the map and dereference it at any point in time. - /// The map must not move in memory! - #[must_use] - pub fn new(name: &'static str, map: &'a mut [T]) -> Self { - assert!(map.len() >= N); - Self { - map: OwnedMutSlice::from(map), - name: Cow::from(name), - initial: T::default(), - } - } - - /// Creates a new [`MapObserver`] with an owned map - #[must_use] - pub fn owned(name: &'static str, map: Vec) -> Self { - assert!(map.len() >= N); - let initial = if map.is_empty() { T::default() } else { map[0] }; - Self { - map: OwnedMutSlice::from(map), - name: Cow::from(name), - initial, - } - } - - /// Creates a new [`MapObserver`] from a raw pointer - /// - /// # Safety - /// Will dereference the `map_ptr` with up to len elements. - pub unsafe fn from_mut_ptr(name: &'static str, map_ptr: *mut T) -> Self { - ConstMapObserver { - map: OwnedMutSlice::from_raw_parts_mut(map_ptr, N), - name: Cow::from(name), - initial: T::default(), - } - } -} - -/// Overlooking a variable bitmap -#[derive(Serialize, Deserialize, Debug)] -#[serde(bound = "T: serde::de::DeserializeOwned")] -#[allow(clippy::unsafe_derive_deserialize)] -pub struct VariableMapObserver<'a, T> -where - T: Default + Copy + 'static + Serialize + PartialEq + Bounded, -{ - map: OwnedMutSlice<'a, T>, - size: OwnedMutPtr, - initial: T, - name: Cow<'static, str>, -} - -impl<'a, S, T> Observer for VariableMapObserver<'a, T> -where - S: UsesInput, - T: Default - + Copy - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug - + Bounded - + PartialEq, - Self: MapObserver, -{ - #[inline] - fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { - self.reset_map() - } -} - -impl<'a, T> Named for VariableMapObserver<'a, T> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Bounded + PartialEq, -{ - #[inline] - fn name(&self) -> &Cow<'static, str> { - &self.name - } -} - -impl<'a, T> HasLen for VariableMapObserver<'a, T> -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + PartialEq + Bounded, -{ - #[inline] - fn len(&self) -> usize { - *self.size.as_ref() - } -} - -impl<'a, 'it, T> IntoIterator for &'it VariableMapObserver<'a, T> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug - + PartialEq - + Bounded, -{ - type Item = as Iterator>::Item; - type IntoIter = Iter<'it, T>; - - fn into_iter(self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice()[..cnt].iter() - } -} - -impl<'a, 'it, T> IntoIterator for &'it mut VariableMapObserver<'a, T> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug - + PartialEq - + Bounded, -{ - type Item = as Iterator>::Item; - type IntoIter = IterMut<'it, T>; - - fn into_iter(self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice_mut()[..cnt].iter_mut() - } -} - -impl<'a, T> VariableMapObserver<'a, T> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug - + PartialEq - + Bounded, -{ - /// Returns an iterator over the map. - pub fn iter(&self) -> Iter<'_, T> { - <&Self as IntoIterator>::into_iter(self) - } - - /// Returns a mutable iterator over the map. - pub fn iter_mut(&mut self) -> IterMut<'_, T> { - <&mut Self as IntoIterator>::into_iter(self) - } -} - -impl<'a, T> Hash for VariableMapObserver<'a, T> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug - + PartialEq - + Bounded, -{ - #[inline] - fn hash(&self, hasher: &mut H) { - self.as_slice().hash(hasher); - } -} - -impl<'a, T> AsRef for VariableMapObserver<'a, T> -where - T: Default + Copy + 'static + Serialize + PartialEq + Bounded, -{ - fn as_ref(&self) -> &Self { - self - } -} - -impl<'a, T> AsMut for VariableMapObserver<'a, T> -where - T: Default + Copy + 'static + Serialize + PartialEq + Bounded, -{ - fn as_mut(&mut self) -> &mut Self { - self - } -} - -impl<'a, T> MapObserver for VariableMapObserver<'a, T> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug - + PartialEq - + Bounded, -{ - type Entry = T; - - #[inline] - fn initial(&self) -> T { - self.initial - } - - #[inline] - fn usable_count(&self) -> usize { - *self.size.as_ref() - } - - fn get(&self, idx: usize) -> T { - self.map.as_slice()[idx] - } - - fn set(&mut self, idx: usize, val: T) { - self.map.as_slice_mut()[idx] = val; - } - - /// Count the set bytes in the map - fn count_bytes(&self) -> u64 { - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice(); - let mut res = 0; - for x in &map[0..cnt] { - if *x != initial { - res += 1; - } - } - res - } - - #[inline] - fn hash_simple(&self) -> u64 { - RandomState::with_seeds(0, 0, 0, 0).hash_one(self) - } - - /// Reset the map - #[inline] - fn reset_map(&mut self) -> Result<(), Error> { - // Normal memset, see https://rust.godbolt.org/z/Trs5hv - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice_mut(); - for x in &mut map[0..cnt] { - *x = initial; - } - Ok(()) - } - - fn to_vec(&self) -> Vec { - self.as_slice().to_vec() - } - - fn how_many_set(&self, indexes: &[usize]) -> usize { - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice(); - let mut res = 0; - for i in indexes { - if *i < cnt && map[*i] != initial { - res += 1; - } - } - res - } -} - -impl<'a, T> Deref for VariableMapObserver<'a, T> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug - + PartialEq - + Bounded, -{ - type Target = [T]; - fn deref(&self) -> &[T] { - let cnt = self.usable_count(); - &self.map[..cnt] - } -} - -impl<'a, T> DerefMut for VariableMapObserver<'a, T> -where - T: 'static - + Default - + Copy - + Hash - + Serialize - + serde::de::DeserializeOwned - + Debug - + PartialEq - + Bounded, -{ - fn deref_mut(&mut self) -> &mut [T] { - let cnt = self.usable_count(); - &mut self.map[..cnt] - } -} - -impl<'a, T> VariableMapObserver<'a, T> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + PartialEq + Bounded, -{ - /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] - /// - /// # Safety - /// The observer will dereference the owned slice, as well as the `map_ptr`. - /// Dereferences `map_ptr` with up to `max_len` elements of size. - pub unsafe fn from_mut_slice( - name: &'static str, - map_slice: OwnedMutSlice<'a, T>, - size: *mut usize, - ) -> Self { - VariableMapObserver { - name: name.into(), - map: map_slice, - size: OwnedMutPtr::Ptr(size), - initial: T::default(), - } - } - - /// Creates a new [`MapObserver`] from a raw pointer - /// - /// # Safety - /// The observer will dereference the `size` ptr, as well as the `map_ptr`. - /// Dereferences `map_ptr` with up to `max_len` elements of size. - pub unsafe fn from_mut_ptr( - name: &'static str, - map_ptr: *mut T, - max_len: usize, - size: *mut usize, - ) -> Self { - Self::from_mut_slice( - name, - OwnedMutSlice::from_raw_parts_mut(map_ptr, max_len), - size, - ) - } -} - -/// Map observer with AFL-like hitcounts postprocessing -/// -/// [`MapObserver`]s that are not slice-backed, such as [`MultiMapObserver`], can use -/// [`HitcountsIterableMapObserver`] instead. -#[derive(Serialize, Deserialize, Clone, Debug, Hash)] -#[serde(bound = "M: serde::de::DeserializeOwned")] -pub struct HitcountsMapObserver -where - M: Serialize, -{ - base: M, -} - -impl Observer for HitcountsMapObserver -where - M: MapObserver + Observer + for<'a> AsSliceMut<'a, Entry = u8>, - S: UsesInput, -{ - #[inline] - fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { - self.base.pre_exec(state, input) - } - - #[inline] - #[allow(clippy::cast_ptr_alignment)] - fn post_exec( - &mut self, - state: &mut S, - input: &S::Input, - exit_kind: &ExitKind, - ) -> Result<(), Error> { - let mut map = self.as_slice_mut(); - let mut len = map.len(); - let align_offset = map.as_ptr().align_offset(size_of::()); - - // if len == 1, the next branch will already do this lookup - if len > 1 && align_offset != 0 { - debug_assert_eq!( - align_offset, 1, - "Aligning u8 to u16 should always be offset of 1?" - ); - unsafe { - *map.get_unchecked_mut(0) = - *COUNT_CLASS_LOOKUP.get_unchecked(*map.get_unchecked(0) as usize); - } - len -= 1; - } - - // Fix the last element - if (len & 1) != 0 { - unsafe { - *map.get_unchecked_mut(len - 1) = - *COUNT_CLASS_LOOKUP.get_unchecked(*map.get_unchecked(len - 1) as usize); - } - } - - let cnt = len / 2; - - let map16 = unsafe { - slice::from_raw_parts_mut(map.as_mut_ptr().add(align_offset) as *mut u16, cnt) - }; - // 2022-07: Adding `enumerate` here increases execution speed/register allocation on x86_64. - #[allow(clippy::unused_enumerate_index)] - for (_i, item) in map16[0..cnt].iter_mut().enumerate() { - unsafe { - *item = *COUNT_CLASS_LOOKUP_16.get_unchecked(*item as usize); - } - } - - drop(map); - - self.base.post_exec(state, input, exit_kind) - } -} - -impl Named for HitcountsMapObserver -where - M: Named + Serialize + serde::de::DeserializeOwned, -{ - #[inline] - fn name(&self) -> &Cow<'static, str> { - self.base.name() - } -} - -impl HasLen for HitcountsMapObserver -where - M: MapObserver, -{ - #[inline] - fn len(&self) -> usize { - self.base.len() - } -} - -impl AsRef for HitcountsMapObserver -where - M: MapObserver, -{ - fn as_ref(&self) -> &Self { - self - } -} - -impl AsMut for HitcountsMapObserver -where - M: MapObserver, -{ - fn as_mut(&mut self) -> &mut Self { - self - } -} - -impl MapObserver for HitcountsMapObserver -where - M: MapObserver, -{ - type Entry = u8; - - #[inline] - fn initial(&self) -> u8 { - self.base.initial() - } - - #[inline] - fn usable_count(&self) -> usize { - self.base.usable_count() - } - - #[inline] - fn get(&self, idx: usize) -> u8 { - self.base.get(idx) - } - - #[inline] - fn set(&mut self, idx: usize, val: u8) { - self.base.set(idx, val); - } - - /// Count the set bytes in the map - fn count_bytes(&self) -> u64 { - self.base.count_bytes() - } - - /// Reset the map - #[inline] - fn reset_map(&mut self) -> Result<(), Error> { - self.base.reset_map() - } - - #[inline] - fn hash_simple(&self) -> u64 { - self.base.hash_simple() - } - fn to_vec(&self) -> Vec { - self.base.to_vec() - } - - fn how_many_set(&self, indexes: &[usize]) -> usize { - self.base.how_many_set(indexes) - } -} - -impl Truncate for HitcountsMapObserver -where - M: Named + Serialize + serde::de::DeserializeOwned + Truncate, -{ - fn truncate(&mut self, new_len: usize) { - self.base.truncate(new_len); - } -} - -impl<'a, M> AsSlice<'a> for HitcountsMapObserver -where - M: MapObserver + AsSlice<'a>, -{ - type Entry = >::Entry; - type SliceRef = >::SliceRef; - - #[inline] - fn as_slice(&'a self) -> Self::SliceRef { - self.base.as_slice() - } -} - -impl<'a, M> AsSliceMut<'a> for HitcountsMapObserver -where - M: MapObserver + AsSliceMut<'a>, -{ - type SliceRefMut = >::SliceRefMut; - #[inline] - fn as_slice_mut(&'a mut self) -> Self::SliceRefMut { - self.base.as_slice_mut() - } -} - -impl HitcountsMapObserver -where - M: MapObserver, -{ - /// Creates a new [`MapObserver`] - pub fn new(base: M) -> Self { - init_count_class_16(); - Self { base } - } -} - -impl<'it, M> IntoIterator for &'it HitcountsMapObserver -where - M: Serialize + serde::de::DeserializeOwned, - &'it M: IntoIterator, -{ - type Item = &'it u8; - type IntoIter = <&'it M as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.base.into_iter() - } -} - -impl<'it, M> IntoIterator for &'it mut HitcountsMapObserver -where - M: Serialize + serde::de::DeserializeOwned, - &'it mut M: IntoIterator, -{ - type Item = &'it mut u8; - type IntoIter = <&'it mut M as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.base.into_iter() - } -} - -impl HitcountsMapObserver -where - M: Serialize + serde::de::DeserializeOwned, - for<'it> &'it M: IntoIterator, -{ - /// Returns an iterator over the map. - pub fn iter(&self) -> <&M as IntoIterator>::IntoIter { - <&Self as IntoIterator>::into_iter(self) - } -} - -impl HitcountsMapObserver -where - M: Serialize + serde::de::DeserializeOwned, - for<'it> &'it mut M: IntoIterator, -{ - /// Returns a mutable iterator over the map. - pub fn iter_mut(&mut self) -> <&mut M as IntoIterator>::IntoIter { - <&mut Self as IntoIterator>::into_iter(self) - } -} - -impl DifferentialObserver for HitcountsMapObserver -where - M: DifferentialObserver - + MapObserver - + Serialize - + for<'a> AsSliceMut<'a, Entry = u8>, - OTA: ObserversTuple, - OTB: ObserversTuple, - S: UsesInput, -{ - fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { - self.base.pre_observe_first(observers) - } - - fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { - self.base.post_observe_first(observers) - } - - fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { - self.base.pre_observe_second(observers) - } - - fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { - self.base.post_observe_second(observers) - } -} - -/// Map observer with hitcounts postprocessing -/// Less optimized version for non-slice iterators. -/// Slice-backed observers should use a [`HitcountsMapObserver`]. -#[derive(Serialize, Deserialize, Clone, Debug, Hash)] -#[serde(bound = "M: serde::de::DeserializeOwned")] -pub struct HitcountsIterableMapObserver -where - M: Serialize, -{ - base: M, -} - -impl Observer for HitcountsIterableMapObserver -where - M: MapObserver + Observer, - for<'it> M: AsIterMut<'it, Item = u8>, - S: UsesInput, -{ - #[inline] - fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { - self.base.pre_exec(state, input) - } - - #[inline] - #[allow(clippy::cast_ptr_alignment)] - fn post_exec( - &mut self, - state: &mut S, - input: &S::Input, - exit_kind: &ExitKind, - ) -> Result<(), Error> { - for mut item in self.as_iter_mut() { - *item = unsafe { *COUNT_CLASS_LOOKUP.get_unchecked((*item) as usize) }; - } - - self.base.post_exec(state, input, exit_kind) - } -} - -impl Named for HitcountsIterableMapObserver -where - M: Named + Serialize + serde::de::DeserializeOwned, -{ - #[inline] - fn name(&self) -> &Cow<'static, str> { - self.base.name() - } -} - -impl HasLen for HitcountsIterableMapObserver -where - M: MapObserver, -{ - #[inline] - fn len(&self) -> usize { - self.base.len() - } -} - -impl AsRef for HitcountsIterableMapObserver -where - M: MapObserver, - for<'it> M: AsIterMut<'it, Item = u8>, -{ - fn as_ref(&self) -> &Self { - self - } -} - -impl AsMut for HitcountsIterableMapObserver -where - M: MapObserver, - for<'it> M: AsIterMut<'it, Item = u8>, -{ - fn as_mut(&mut self) -> &mut Self { - self - } -} - -impl MapObserver for HitcountsIterableMapObserver -where - M: MapObserver, - for<'it> M: AsIterMut<'it, Item = u8>, -{ - type Entry = u8; - - #[inline] - fn initial(&self) -> u8 { - self.base.initial() - } - - #[inline] - fn usable_count(&self) -> usize { - self.base.usable_count() - } - - #[inline] - fn get(&self, idx: usize) -> u8 { - self.base.get(idx) - } - - #[inline] - fn set(&mut self, idx: usize, val: u8) { - self.base.set(idx, val); - } - - /// Count the set bytes in the map - fn count_bytes(&self) -> u64 { - self.base.count_bytes() - } - - /// Reset the map - #[inline] - fn reset_map(&mut self) -> Result<(), Error> { - self.base.reset_map() - } - - #[inline] - fn hash_simple(&self) -> u64 { - self.base.hash_simple() - } - fn to_vec(&self) -> Vec { - self.base.to_vec() - } - - fn how_many_set(&self, indexes: &[usize]) -> usize { - self.base.how_many_set(indexes) - } -} - -impl Truncate for HitcountsIterableMapObserver -where - M: Named + Serialize + serde::de::DeserializeOwned + Truncate, -{ - fn truncate(&mut self, new_len: usize) { - self.base.truncate(new_len); - } -} - -impl HitcountsIterableMapObserver -where - M: Serialize + serde::de::DeserializeOwned, -{ - /// Creates a new [`MapObserver`] - pub fn new(base: M) -> Self { - init_count_class_16(); - Self { base } - } -} - -impl<'it, M> AsIter<'it> for HitcountsIterableMapObserver -where - M: Named + Serialize + serde::de::DeserializeOwned + AsIter<'it, Item = u8>, -{ - type Item = u8; - type Ref = >::Ref; - type IntoIter = >::IntoIter; - - fn as_iter(&'it self) -> Self::IntoIter { - self.base.as_iter() - } -} - -impl<'it, M> AsIterMut<'it> for HitcountsIterableMapObserver -where - M: Named + Serialize + serde::de::DeserializeOwned + AsIterMut<'it, Item = u8>, -{ - type RefMut = >::RefMut; - type IntoIterMut = >::IntoIterMut; - - fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { - self.base.as_iter_mut() - } -} - -impl<'it, M> IntoIterator for &'it HitcountsIterableMapObserver -where - M: Serialize + serde::de::DeserializeOwned, - &'it M: IntoIterator, -{ - type Item = &'it u8; - type IntoIter = <&'it M as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.base.into_iter() - } -} - -impl<'it, M> IntoIterator for &'it mut HitcountsIterableMapObserver -where - M: Serialize + serde::de::DeserializeOwned, - &'it mut M: IntoIterator, -{ - type Item = &'it mut u8; - type IntoIter = <&'it mut M as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.base.into_iter() - } -} - -impl HitcountsIterableMapObserver -where - M: Serialize + serde::de::DeserializeOwned, - for<'it> &'it M: IntoIterator, -{ - /// Returns an iterator over the map. - pub fn iter(&self) -> <&M as IntoIterator>::IntoIter { - <&Self as IntoIterator>::into_iter(self) - } -} - -impl HitcountsIterableMapObserver -where - M: Serialize + serde::de::DeserializeOwned, - for<'it> &'it mut M: IntoIterator, -{ - /// Returns a mutable iterator over the map. - pub fn iter_mut(&mut self) -> <&mut M as IntoIterator>::IntoIter { - <&mut Self as IntoIterator>::into_iter(self) - } -} - -impl DifferentialObserver for HitcountsIterableMapObserver -where - M: MapObserver + Observer + DifferentialObserver, - for<'it> M: AsIterMut<'it, Item = u8>, - OTA: ObserversTuple, - OTB: ObserversTuple, - S: UsesInput, -{ - fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { - self.base.pre_observe_first(observers) - } - - fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { - self.base.post_observe_first(observers) - } - - fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { - self.base.pre_observe_second(observers) - } - - fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { - self.base.post_observe_second(observers) - } -} - -/// The Multi Map Observer merge different maps into one observer -#[derive(Serialize, Deserialize, Debug)] -#[serde(bound = "T: serde::de::DeserializeOwned")] -#[allow(clippy::unsafe_derive_deserialize)] -pub struct MultiMapObserver<'a, T, const DIFFERENTIAL: bool> -where - T: 'static + Default + Copy + Serialize + Debug, -{ - maps: Vec>, - intervals: IntervalTree, - len: usize, - initial: T, - name: Cow<'static, str>, - iter_idx: usize, -} - -impl<'a, S, T> Observer for MultiMapObserver<'a, T, false> -where - S: UsesInput, - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, - Self: MapObserver, -{ - #[inline] - fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { - self.reset_map() - } -} - -impl<'a, S, T> Observer for MultiMapObserver<'a, T, true> -where - S: UsesInput, - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, - Self: MapObserver, -{ - // in differential mode, we are *not* responsible for resetting the map! -} - -impl<'a, T, const DIFFERENTIAL: bool> Named for MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - #[inline] - fn name(&self) -> &Cow<'static, str> { - &self.name - } -} - -impl<'a, T, const DIFFERENTIAL: bool> HasLen for MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - #[inline] - fn len(&self) -> usize { - self.len - } -} - -impl<'a, T, const DIFFERENTIAL: bool> Hash for MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - fn hash(&self, hasher: &mut H) { - for map in &self.maps { - let slice = map.as_slice(); - let ptr = slice.as_ptr() as *const u8; - let map_size = slice.len() / size_of::(); - unsafe { - hasher.write(slice::from_raw_parts(ptr, map_size)); - } - } - } -} - -impl<'a, T, const DIFFERENTIAL: bool> AsRef for MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static + Default + Copy + Serialize + Debug, -{ - fn as_ref(&self) -> &Self { - self - } -} - -impl<'a, T, const DIFFERENTIAL: bool> AsMut for MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static + Default + Copy + Serialize + Debug, -{ - fn as_mut(&mut self) -> &mut Self { - self - } -} - -impl<'a, T, const DIFFERENTIAL: bool> MapObserver for MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static - + Bounded - + PartialEq - + Default - + Copy - + Hash - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Entry = T; - - #[inline] - fn get(&self, idx: usize) -> T { - let elem = self.intervals.query(idx..=idx).next().unwrap(); - let i = *elem.value; - let j = idx - elem.interval.start; - self.maps[i].as_slice()[j] - } - - #[inline] - fn set(&mut self, idx: usize, val: Self::Entry) { - let elem = self.intervals.query(idx..=idx).next().unwrap(); - let i = *elem.value; - let j = idx - elem.interval.start; - self.maps[i].as_slice_mut()[j] = val; - } - - #[inline] - fn initial(&self) -> T { - self.initial - } - - fn count_bytes(&self) -> u64 { - let initial = self.initial(); - let mut res = 0; - for map in &self.maps { - for x in map.as_slice() { - if *x != initial { - res += 1; - } - } - } - res - } - - #[inline] - fn hash_simple(&self) -> u64 { - RandomState::with_seeds(0, 0, 0, 0).hash_one(self) - } - - fn reset_map(&mut self) -> Result<(), Error> { - let initial = self.initial(); - for map in &mut self.maps { - for x in map.as_slice_mut() { - *x = initial; - } - } - Ok(()) - } - - fn usable_count(&self) -> usize { - self.len() - } - - fn to_vec(&self) -> Vec { - let cnt = self.usable_count(); - let mut res = Vec::with_capacity(cnt); - for i in 0..cnt { - res.push(self.get(i)); - } - res - } - - /// Get the number of set entries with the specified indexes - fn how_many_set(&self, indexes: &[usize]) -> usize { - let initial = self.initial(); - let cnt = self.usable_count(); - let mut res = 0; - for i in indexes { - if *i < cnt && self.get(*i) != initial { - res += 1; - } - } - res - } -} - -impl<'a, T, const DIFFERENTIAL: bool> MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - /// Creates a new [`MultiMapObserver`], maybe in differential mode - #[must_use] - fn maybe_differential(name: &'static str, maps: Vec>) -> Self { - let mut idx = 0; - let mut intervals = IntervalTree::new(); - for (v, x) in maps.iter().enumerate() { - let l = x.as_slice().len(); - intervals.insert(idx..(idx + l), v); - idx += l; - } - Self { - maps, - intervals, - len: idx, - name: Cow::from(name), - initial: T::default(), - iter_idx: 0, - } - } -} - -impl<'a, T> MultiMapObserver<'a, T, true> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - /// Creates a new [`MultiMapObserver`] in differential mode - #[must_use] - pub fn differential(name: &'static str, maps: Vec>) -> Self { - Self::maybe_differential(name, maps) - } -} - -impl<'a, T> MultiMapObserver<'a, T, false> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - /// Creates a new [`MultiMapObserver`] - #[must_use] - pub fn new(name: &'static str, maps: Vec>) -> Self { - Self::maybe_differential(name, maps) - } - - /// Creates a new [`MultiMapObserver`] with an owned map - #[must_use] - pub fn owned(name: &'static str, maps: Vec>) -> Self { - let mut idx = 0; - let mut v = 0; - let mut intervals = IntervalTree::new(); - let maps: Vec<_> = maps - .into_iter() - .map(|x| { - let l = x.len(); - intervals.insert(idx..(idx + l), v); - idx += l; - v += 1; - OwnedMutSlice::from(x) - }) - .collect(); - Self { - maps, - intervals, - len: idx, - name: Cow::from(name), - initial: T::default(), - iter_idx: 0, - } - } -} - -impl<'a, 'it, T, const DIFFERENTIAL: bool> AsIter<'it> for MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, - 'a: 'it, -{ - type Item = T; - type Ref = &'it T; - type IntoIter = Flatten>>; - - fn as_iter(&'it self) -> Self::IntoIter { - self.maps.iter().flatten() - } -} - -impl<'a, 'it, T, const DIFFERENTIAL: bool> AsIterMut<'it> for MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, - 'a: 'it, -{ - type RefMut = &'it mut T; - type IntoIterMut = Flatten>>; - - fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { - self.maps.iter_mut().flatten() - } -} - -impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator - for &'it MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - type Item = as Iterator>::Item; - type IntoIter = Flatten>>; - - fn into_iter(self) -> Self::IntoIter { - self.maps.iter().flatten() - } -} - -impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator - for &'it mut MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - type Item = as Iterator>::Item; - type IntoIter = Flatten>>; - - fn into_iter(self) -> Self::IntoIter { - self.maps.iter_mut().flatten() - } -} - -impl<'a, T, const DIFFERENTIAL: bool> MultiMapObserver<'a, T, DIFFERENTIAL> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - /// Returns an iterator over the map. - pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter { - <&Self as IntoIterator>::into_iter(self) - } - - /// Returns a mutable iterator over the map. - pub fn iter_mut(&mut self) -> <&mut Self as IntoIterator>::IntoIter { - <&mut Self as IntoIterator>::into_iter(self) - } -} - -impl<'a, T, OTA, OTB, S> DifferentialObserver for MultiMapObserver<'a, T, true> -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, - Self: MapObserver, - OTA: ObserversTuple, - OTB: ObserversTuple, - S: UsesInput, -{ -} - -/// Exact copy of `StdMapObserver` that owns its map -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(bound = "T: serde::de::DeserializeOwned")] -#[allow(clippy::unsafe_derive_deserialize)] -pub struct OwnedMapObserver -where - T: 'static + Default + Copy + Serialize, -{ - map: Vec, - initial: T, - name: Cow<'static, str>, -} - -impl Observer for OwnedMapObserver -where - S: UsesInput, - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, - Self: MapObserver, -{ - #[inline] - fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { - self.reset_map() - } -} - -impl Named for OwnedMapObserver -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned, -{ - #[inline] - fn name(&self) -> &Cow<'static, str> { - &self.name - } -} - -impl HasLen for OwnedMapObserver -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned, -{ - #[inline] - fn len(&self) -> usize { - self.map.as_slice().len() - } -} - -impl<'it, T> IntoIterator for &'it OwnedMapObserver -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - type Item = as Iterator>::Item; - type IntoIter = Iter<'it, T>; - - fn into_iter(self) -> Self::IntoIter { - self.as_slice().iter() - } -} - -impl<'it, T> IntoIterator for &'it mut OwnedMapObserver -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - type Item = as Iterator>::Item; - type IntoIter = IterMut<'it, T>; - - fn into_iter(self) -> Self::IntoIter { - self.as_slice_mut().iter_mut() - } -} - -impl OwnedMapObserver -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - /// Returns an iterator over the map. - pub fn iter(&self) -> Iter<'_, T> { - <&Self as IntoIterator>::into_iter(self) - } - - /// Returns a mutable iterator over the map. - pub fn iter_mut(&mut self) -> IterMut<'_, T> { - <&mut Self as IntoIterator>::into_iter(self) - } -} - -impl Hash for OwnedMapObserver -where - T: 'static + Hash + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - #[inline] - fn hash(&self, hasher: &mut H) { - self.as_slice().hash(hasher); - } -} - -impl AsRef for OwnedMapObserver -where - T: 'static + Default + Copy + Serialize, -{ - fn as_ref(&self) -> &Self { - self - } -} - -impl AsMut for OwnedMapObserver -where - T: 'static + Default + Copy + Serialize, -{ - fn as_mut(&mut self) -> &mut Self { - self - } -} - -impl MapObserver for OwnedMapObserver -where - T: 'static - + Bounded - + PartialEq - + Default - + Copy - + Hash - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Entry = T; - - #[inline] - fn get(&self, pos: usize) -> T { - self.as_slice()[pos] - } - - #[inline] - fn set(&mut self, pos: usize, val: Self::Entry) { - self.as_slice_mut()[pos] = val; - } - - /// Count the set bytes in the map - fn count_bytes(&self) -> u64 { - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice(); - let mut res = 0; - for x in &map[0..cnt] { - if *x != initial { - res += 1; - } - } - res - } - - #[inline] - fn usable_count(&self) -> usize { - self.as_slice().len() - } - - #[inline] - fn hash_simple(&self) -> u64 { - RandomState::with_seeds(0, 0, 0, 0).hash_one(self) - } - - #[inline] - fn initial(&self) -> T { - self.initial - } - - /// Reset the map - #[inline] - fn reset_map(&mut self) -> Result<(), Error> { - // Normal memset, see https://rust.godbolt.org/z/Trs5hv - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice_mut(); - for x in &mut map[0..cnt] { - *x = initial; - } - Ok(()) - } - fn to_vec(&self) -> Vec { - self.as_slice().to_vec() - } - - fn how_many_set(&self, indexes: &[usize]) -> usize { - let initial = self.initial(); - let cnt = self.usable_count(); - let map = self.as_slice(); - let mut res = 0; - for i in indexes { - if *i < cnt && map[*i] != initial { - res += 1; - } - } - res - } -} - -impl Deref for OwnedMapObserver -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - type Target = [T]; - - fn deref(&self) -> &[T] { - &self.map - } -} - -impl DerefMut for OwnedMapObserver -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - fn deref_mut(&mut self) -> &mut [T] { - &mut self.map - } -} - -impl OwnedMapObserver -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned, -{ - /// Creates a new [`MapObserver`] with an owned map - #[must_use] - pub fn new(name: &'static str, map: Vec) -> Self { - let initial = if map.is_empty() { T::default() } else { map[0] }; - Self { - map, - name: Cow::from(name), - initial, - } - } -} diff --git a/libafl/src/observers/map/const_map.rs b/libafl/src/observers/map/const_map.rs new file mode 100644 index 0000000000..533b7ded55 --- /dev/null +++ b/libafl/src/observers/map/const_map.rs @@ -0,0 +1,313 @@ +//! Map observer with a const size + +use alloc::{borrow::Cow, vec::Vec}; +use core::{ + fmt::Debug, + hash::{Hash, Hasher}, + ops::{Deref, DerefMut}, + slice::{Iter, IterMut}, +}; + +use ahash::RandomState; +use libafl_bolts::{ownedref::OwnedMutSlice, AsSlice, AsSliceMut, HasLen, Named}; +use num_traits::Bounded; +use serde::{Deserialize, Serialize}; + +use crate::{ + inputs::UsesInput, + observers::{map::MapObserver, Observer}, + Error, +}; + +/// Use a const size to speedup `Feedback::is_interesting` when the user can +/// know the size of the map at compile time. +#[derive(Serialize, Deserialize, Debug)] +#[serde(bound = "T: serde::de::DeserializeOwned")] +#[allow(clippy::unsafe_derive_deserialize)] +pub struct ConstMapObserver<'a, T, const N: usize> +where + T: Default + Copy + 'static + Serialize, +{ + map: OwnedMutSlice<'a, T>, + initial: T, + name: Cow<'static, str>, +} + +impl<'a, S, T, const N: usize> Observer for ConstMapObserver<'a, T, N> +where + S: UsesInput, + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + Self: MapObserver, +{ + #[inline] + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { + self.reset_map() + } +} + +impl<'a, T, const N: usize> Named for ConstMapObserver<'a, T, N> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +impl<'a, T, const N: usize> HasLen for ConstMapObserver<'a, T, N> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn len(&self) -> usize { + N + } +} + +impl<'a, 'it, T, const N: usize> IntoIterator for &'it ConstMapObserver<'a, T, N> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + type Item = as Iterator>::Item; + type IntoIter = Iter<'it, T>; + + fn into_iter(self) -> Self::IntoIter { + let cnt = self.usable_count(); + self.as_slice()[..cnt].iter() + } +} + +impl<'a, 'it, T, const N: usize> IntoIterator for &'it mut ConstMapObserver<'a, T, N> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + type Item = as Iterator>::Item; + type IntoIter = IterMut<'it, T>; + + fn into_iter(self) -> Self::IntoIter { + let cnt = self.usable_count(); + self.as_slice_mut()[..cnt].iter_mut() + } +} + +impl<'a, T, const N: usize> ConstMapObserver<'a, T, N> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + /// Returns an iterator over the map. + pub fn iter(&self) -> Iter<'_, T> { + <&Self as IntoIterator>::into_iter(self) + } + + /// Returns a mutable iterator over the map. + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + <&mut Self as IntoIterator>::into_iter(self) + } +} + +impl<'a, T, const N: usize> Hash for ConstMapObserver<'a, T, N> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + #[inline] + fn hash(&self, hasher: &mut H) { + self.as_slice().hash(hasher); + } +} +impl<'a, T, const N: usize> AsRef for ConstMapObserver<'a, T, N> +where + T: Default + Copy + 'static + Serialize, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl<'a, T, const N: usize> AsMut for ConstMapObserver<'a, T, N> +where + T: Default + Copy + 'static + Serialize, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + +impl<'a, T, const N: usize> MapObserver for ConstMapObserver<'a, T, N> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + type Entry = T; + + #[inline] + fn initial(&self) -> T { + self.initial + } + + #[inline] + fn get(&self, idx: usize) -> T { + self.as_slice()[idx] + } + + #[inline] + fn set(&mut self, idx: usize, val: T) { + self.map.as_slice_mut()[idx] = val; + } + + /// Count the set bytes in the map + fn count_bytes(&self) -> u64 { + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice(); + let mut res = 0; + for x in &map[0..cnt] { + if *x != initial { + res += 1; + } + } + res + } + + fn usable_count(&self) -> usize { + self.as_slice().len() + } + + #[inline] + fn hash_simple(&self) -> u64 { + RandomState::with_seeds(0, 0, 0, 0).hash_one(self) + } + + /// Reset the map + #[inline] + fn reset_map(&mut self) -> Result<(), Error> { + // Normal memset, see https://rust.godbolt.org/z/Trs5hv + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice_mut(); + for x in &mut map[0..cnt] { + *x = initial; + } + Ok(()) + } + + fn to_vec(&self) -> Vec { + self.as_slice().to_vec() + } + + /// Get the number of set entries with the specified indexes + fn how_many_set(&self, indexes: &[usize]) -> usize { + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice(); + let mut res = 0; + for i in indexes { + if *i < cnt && map[*i] != initial { + res += 1; + } + } + res + } +} + +impl<'a, T, const N: usize> Deref for ConstMapObserver<'a, T, N> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, +{ + type Target = [T]; + fn deref(&self) -> &[T] { + &self.map + } +} + +impl<'a, T, const N: usize> DerefMut for ConstMapObserver<'a, T, N> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, +{ + fn deref_mut(&mut self) -> &mut [T] { + &mut self.map + } +} + +impl<'a, T, const N: usize> ConstMapObserver<'a, T, N> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, +{ + /// Creates a new [`MapObserver`] + /// + /// # Note + /// Will get a pointer to the map and dereference it at any point in time. + /// The map must not move in memory! + #[must_use] + pub fn new(name: &'static str, map: &'a mut [T]) -> Self { + assert!(map.len() >= N); + Self { + map: OwnedMutSlice::from(map), + name: Cow::from(name), + initial: T::default(), + } + } + + /// Creates a new [`MapObserver`] with an owned map + #[must_use] + pub fn owned(name: &'static str, map: Vec) -> Self { + assert!(map.len() >= N); + let initial = if map.is_empty() { T::default() } else { map[0] }; + Self { + map: OwnedMutSlice::from(map), + name: Cow::from(name), + initial, + } + } + + /// Creates a new [`MapObserver`] from a raw pointer + /// + /// # Safety + /// Will dereference the `map_ptr` with up to len elements. + pub unsafe fn from_mut_ptr(name: &'static str, map_ptr: *mut T) -> Self { + ConstMapObserver { + map: OwnedMutSlice::from_raw_parts_mut(map_ptr, N), + name: Cow::from(name), + initial: T::default(), + } + } +} diff --git a/libafl/src/observers/map/hitcount_map.rs b/libafl/src/observers/map/hitcount_map.rs new file mode 100644 index 0000000000..cd8f1f7193 --- /dev/null +++ b/libafl/src/observers/map/hitcount_map.rs @@ -0,0 +1,583 @@ +//! Hitcount map observer is for implementing AFL's hit count bucket +use alloc::{borrow::Cow, vec::Vec}; +use core::{fmt::Debug, hash::Hash, mem::size_of, slice}; + +use libafl_bolts::{AsIter, AsIterMut, AsSlice, AsSliceMut, HasLen, Named, Truncate}; +use serde::{Deserialize, Serialize}; + +use crate::{ + executors::ExitKind, + inputs::UsesInput, + observers::{map::MapObserver, DifferentialObserver, Observer, ObserversTuple}, + Error, +}; + +/// Hitcounts class lookup +static COUNT_CLASS_LOOKUP: [u8; 256] = [ + 0, 1, 2, 4, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +]; + +/// Hitcounts class lookup for 16-byte values +static mut COUNT_CLASS_LOOKUP_16: Vec = vec![]; + +/// Initialize the 16-byte hitcounts map +/// +/// # Safety +/// +/// Calling this from multiple threads may be racey and hence leak 65k mem +fn init_count_class_16() { + unsafe { + if !COUNT_CLASS_LOOKUP_16.is_empty() { + return; + } + + COUNT_CLASS_LOOKUP_16 = vec![0; 65536]; + for i in 0..256 { + for j in 0..256 { + COUNT_CLASS_LOOKUP_16[(i << 8) + j] = + (u16::from(COUNT_CLASS_LOOKUP[i]) << 8) | u16::from(COUNT_CLASS_LOOKUP[j]); + } + } + } +} + +/// Map observer with AFL-like hitcounts postprocessing +/// +/// [`MapObserver`]s that are not slice-backed, such as `MultiMapObserver`, can use +/// [`HitcountsIterableMapObserver`] instead. +#[derive(Serialize, Deserialize, Clone, Debug, Hash)] +#[serde(bound = "M: serde::de::DeserializeOwned")] +pub struct HitcountsMapObserver +where + M: Serialize, +{ + base: M, +} + +impl Observer for HitcountsMapObserver +where + M: MapObserver + Observer + for<'a> AsSliceMut<'a, Entry = u8>, + S: UsesInput, +{ + #[inline] + fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { + self.base.pre_exec(state, input) + } + + #[inline] + #[allow(clippy::cast_ptr_alignment)] + fn post_exec( + &mut self, + state: &mut S, + input: &S::Input, + exit_kind: &ExitKind, + ) -> Result<(), Error> { + let mut map = self.as_slice_mut(); + let mut len = map.len(); + let align_offset = map.as_ptr().align_offset(size_of::()); + + // if len == 1, the next branch will already do this lookup + if len > 1 && align_offset != 0 { + debug_assert_eq!( + align_offset, 1, + "Aligning u8 to u16 should always be offset of 1?" + ); + unsafe { + *map.get_unchecked_mut(0) = + *COUNT_CLASS_LOOKUP.get_unchecked(*map.get_unchecked(0) as usize); + } + len -= 1; + } + + // Fix the last element + if (len & 1) != 0 { + unsafe { + *map.get_unchecked_mut(len - 1) = + *COUNT_CLASS_LOOKUP.get_unchecked(*map.get_unchecked(len - 1) as usize); + } + } + + let cnt = len / 2; + + let map16 = unsafe { + slice::from_raw_parts_mut(map.as_mut_ptr().add(align_offset) as *mut u16, cnt) + }; + // 2022-07: Adding `enumerate` here increases execution speed/register allocation on x86_64. + #[allow(clippy::unused_enumerate_index)] + for (_i, item) in map16[0..cnt].iter_mut().enumerate() { + unsafe { + *item = *COUNT_CLASS_LOOKUP_16.get_unchecked(*item as usize); + } + } + + drop(map); + + self.base.post_exec(state, input, exit_kind) + } +} + +impl Named for HitcountsMapObserver +where + M: Named + Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn name(&self) -> &Cow<'static, str> { + self.base.name() + } +} + +impl HasLen for HitcountsMapObserver +where + M: MapObserver, +{ + #[inline] + fn len(&self) -> usize { + self.base.len() + } +} + +impl AsRef for HitcountsMapObserver +where + M: MapObserver, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl AsMut for HitcountsMapObserver +where + M: MapObserver, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + +impl MapObserver for HitcountsMapObserver +where + M: MapObserver, +{ + type Entry = u8; + + #[inline] + fn initial(&self) -> u8 { + self.base.initial() + } + + #[inline] + fn usable_count(&self) -> usize { + self.base.usable_count() + } + + #[inline] + fn get(&self, idx: usize) -> u8 { + self.base.get(idx) + } + + #[inline] + fn set(&mut self, idx: usize, val: u8) { + self.base.set(idx, val); + } + + /// Count the set bytes in the map + fn count_bytes(&self) -> u64 { + self.base.count_bytes() + } + + /// Reset the map + #[inline] + fn reset_map(&mut self) -> Result<(), Error> { + self.base.reset_map() + } + + #[inline] + fn hash_simple(&self) -> u64 { + self.base.hash_simple() + } + fn to_vec(&self) -> Vec { + self.base.to_vec() + } + + fn how_many_set(&self, indexes: &[usize]) -> usize { + self.base.how_many_set(indexes) + } +} + +impl Truncate for HitcountsMapObserver +where + M: Named + Serialize + serde::de::DeserializeOwned + Truncate, +{ + fn truncate(&mut self, new_len: usize) { + self.base.truncate(new_len); + } +} + +impl<'a, M> AsSlice<'a> for HitcountsMapObserver +where + M: MapObserver + AsSlice<'a>, +{ + type Entry = >::Entry; + type SliceRef = >::SliceRef; + + #[inline] + fn as_slice(&'a self) -> Self::SliceRef { + self.base.as_slice() + } +} + +impl<'a, M> AsSliceMut<'a> for HitcountsMapObserver +where + M: MapObserver + AsSliceMut<'a>, +{ + type SliceRefMut = >::SliceRefMut; + #[inline] + fn as_slice_mut(&'a mut self) -> Self::SliceRefMut { + self.base.as_slice_mut() + } +} + +impl HitcountsMapObserver +where + M: MapObserver, +{ + /// Creates a new [`MapObserver`] + pub fn new(base: M) -> Self { + init_count_class_16(); + Self { base } + } +} + +impl<'it, M> IntoIterator for &'it HitcountsMapObserver +where + M: Serialize + serde::de::DeserializeOwned, + &'it M: IntoIterator, +{ + type Item = &'it u8; + type IntoIter = <&'it M as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.base.into_iter() + } +} + +impl<'it, M> IntoIterator for &'it mut HitcountsMapObserver +where + M: Serialize + serde::de::DeserializeOwned, + &'it mut M: IntoIterator, +{ + type Item = &'it mut u8; + type IntoIter = <&'it mut M as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.base.into_iter() + } +} + +impl HitcountsMapObserver +where + M: Serialize + serde::de::DeserializeOwned, + for<'it> &'it M: IntoIterator, +{ + /// Returns an iterator over the map. + pub fn iter(&self) -> <&M as IntoIterator>::IntoIter { + <&Self as IntoIterator>::into_iter(self) + } +} + +impl HitcountsMapObserver +where + M: Serialize + serde::de::DeserializeOwned, + for<'it> &'it mut M: IntoIterator, +{ + /// Returns a mutable iterator over the map. + pub fn iter_mut(&mut self) -> <&mut M as IntoIterator>::IntoIter { + <&mut Self as IntoIterator>::into_iter(self) + } +} + +impl DifferentialObserver for HitcountsMapObserver +where + M: DifferentialObserver + + MapObserver + + Serialize + + for<'a> AsSliceMut<'a, Entry = u8>, + OTA: ObserversTuple, + OTB: ObserversTuple, + S: UsesInput, +{ + fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { + self.base.pre_observe_first(observers) + } + + fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { + self.base.post_observe_first(observers) + } + + fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { + self.base.pre_observe_second(observers) + } + + fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { + self.base.post_observe_second(observers) + } +} + +/// Map observer with hitcounts postprocessing +/// Less optimized version for non-slice iterators. +/// Slice-backed observers should use a [`HitcountsMapObserver`]. +#[derive(Serialize, Deserialize, Clone, Debug, Hash)] +#[serde(bound = "M: serde::de::DeserializeOwned")] +pub struct HitcountsIterableMapObserver +where + M: Serialize, +{ + base: M, +} + +impl Observer for HitcountsIterableMapObserver +where + M: MapObserver + Observer, + for<'it> M: AsIterMut<'it, Item = u8>, + S: UsesInput, +{ + #[inline] + fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { + self.base.pre_exec(state, input) + } + + #[inline] + #[allow(clippy::cast_ptr_alignment)] + fn post_exec( + &mut self, + state: &mut S, + input: &S::Input, + exit_kind: &ExitKind, + ) -> Result<(), Error> { + for mut item in self.as_iter_mut() { + *item = unsafe { *COUNT_CLASS_LOOKUP.get_unchecked((*item) as usize) }; + } + + self.base.post_exec(state, input, exit_kind) + } +} + +impl Named for HitcountsIterableMapObserver +where + M: Named + Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn name(&self) -> &Cow<'static, str> { + self.base.name() + } +} + +impl HasLen for HitcountsIterableMapObserver +where + M: MapObserver, +{ + #[inline] + fn len(&self) -> usize { + self.base.len() + } +} + +impl AsRef for HitcountsIterableMapObserver +where + M: MapObserver, + for<'it> M: AsIterMut<'it, Item = u8>, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl AsMut for HitcountsIterableMapObserver +where + M: MapObserver, + for<'it> M: AsIterMut<'it, Item = u8>, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + +impl MapObserver for HitcountsIterableMapObserver +where + M: MapObserver, + for<'it> M: AsIterMut<'it, Item = u8>, +{ + type Entry = u8; + + #[inline] + fn initial(&self) -> u8 { + self.base.initial() + } + + #[inline] + fn usable_count(&self) -> usize { + self.base.usable_count() + } + + #[inline] + fn get(&self, idx: usize) -> u8 { + self.base.get(idx) + } + + #[inline] + fn set(&mut self, idx: usize, val: u8) { + self.base.set(idx, val); + } + + /// Count the set bytes in the map + fn count_bytes(&self) -> u64 { + self.base.count_bytes() + } + + /// Reset the map + #[inline] + fn reset_map(&mut self) -> Result<(), Error> { + self.base.reset_map() + } + + #[inline] + fn hash_simple(&self) -> u64 { + self.base.hash_simple() + } + fn to_vec(&self) -> Vec { + self.base.to_vec() + } + + fn how_many_set(&self, indexes: &[usize]) -> usize { + self.base.how_many_set(indexes) + } +} + +impl Truncate for HitcountsIterableMapObserver +where + M: Named + Serialize + serde::de::DeserializeOwned + Truncate, +{ + fn truncate(&mut self, new_len: usize) { + self.base.truncate(new_len); + } +} + +impl HitcountsIterableMapObserver +where + M: Serialize + serde::de::DeserializeOwned, +{ + /// Creates a new [`MapObserver`] + pub fn new(base: M) -> Self { + init_count_class_16(); + Self { base } + } +} + +impl<'it, M> AsIter<'it> for HitcountsIterableMapObserver +where + M: Named + Serialize + serde::de::DeserializeOwned + AsIter<'it, Item = u8>, +{ + type Item = u8; + type Ref = >::Ref; + type IntoIter = >::IntoIter; + + fn as_iter(&'it self) -> Self::IntoIter { + self.base.as_iter() + } +} + +impl<'it, M> AsIterMut<'it> for HitcountsIterableMapObserver +where + M: Named + Serialize + serde::de::DeserializeOwned + AsIterMut<'it, Item = u8>, +{ + type RefMut = >::RefMut; + type IntoIterMut = >::IntoIterMut; + + fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { + self.base.as_iter_mut() + } +} + +impl<'it, M> IntoIterator for &'it HitcountsIterableMapObserver +where + M: Serialize + serde::de::DeserializeOwned, + &'it M: IntoIterator, +{ + type Item = &'it u8; + type IntoIter = <&'it M as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.base.into_iter() + } +} + +impl<'it, M> IntoIterator for &'it mut HitcountsIterableMapObserver +where + M: Serialize + serde::de::DeserializeOwned, + &'it mut M: IntoIterator, +{ + type Item = &'it mut u8; + type IntoIter = <&'it mut M as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.base.into_iter() + } +} + +impl HitcountsIterableMapObserver +where + M: Serialize + serde::de::DeserializeOwned, + for<'it> &'it M: IntoIterator, +{ + /// Returns an iterator over the map. + pub fn iter(&self) -> <&M as IntoIterator>::IntoIter { + <&Self as IntoIterator>::into_iter(self) + } +} + +impl HitcountsIterableMapObserver +where + M: Serialize + serde::de::DeserializeOwned, + for<'it> &'it mut M: IntoIterator, +{ + /// Returns a mutable iterator over the map. + pub fn iter_mut(&mut self) -> <&mut M as IntoIterator>::IntoIter { + <&mut Self as IntoIterator>::into_iter(self) + } +} + +impl DifferentialObserver for HitcountsIterableMapObserver +where + M: MapObserver + Observer + DifferentialObserver, + for<'it> M: AsIterMut<'it, Item = u8>, + OTA: ObserversTuple, + OTB: ObserversTuple, + S: UsesInput, +{ + fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { + self.base.pre_observe_first(observers) + } + + fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { + self.base.post_observe_first(observers) + } + + fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { + self.base.pre_observe_second(observers) + } + + fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { + self.base.post_observe_second(observers) + } +} diff --git a/libafl/src/observers/map/mod.rs b/libafl/src/observers/map/mod.rs new file mode 100644 index 0000000000..a5fb8d3e26 --- /dev/null +++ b/libafl/src/observers/map/mod.rs @@ -0,0 +1,932 @@ +//! All the map observer variants + +use alloc::{borrow::Cow, vec::Vec}; +use core::{ + fmt::Debug, + hash::{Hash, Hasher}, + ops::{Deref, DerefMut}, + slice::{Iter, IterMut}, +}; + +use ahash::RandomState; +use libafl_bolts::{ownedref::OwnedMutSlice, AsSlice, AsSliceMut, HasLen, Named, Truncate}; +use num_traits::Bounded; +use serde::{Deserialize, Serialize}; + +use crate::{ + executors::ExitKind, + inputs::UsesInput, + observers::{DifferentialObserver, Observer, ObserversTuple}, + Error, +}; + +pub mod const_map; +pub use const_map::*; + +pub mod variable_map; +pub use variable_map::*; + +pub mod hitcount_map; +pub use hitcount_map::*; + +pub mod multi_map; +pub use multi_map::*; + +pub mod owned_map; +pub use owned_map::*; + +/// Trait marker which indicates that this [`MapObserver`] is tracked for indices or novelties. +/// Implementors of feedbacks similar to [`crate::feedbacks::MapFeedback`] may wish to use this to +/// ensure that edge metadata is recorded as is appropriate for the provided observer. +/// +/// If you get a type constraint failure for your map due to this type being unfulfilled, you must +/// call [`CanTrack::track_indices`] or [`CanTrack::track_novelties`] **at +/// the initialisation site of your map**. +/// +/// This trait allows various components which interact with map metadata to ensure that the +/// information they need is actually recorded by the map feedback. +/// For example, if you are using [`crate::schedulers::MinimizerScheduler`]: +/// ``` +/// # use libafl::corpus::InMemoryCorpus; +/// # use libafl::feedbacks::{Feedback, MapFeedbackMetadata}; +/// use libafl::feedbacks::MaxMapFeedback; +/// # use libafl::inputs::BytesInput; +/// use libafl::observers::{StdMapObserver, CanTrack}; +/// use libafl::schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}; +/// # use libafl::state::StdState; +/// # use libafl_bolts::serdeany::RegistryBuilder; +/// # +/// # #[cfg(any(not(feature = "serdeany_autoreg"), miri))] +/// # unsafe { MapFeedbackMetadata::::register() } +/// # #[cfg(not(feature = "std"))] +/// # #[no_mangle] +/// # pub extern "C" fn external_current_millis() -> u64 { 0 } +/// +/// use libafl_bolts::ownedref::OwnedMutSlice; +/// # use libafl_bolts::rands::StdRand; +/// +/// // initialise your map as necessary +/// let edges_observer = StdMapObserver::from_ownedref("edges", OwnedMutSlice::from(vec![0u8; 16])); +/// // inform the feedback to track indices (required by IndexesLenTimeMinimizerScheduler), but not novelties +/// // this *MUST* be done before it is passed to MaxMapFeedback! +/// let edges_observer = edges_observer.track_indices(); +/// +/// // init the feedback +/// let mut feedback = MaxMapFeedback::new(&edges_observer); +/// # +/// # // init the state +/// # let mut state = StdState::new( +/// # StdRand::with_seed(0), +/// # InMemoryCorpus::::new(), +/// # InMemoryCorpus::new(), +/// # &mut feedback, +/// # &mut () +/// # ).unwrap(); +/// # feedback.init_state(&mut state).unwrap(); +/// +/// let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); +/// # scheduler.cull(&state).unwrap(); +/// ``` +/// +/// [`MapObserver`] implementors: see [`StdMapObserver`] for an example implementation. +pub trait CanTrack { + /// The resulting type of enabling index tracking. + type WithIndexTracking: CanTrack; + /// The resulting type of enabling novelty tracking. + type WithNoveltiesTracking: CanTrack; + + /// Whether indices should be tracked for this [`MapObserver`]. + const INDICES: bool; + /// Whether novelties should be tracked for this [`MapObserver`]. + const NOVELTIES: bool; + + /// Convert this map observer into one that tracks indices. + fn track_indices(self) -> Self::WithIndexTracking; + /// Convert this map observer into one that tracks novelties. + fn track_novelties(self) -> Self::WithNoveltiesTracking; +} + +/// Struct which wraps [`MapObserver`] instances to explicitly give them tracking data. +/// +/// # Safety +/// +/// This is a bit of a magic structure. We pass it to the observer tuple as itself, but when its +/// referred to with `match_name`, there is a cast from this type to its inner type. This is +/// *guaranteed to be safe* by `#[repr(transparent)]`. +#[derive(Copy, Clone, Debug, Deserialize, Serialize)] +pub struct ExplicitTracking(T); + +impl CanTrack for ExplicitTracking { + type WithIndexTracking = ExplicitTracking; + type WithNoveltiesTracking = ExplicitTracking; + const INDICES: bool = ITH; + const NOVELTIES: bool = NTH; + + fn track_indices(self) -> Self::WithIndexTracking { + ExplicitTracking::(self.0) + } + + fn track_novelties(self) -> Self::WithNoveltiesTracking { + ExplicitTracking::(self.0) + } +} + +impl AsRef for ExplicitTracking { + fn as_ref(&self) -> &T { + &self.0 + } +} + +impl AsMut for ExplicitTracking { + fn as_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl Named for ExplicitTracking +where + T: Named, +{ + fn name(&self) -> &Cow<'static, str> { + self.0.name() + } +} + +impl Observer for ExplicitTracking +where + S: UsesInput, + T: Observer, +{ + fn flush(&mut self) -> Result<(), Error> { + self.0.flush() + } + + fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { + self.0.pre_exec(state, input) + } + + fn post_exec( + &mut self, + state: &mut S, + input: &S::Input, + exit_kind: &ExitKind, + ) -> Result<(), Error> { + self.0.post_exec(state, input, exit_kind) + } + + fn pre_exec_child(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { + self.0.pre_exec_child(state, input) + } + + fn post_exec_child( + &mut self, + state: &mut S, + input: &S::Input, + exit_kind: &ExitKind, + ) -> Result<(), Error> { + self.0.post_exec_child(state, input, exit_kind) + } + + fn observes_stdout(&self) -> bool { + self.0.observes_stdout() + } + + fn observes_stderr(&self) -> bool { + self.0.observes_stderr() + } + + fn observe_stdout(&mut self, stdout: &[u8]) { + self.0.observe_stdout(stdout); + } + + fn observe_stderr(&mut self, stderr: &[u8]) { + self.0.observe_stderr(stderr); + } +} + +impl DifferentialObserver + for ExplicitTracking +where + OTA: ObserversTuple, + OTB: ObserversTuple, + S: UsesInput, + T: DifferentialObserver, +{ + fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { + self.as_mut().pre_observe_first(observers) + } + + fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { + self.as_mut().post_observe_first(observers) + } + + fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { + self.as_mut().pre_observe_second(observers) + } + + fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { + self.as_mut().post_observe_second(observers) + } +} + +/// Module which holds the necessary functions and types for map-relevant macros, namely +/// [`crate::require_index_tracking`] and [`crate::require_novelties_tracking`]. +pub mod macros { + pub use const_format::{concatcp, str_repeat}; + pub use const_panic::{concat_panic, FmtArg}; + + /// Use in the constructor of your component which requires index tracking of a + /// [`super::MapObserver`]. See [`super::CanTrack`] for details. + /// + /// As an example, if you are developing the type `MyCustomScheduler` which requires novelty + /// tracking, use this in your constructor: + /// ``` + /// # use libafl::observers::{MapObserver, CanTrack}; + /// # use libafl::require_index_tracking; + /// # use core::marker::PhantomData; + /// # + /// # struct MyCustomScheduler { + /// # phantom: PhantomData<(C, O)>, + /// # } + /// # + /// impl MyCustomScheduler where O: MapObserver, C: CanTrack + AsRef { + /// pub fn new(obs: &C) -> Self { + /// require_index_tracking!("MyCustomScheduler", C); + /// todo!("Construct your type") + /// } + /// } + /// ``` + #[macro_export] + macro_rules! require_index_tracking { + ($name: literal, $obs: ident) => { + struct SanityCheck { + phantom: ::core::marker::PhantomData, + } + + impl SanityCheck { + #[rustfmt::skip] + const MESSAGE: &'static str = { + const LINE_OFFSET: usize = line!().ilog10() as usize + 2; + const SPACING: &str = $crate::observers::map::macros::str_repeat!(" ", LINE_OFFSET); + $crate::observers::map::macros::concatcp!( + "\n", + SPACING, "|\n", + SPACING, "= note: index tracking is required by ", $name, "\n", + SPACING, "= note: see the documentation of CanTrack for details\n", + SPACING, "|\n", + SPACING, "= hint: call `.track_indices()` on the map observer passed to ", $name, " at the point where it is defined\n", + SPACING, "|\n", + SPACING, "| ", + ) + }; + const TRACKING_SANITY: bool = { + if !O::INDICES { + panic!("{}", Self::MESSAGE) + } else { + true + } + }; + + #[inline(always)] + fn check_sanity() { + if !Self::TRACKING_SANITY { + unreachable!("{}", Self::MESSAGE); + } + } + } + SanityCheck::<$obs>::check_sanity(); // check that tracking is enabled for this map + }; + } + + /// Use in the constructor of your component which requires novelties tracking of a + /// [`super::MapObserver`]. See [`super::CanTrack`] for details on the concept. + /// + /// As an example, if you are developing the type `MyCustomScheduler` which requires novelty + /// tracking, use this in your constructor: + /// ``` + /// # use libafl::observers::{MapObserver, CanTrack}; + /// # use libafl::require_novelties_tracking; + /// # use core::marker::PhantomData; + /// # + /// # struct MyCustomScheduler { + /// # phantom: PhantomData<(C, O)>, + /// # } + /// # + /// impl MyCustomScheduler where O: MapObserver, C: CanTrack + AsRef { + /// pub fn new(obs: &C) -> Self { + /// require_novelties_tracking!("MyCustomScheduler", C); + /// todo!("Construct your type") + /// } + /// } + /// ``` + #[macro_export] + macro_rules! require_novelties_tracking { + ($name: literal, $obs: ident) => { + struct SanityCheck { + phantom: ::core::marker::PhantomData, + } + + impl SanityCheck { + #[rustfmt::skip] + const MESSAGE: &'static str = { + const LINE_OFFSET: usize = line!().ilog10() as usize + 2; + const SPACING: &str = + $crate::observers::map::macros::str_repeat!(" ", LINE_OFFSET); + $crate::observers::map::macros::concatcp!( + "\n", + SPACING, "|\n", + SPACING, "= note: novelty tracking is required by ", $name, "\n", + SPACING, "= note: see the documentation of CanTrack for details\n", + SPACING, "|\n", + SPACING, "= hint: call `.track_novelties()` on the map observer passed to ", $name, " at the point where it is defined\n", + SPACING, "|\n", + SPACING, "| ", + ) + }; + const TRACKING_SANITY: bool = { + if !O::NOVELTIES { + panic!("{}", Self::MESSAGE) + } else { + true + } + }; + + #[inline(always)] + fn check_sanity() { + if !Self::TRACKING_SANITY { + unreachable!("{}", Self::MESSAGE); + } + } + } + SanityCheck::<$obs>::check_sanity(); // check that tracking is enabled for this map + }; + } +} + +/// A [`MapObserver`] observes the static map, as oftentimes used for AFL-like coverage information +/// +/// When referring to this type in a constraint (e.g. `O: MapObserver`), ensure that you only refer +/// to instances of a second type, e.g. `C: AsRef` or `A: AsMut`. Map observer instances are +/// passed around in a way that may be potentially wrapped by e.g. [`ExplicitTracking`] as a way to +/// encode metadata into the type. This is an unfortunate additional requirement that we can't get +/// around without specialization. +/// +/// See [`crate::require_index_tracking`] for an example of how to do so. +/// +/// TODO: enforce `iter() -> AssociatedTypeIter` when generic associated types stabilize +pub trait MapObserver: + HasLen + Named + Serialize + serde::de::DeserializeOwned + AsRef + AsMut + Hash +// where +// for<'it> &'it Self: IntoIterator +{ + /// Type of each entry in this map + type Entry: Bounded + PartialEq + Default + Copy + Debug + Hash + 'static; + + /// Get the value at `idx` + fn get(&self, idx: usize) -> Self::Entry; + + /// Set the value at `idx` + fn set(&mut self, idx: usize, val: Self::Entry); + + /// Get the number of usable entries in the map (all by default) + fn usable_count(&self) -> usize; + + /// Count the set bytes in the map + fn count_bytes(&self) -> u64; + + /// Compute the hash of the map without needing to provide a hasher + fn hash_simple(&self) -> u64; + + /// Get the initial value for `reset()` + fn initial(&self) -> Self::Entry; + + /// Reset the map + fn reset_map(&mut self) -> Result<(), Error>; + + /// Get these observer's contents as [`Vec`] + fn to_vec(&self) -> Vec; + + /// Get the number of set entries with the specified indexes + fn how_many_set(&self, indexes: &[usize]) -> usize; +} + +impl CanTrack for M +where + M: MapObserver, +{ + type WithIndexTracking = ExplicitTracking; + type WithNoveltiesTracking = ExplicitTracking; + const INDICES: bool = false; + const NOVELTIES: bool = false; + + fn track_indices(self) -> Self::WithIndexTracking { + ExplicitTracking::(self) + } + + fn track_novelties(self) -> Self::WithNoveltiesTracking { + ExplicitTracking::(self) + } +} + +/// The Map Observer retrieves the state of a map, +/// that will get updated by the target. +/// A well-known example is the AFL-Style coverage map. +#[derive(Clone, Serialize, Deserialize, Debug)] +#[serde(bound = "T: serde::de::DeserializeOwned")] +#[allow(clippy::unsafe_derive_deserialize)] +pub struct StdMapObserver<'a, T, const DIFFERENTIAL: bool> +where + T: Default + Copy + 'static + Serialize, +{ + map: OwnedMutSlice<'a, T>, + initial: T, + name: Cow<'static, str>, +} + +impl<'a, S, T> Observer for StdMapObserver<'a, T, false> +where + S: UsesInput, + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + #[inline] + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { + self.reset_map() + } +} + +impl<'a, S, T> Observer for StdMapObserver<'a, T, true> +where + S: UsesInput, + T: Bounded + + PartialEq + + Default + + Copy + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ +} + +impl<'a, T, const DIFFERENTIAL: bool> Named for StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +impl<'a, T, const DIFFERENTIAL: bool> HasLen for StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn len(&self) -> usize { + self.map.as_slice().len() + } +} + +impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator for &'it StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + type Item = as Iterator>::Item; + type IntoIter = Iter<'it, T>; + + fn into_iter(self) -> Self::IntoIter { + let cnt = self.usable_count(); + self.as_slice()[..cnt].iter() + } +} + +impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator + for &'it mut StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + type Item = as Iterator>::Item; + type IntoIter = IterMut<'it, T>; + + fn into_iter(self) -> Self::IntoIter { + let cnt = self.usable_count(); + self.as_slice_mut()[..cnt].iter_mut() + } +} + +impl<'a, T, const DIFFERENTIAL: bool> StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + /// Returns an iterator over the map. + pub fn iter(&self) -> Iter<'_, T> { + <&Self as IntoIterator>::into_iter(self) + } + + /// Returns a mutable iterator over the map. + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + <&mut Self as IntoIterator>::into_iter(self) + } +} + +impl<'a, T, const DIFFERENTIAL: bool> Hash for StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + #[inline] + fn hash(&self, hasher: &mut H) { + self.as_slice().hash(hasher); + } +} + +impl<'a, T, const DIFFERENTIAL: bool> AsRef for StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Default + Copy + 'static + Serialize, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl<'a, T, const DIFFERENTIAL: bool> AsMut for StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Default + Copy + 'static + Serialize, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + +impl<'a, T, const DIFFERENTIAL: bool> MapObserver for StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + type Entry = T; + + #[inline] + fn get(&self, pos: usize) -> T { + self.as_slice()[pos] + } + + fn set(&mut self, pos: usize, val: T) { + self.map.as_slice_mut()[pos] = val; + } + + /// Count the set bytes in the map + fn count_bytes(&self) -> u64 { + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice(); + let mut res = 0; + for x in &map[0..cnt] { + if *x != initial { + res += 1; + } + } + res + } + + #[inline] + fn usable_count(&self) -> usize { + self.as_slice().len() + } + + #[inline] + fn hash_simple(&self) -> u64 { + RandomState::with_seeds(0, 0, 0, 0).hash_one(self) + } + + #[inline] + fn initial(&self) -> T { + self.initial + } + + fn to_vec(&self) -> Vec { + self.as_slice().to_vec() + } + + /// Reset the map + #[inline] + fn reset_map(&mut self) -> Result<(), Error> { + // Normal memset, see https://rust.godbolt.org/z/Trs5hv + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice_mut(); + for x in &mut map[0..cnt] { + *x = initial; + } + Ok(()) + } + + fn how_many_set(&self, indexes: &[usize]) -> usize { + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice(); + let mut res = 0; + for i in indexes { + if *i < cnt && map[*i] != initial { + res += 1; + } + } + res + } +} + +impl<'a, T, const DIFFERENTIAL: bool> Truncate for StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Bounded + + PartialEq + + Default + + Copy + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + fn truncate(&mut self, new_len: usize) { + self.map.truncate(new_len); + } +} + +impl<'a, T, const DIFFERENTIAL: bool> Deref for StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, +{ + type Target = [T]; + fn deref(&self) -> &[T] { + &self.map + } +} + +impl<'a, T, const DIFFERENTIAL: bool> DerefMut for StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, +{ + fn deref_mut(&mut self) -> &mut [T] { + &mut self.map + } +} + +impl<'a, T, const DIFFERENTIAL: bool> StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, +{ + /// Creates a new [`MapObserver`] + /// + /// # Safety + /// Will get a pointer to the map and dereference it at any point in time. + /// The map must not move in memory! + #[must_use] + unsafe fn maybe_differential(name: S, map: &'a mut [T]) -> Self + where + S: Into>, + { + let len = map.len(); + let ptr = map.as_mut_ptr(); + Self::maybe_differential_from_mut_ptr(name, ptr, len) + } + + /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] + #[must_use] + fn maybe_differential_from_mut_slice(name: S, map: OwnedMutSlice<'a, T>) -> Self + where + S: Into>, + { + StdMapObserver { + name: name.into(), + map, + initial: T::default(), + } + } + + /// Creates a new [`MapObserver`] with an owned map + #[must_use] + fn maybe_differential_owned(name: S, map: Vec) -> Self + where + S: Into>, + { + Self { + map: OwnedMutSlice::from(map), + name: name.into(), + initial: T::default(), + } + } + + /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] map. + /// + /// # Safety + /// Will dereference the owned slice with up to len elements. + #[must_use] + fn maybe_differential_from_ownedref(name: S, map: OwnedMutSlice<'a, T>) -> Self + where + S: Into>, + { + Self { + map, + name: name.into(), + initial: T::default(), + } + } + + /// Creates a new [`MapObserver`] from a raw pointer + /// + /// # Safety + /// Will dereference the `map_ptr` with up to len elements. + unsafe fn maybe_differential_from_mut_ptr(name: S, map_ptr: *mut T, len: usize) -> Self + where + S: Into>, + { + Self::maybe_differential_from_mut_slice( + name, + OwnedMutSlice::from_raw_parts_mut(map_ptr, len), + ) + } + + /// Gets the initial value for this map, mutably + pub fn initial_mut(&mut self) -> &mut T { + &mut self.initial + } + + /// Gets the backing for this map + pub fn map(&self) -> &OwnedMutSlice<'a, T> { + &self.map + } + + /// Gets the backing for this map mutably + pub fn map_mut(&mut self) -> &mut OwnedMutSlice<'a, T> { + &mut self.map + } +} + +impl<'a, T> StdMapObserver<'a, T, false> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, +{ + /// Creates a new [`MapObserver`] + /// + /// # Safety + /// The observer will keep a pointer to the map. + /// Hence, the map may never move in memory. + #[must_use] + pub unsafe fn new(name: S, map: &'a mut [T]) -> Self + where + S: Into>, + { + Self::maybe_differential(name, map) + } + + /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] + pub fn from_mut_slice(name: S, map: OwnedMutSlice<'a, T>) -> Self + where + S: Into>, + { + Self::maybe_differential_from_mut_slice(name, map) + } + + /// Creates a new [`MapObserver`] with an owned map + #[must_use] + pub fn owned(name: S, map: Vec) -> Self + where + S: Into>, + { + Self::maybe_differential_owned(name, map) + } + + /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] map. + /// + /// # Note + /// Will dereference the owned slice with up to len elements. + #[must_use] + pub fn from_ownedref(name: S, map: OwnedMutSlice<'a, T>) -> Self + where + S: Into>, + { + Self::maybe_differential_from_ownedref(name, map) + } + + /// Creates a new [`MapObserver`] from a raw pointer + /// + /// # Safety + /// Will dereference the `map_ptr` with up to len elements. + pub unsafe fn from_mut_ptr(name: S, map_ptr: *mut T, len: usize) -> Self + where + S: Into>, + { + Self::maybe_differential_from_mut_ptr(name, map_ptr, len) + } +} + +impl<'a, T> StdMapObserver<'a, T, true> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, +{ + /// Creates a new [`MapObserver`] in differential mode + /// + /// # Safety + /// Will get a pointer to the map and dereference it at any point in time. + /// The map must not move in memory! + #[must_use] + pub unsafe fn differential(name: S, map: &'a mut [T]) -> Self + where + S: Into>, + { + Self::maybe_differential(name, map) + } + + /// Creates a new [`MapObserver`] with an owned map in differential mode + #[must_use] + pub fn differential_owned(name: S, map: Vec) -> Self + where + S: Into>, + { + Self::maybe_differential_owned(name, map) + } + + /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] map in differential mode. + /// + /// # Note + /// Will dereference the owned slice with up to len elements. + #[must_use] + pub fn differential_from_ownedref(name: S, map: OwnedMutSlice<'a, T>) -> Self + where + S: Into>, + { + Self::maybe_differential_from_ownedref(name, map) + } + + /// Creates a new [`MapObserver`] from a raw pointer in differential mode + /// + /// # Safety + /// Will dereference the `map_ptr` with up to len elements. + pub unsafe fn differential_from_mut_ptr(name: S, map_ptr: *mut T, len: usize) -> Self + where + S: Into>, + { + Self::maybe_differential_from_mut_ptr(name, map_ptr, len) + } +} + +impl<'a, OTA, OTB, S, T> DifferentialObserver for StdMapObserver<'a, T, true> +where + OTA: ObserversTuple, + OTB: ObserversTuple, + S: UsesInput, + T: Bounded + + PartialEq + + Default + + Copy + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ +} diff --git a/libafl/src/observers/map/multi_map.rs b/libafl/src/observers/map/multi_map.rs new file mode 100644 index 0000000000..0a835e4969 --- /dev/null +++ b/libafl/src/observers/map/multi_map.rs @@ -0,0 +1,356 @@ +//! An observer that takes multiple pointers or slices to observe + +use alloc::{borrow::Cow, vec::Vec}; +use core::{ + fmt::Debug, + hash::{Hash, Hasher}, + iter::Flatten, + mem::size_of, + slice::{self, Iter, IterMut}, +}; + +use ahash::RandomState; +use libafl_bolts::{ + ownedref::OwnedMutSlice, AsIter, AsIterMut, AsSlice, AsSliceMut, HasLen, Named, +}; +use meminterval::IntervalTree; +use num_traits::Bounded; +use serde::{Deserialize, Serialize}; + +use crate::{ + inputs::UsesInput, + observers::{map::MapObserver, DifferentialObserver, Observer, ObserversTuple}, + Error, +}; + +/// The Multi Map Observer merge different maps into one observer +#[derive(Serialize, Deserialize, Debug)] +#[serde(bound = "T: serde::de::DeserializeOwned")] +#[allow(clippy::unsafe_derive_deserialize)] +pub struct MultiMapObserver<'a, T, const DIFFERENTIAL: bool> +where + T: 'static + Default + Copy + Serialize + Debug, +{ + maps: Vec>, + intervals: IntervalTree, + len: usize, + initial: T, + name: Cow<'static, str>, + iter_idx: usize, +} + +impl<'a, S, T> Observer for MultiMapObserver<'a, T, false> +where + S: UsesInput, + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, + Self: MapObserver, +{ + #[inline] + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { + self.reset_map() + } +} + +impl<'a, S, T> Observer for MultiMapObserver<'a, T, true> +where + S: UsesInput, + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, + Self: MapObserver, +{ + // in differential mode, we are *not* responsible for resetting the map! +} + +impl<'a, T, const DIFFERENTIAL: bool> Named for MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + #[inline] + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +impl<'a, T, const DIFFERENTIAL: bool> HasLen for MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + #[inline] + fn len(&self) -> usize { + self.len + } +} + +impl<'a, T, const DIFFERENTIAL: bool> Hash for MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + fn hash(&self, hasher: &mut H) { + for map in &self.maps { + let slice = map.as_slice(); + let ptr = slice.as_ptr() as *const u8; + let map_size = slice.len() / size_of::(); + unsafe { + hasher.write(slice::from_raw_parts(ptr, map_size)); + } + } + } +} + +impl<'a, T, const DIFFERENTIAL: bool> AsRef for MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + Debug, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl<'a, T, const DIFFERENTIAL: bool> AsMut for MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + Debug, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + +impl<'a, T, const DIFFERENTIAL: bool> MapObserver for MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + + Bounded + + PartialEq + + Default + + Copy + + Hash + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + type Entry = T; + + #[inline] + fn get(&self, idx: usize) -> T { + let elem = self.intervals.query(idx..=idx).next().unwrap(); + let i = *elem.value; + let j = idx - elem.interval.start; + self.maps[i].as_slice()[j] + } + + #[inline] + fn set(&mut self, idx: usize, val: Self::Entry) { + let elem = self.intervals.query(idx..=idx).next().unwrap(); + let i = *elem.value; + let j = idx - elem.interval.start; + self.maps[i].as_slice_mut()[j] = val; + } + + #[inline] + fn initial(&self) -> T { + self.initial + } + + fn count_bytes(&self) -> u64 { + let initial = self.initial(); + let mut res = 0; + for map in &self.maps { + for x in map.as_slice() { + if *x != initial { + res += 1; + } + } + } + res + } + + #[inline] + fn hash_simple(&self) -> u64 { + RandomState::with_seeds(0, 0, 0, 0).hash_one(self) + } + + fn reset_map(&mut self) -> Result<(), Error> { + let initial = self.initial(); + for map in &mut self.maps { + for x in map.as_slice_mut() { + *x = initial; + } + } + Ok(()) + } + + fn usable_count(&self) -> usize { + self.len() + } + + fn to_vec(&self) -> Vec { + let cnt = self.usable_count(); + let mut res = Vec::with_capacity(cnt); + for i in 0..cnt { + res.push(self.get(i)); + } + res + } + + /// Get the number of set entries with the specified indexes + fn how_many_set(&self, indexes: &[usize]) -> usize { + let initial = self.initial(); + let cnt = self.usable_count(); + let mut res = 0; + for i in indexes { + if *i < cnt && self.get(*i) != initial { + res += 1; + } + } + res + } +} + +impl<'a, T, const DIFFERENTIAL: bool> MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + /// Creates a new [`MultiMapObserver`], maybe in differential mode + #[must_use] + fn maybe_differential(name: &'static str, maps: Vec>) -> Self { + let mut idx = 0; + let mut intervals = IntervalTree::new(); + for (v, x) in maps.iter().enumerate() { + let l = x.as_slice().len(); + intervals.insert(idx..(idx + l), v); + idx += l; + } + Self { + maps, + intervals, + len: idx, + name: Cow::from(name), + initial: T::default(), + iter_idx: 0, + } + } +} + +impl<'a, T> MultiMapObserver<'a, T, true> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + /// Creates a new [`MultiMapObserver`] in differential mode + #[must_use] + pub fn differential(name: &'static str, maps: Vec>) -> Self { + Self::maybe_differential(name, maps) + } +} + +impl<'a, T> MultiMapObserver<'a, T, false> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + /// Creates a new [`MultiMapObserver`] + #[must_use] + pub fn new(name: &'static str, maps: Vec>) -> Self { + Self::maybe_differential(name, maps) + } + + /// Creates a new [`MultiMapObserver`] with an owned map + #[must_use] + pub fn owned(name: &'static str, maps: Vec>) -> Self { + let mut idx = 0; + let mut v = 0; + let mut intervals = IntervalTree::new(); + let maps: Vec<_> = maps + .into_iter() + .map(|x| { + let l = x.len(); + intervals.insert(idx..(idx + l), v); + idx += l; + v += 1; + OwnedMutSlice::from(x) + }) + .collect(); + Self { + maps, + intervals, + len: idx, + name: Cow::from(name), + initial: T::default(), + iter_idx: 0, + } + } +} + +impl<'a, 'it, T, const DIFFERENTIAL: bool> AsIter<'it> for MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, + 'a: 'it, +{ + type Item = T; + type Ref = &'it T; + type IntoIter = Flatten>>; + + fn as_iter(&'it self) -> Self::IntoIter { + self.maps.iter().flatten() + } +} + +impl<'a, 'it, T, const DIFFERENTIAL: bool> AsIterMut<'it> for MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, + 'a: 'it, +{ + type RefMut = &'it mut T; + type IntoIterMut = Flatten>>; + + fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { + self.maps.iter_mut().flatten() + } +} + +impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator + for &'it MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + type Item = as Iterator>::Item; + type IntoIter = Flatten>>; + + fn into_iter(self) -> Self::IntoIter { + self.maps.iter().flatten() + } +} + +impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator + for &'it mut MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + type Item = as Iterator>::Item; + type IntoIter = Flatten>>; + + fn into_iter(self) -> Self::IntoIter { + self.maps.iter_mut().flatten() + } +} + +impl<'a, T, const DIFFERENTIAL: bool> MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + /// Returns an iterator over the map. + pub fn iter(&self) -> <&Self as IntoIterator>::IntoIter { + <&Self as IntoIterator>::into_iter(self) + } + + /// Returns a mutable iterator over the map. + pub fn iter_mut(&mut self) -> <&mut Self as IntoIterator>::IntoIter { + <&mut Self as IntoIterator>::into_iter(self) + } +} + +impl<'a, T, OTA, OTB, S> DifferentialObserver for MultiMapObserver<'a, T, true> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, + Self: MapObserver, + OTA: ObserversTuple, + OTB: ObserversTuple, + S: UsesInput, +{ +} diff --git a/libafl/src/observers/map/owned_map.rs b/libafl/src/observers/map/owned_map.rs new file mode 100644 index 0000000000..518eb9d2da --- /dev/null +++ b/libafl/src/observers/map/owned_map.rs @@ -0,0 +1,251 @@ +//! An observer that owns its map + +use alloc::{borrow::Cow, vec::Vec}; +use core::{ + fmt::Debug, + hash::{Hash, Hasher}, + ops::{Deref, DerefMut}, + slice::{Iter, IterMut}, +}; + +use ahash::RandomState; +use libafl_bolts::{AsSlice, AsSliceMut, HasLen, Named}; +use num_traits::Bounded; +use serde::{Deserialize, Serialize}; + +use crate::{ + inputs::UsesInput, + observers::{map::MapObserver, Observer}, + Error, +}; + +/// Exact copy of `StdMapObserver` that owns its map +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(bound = "T: serde::de::DeserializeOwned")] +#[allow(clippy::unsafe_derive_deserialize)] +pub struct OwnedMapObserver +where + T: 'static + Default + Copy + Serialize, +{ + map: Vec, + initial: T, + name: Cow<'static, str>, +} + +impl Observer for OwnedMapObserver +where + S: UsesInput, + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, + Self: MapObserver, +{ + #[inline] + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { + self.reset_map() + } +} + +impl Named for OwnedMapObserver +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +impl HasLen for OwnedMapObserver +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn len(&self) -> usize { + self.map.as_slice().len() + } +} + +impl<'it, T> IntoIterator for &'it OwnedMapObserver +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + type Item = as Iterator>::Item; + type IntoIter = Iter<'it, T>; + + fn into_iter(self) -> Self::IntoIter { + self.as_slice().iter() + } +} + +impl<'it, T> IntoIterator for &'it mut OwnedMapObserver +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + type Item = as Iterator>::Item; + type IntoIter = IterMut<'it, T>; + + fn into_iter(self) -> Self::IntoIter { + self.as_slice_mut().iter_mut() + } +} + +impl OwnedMapObserver +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + /// Returns an iterator over the map. + pub fn iter(&self) -> Iter<'_, T> { + <&Self as IntoIterator>::into_iter(self) + } + + /// Returns a mutable iterator over the map. + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + <&mut Self as IntoIterator>::into_iter(self) + } +} + +impl Hash for OwnedMapObserver +where + T: 'static + Hash + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + #[inline] + fn hash(&self, hasher: &mut H) { + self.as_slice().hash(hasher); + } +} + +impl AsRef for OwnedMapObserver +where + T: 'static + Default + Copy + Serialize, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl AsMut for OwnedMapObserver +where + T: 'static + Default + Copy + Serialize, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + +impl MapObserver for OwnedMapObserver +where + T: 'static + + Bounded + + PartialEq + + Default + + Copy + + Hash + + Serialize + + serde::de::DeserializeOwned + + Debug, +{ + type Entry = T; + + #[inline] + fn get(&self, pos: usize) -> T { + self.as_slice()[pos] + } + + #[inline] + fn set(&mut self, pos: usize, val: Self::Entry) { + self.as_slice_mut()[pos] = val; + } + + /// Count the set bytes in the map + fn count_bytes(&self) -> u64 { + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice(); + let mut res = 0; + for x in &map[0..cnt] { + if *x != initial { + res += 1; + } + } + res + } + + #[inline] + fn usable_count(&self) -> usize { + self.as_slice().len() + } + + #[inline] + fn hash_simple(&self) -> u64 { + RandomState::with_seeds(0, 0, 0, 0).hash_one(self) + } + + #[inline] + fn initial(&self) -> T { + self.initial + } + + /// Reset the map + #[inline] + fn reset_map(&mut self) -> Result<(), Error> { + // Normal memset, see https://rust.godbolt.org/z/Trs5hv + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice_mut(); + for x in &mut map[0..cnt] { + *x = initial; + } + Ok(()) + } + fn to_vec(&self) -> Vec { + self.as_slice().to_vec() + } + + fn how_many_set(&self, indexes: &[usize]) -> usize { + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice(); + let mut res = 0; + for i in indexes { + if *i < cnt && map[*i] != initial { + res += 1; + } + } + res + } +} + +impl Deref for OwnedMapObserver +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + type Target = [T]; + + fn deref(&self) -> &[T] { + &self.map + } +} + +impl DerefMut for OwnedMapObserver +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, +{ + fn deref_mut(&mut self) -> &mut [T] { + &mut self.map + } +} + +impl OwnedMapObserver +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned, +{ + /// Creates a new [`MapObserver`] with an owned map + #[must_use] + pub fn new(name: &'static str, map: Vec) -> Self { + let initial = if map.is_empty() { T::default() } else { map[0] }; + Self { + map, + name: Cow::from(name), + initial, + } + } +} diff --git a/libafl/src/observers/map/variable_map.rs b/libafl/src/observers/map/variable_map.rs new file mode 100644 index 0000000000..381b837d0f --- /dev/null +++ b/libafl/src/observers/map/variable_map.rs @@ -0,0 +1,349 @@ +//! Map observer with a shrinkable size + +use alloc::{borrow::Cow, vec::Vec}; +use core::{ + fmt::Debug, + hash::{Hash, Hasher}, + ops::{Deref, DerefMut}, + slice::{Iter, IterMut}, +}; + +use ahash::RandomState; +use libafl_bolts::{ + ownedref::{OwnedMutPtr, OwnedMutSlice}, + AsSlice, AsSliceMut, HasLen, Named, +}; +use num_traits::Bounded; +use serde::{Deserialize, Serialize}; + +use crate::{ + inputs::UsesInput, + observers::{map::MapObserver, Observer}, + Error, +}; + +/// Overlooking a variable bitmap +#[derive(Serialize, Deserialize, Debug)] +#[serde(bound = "T: serde::de::DeserializeOwned")] +#[allow(clippy::unsafe_derive_deserialize)] +pub struct VariableMapObserver<'a, T> +where + T: Default + Copy + 'static + Serialize + PartialEq + Bounded, +{ + map: OwnedMutSlice<'a, T>, + size: OwnedMutPtr, + initial: T, + name: Cow<'static, str>, +} + +impl<'a, S, T> Observer for VariableMapObserver<'a, T> +where + S: UsesInput, + T: Default + + Copy + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug + + Bounded + + PartialEq, + Self: MapObserver, +{ + #[inline] + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { + self.reset_map() + } +} + +impl<'a, T> Named for VariableMapObserver<'a, T> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Bounded + PartialEq, +{ + #[inline] + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +impl<'a, T> HasLen for VariableMapObserver<'a, T> +where + T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + PartialEq + Bounded, +{ + #[inline] + fn len(&self) -> usize { + *self.size.as_ref() + } +} + +impl<'a, 'it, T> IntoIterator for &'it VariableMapObserver<'a, T> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug + + PartialEq + + Bounded, +{ + type Item = as Iterator>::Item; + type IntoIter = Iter<'it, T>; + + fn into_iter(self) -> Self::IntoIter { + let cnt = self.usable_count(); + self.as_slice()[..cnt].iter() + } +} + +impl<'a, 'it, T> IntoIterator for &'it mut VariableMapObserver<'a, T> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug + + PartialEq + + Bounded, +{ + type Item = as Iterator>::Item; + type IntoIter = IterMut<'it, T>; + + fn into_iter(self) -> Self::IntoIter { + let cnt = self.usable_count(); + self.as_slice_mut()[..cnt].iter_mut() + } +} + +impl<'a, T> VariableMapObserver<'a, T> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug + + PartialEq + + Bounded, +{ + /// Returns an iterator over the map. + pub fn iter(&self) -> Iter<'_, T> { + <&Self as IntoIterator>::into_iter(self) + } + + /// Returns a mutable iterator over the map. + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + <&mut Self as IntoIterator>::into_iter(self) + } +} + +impl<'a, T> Hash for VariableMapObserver<'a, T> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug + + PartialEq + + Bounded, +{ + #[inline] + fn hash(&self, hasher: &mut H) { + self.as_slice().hash(hasher); + } +} + +impl<'a, T> AsRef for VariableMapObserver<'a, T> +where + T: Default + Copy + 'static + Serialize + PartialEq + Bounded, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl<'a, T> AsMut for VariableMapObserver<'a, T> +where + T: Default + Copy + 'static + Serialize + PartialEq + Bounded, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + +impl<'a, T> MapObserver for VariableMapObserver<'a, T> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug + + PartialEq + + Bounded, +{ + type Entry = T; + + #[inline] + fn initial(&self) -> T { + self.initial + } + + #[inline] + fn usable_count(&self) -> usize { + *self.size.as_ref() + } + + fn get(&self, idx: usize) -> T { + self.map.as_slice()[idx] + } + + fn set(&mut self, idx: usize, val: T) { + self.map.as_slice_mut()[idx] = val; + } + + /// Count the set bytes in the map + fn count_bytes(&self) -> u64 { + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice(); + let mut res = 0; + for x in &map[0..cnt] { + if *x != initial { + res += 1; + } + } + res + } + + #[inline] + fn hash_simple(&self) -> u64 { + RandomState::with_seeds(0, 0, 0, 0).hash_one(self) + } + + /// Reset the map + #[inline] + fn reset_map(&mut self) -> Result<(), Error> { + // Normal memset, see https://rust.godbolt.org/z/Trs5hv + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice_mut(); + for x in &mut map[0..cnt] { + *x = initial; + } + Ok(()) + } + + fn to_vec(&self) -> Vec { + self.as_slice().to_vec() + } + + fn how_many_set(&self, indexes: &[usize]) -> usize { + let initial = self.initial(); + let cnt = self.usable_count(); + let map = self.as_slice(); + let mut res = 0; + for i in indexes { + if *i < cnt && map[*i] != initial { + res += 1; + } + } + res + } +} + +impl<'a, T> Deref for VariableMapObserver<'a, T> +where + T: Bounded + + PartialEq + + Default + + Copy + + Hash + + 'static + + Serialize + + serde::de::DeserializeOwned + + Debug + + PartialEq + + Bounded, +{ + type Target = [T]; + fn deref(&self) -> &[T] { + let cnt = self.usable_count(); + &self.map[..cnt] + } +} + +impl<'a, T> DerefMut for VariableMapObserver<'a, T> +where + T: 'static + + Default + + Copy + + Hash + + Serialize + + serde::de::DeserializeOwned + + Debug + + PartialEq + + Bounded, +{ + fn deref_mut(&mut self) -> &mut [T] { + let cnt = self.usable_count(); + &mut self.map[..cnt] + } +} + +impl<'a, T> VariableMapObserver<'a, T> +where + T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + PartialEq + Bounded, +{ + /// Creates a new [`MapObserver`] from an [`OwnedMutSlice`] + /// + /// # Safety + /// The observer will dereference the owned slice, as well as the `map_ptr`. + /// Dereferences `map_ptr` with up to `max_len` elements of size. + pub unsafe fn from_mut_slice( + name: &'static str, + map_slice: OwnedMutSlice<'a, T>, + size: *mut usize, + ) -> Self { + VariableMapObserver { + name: name.into(), + map: map_slice, + size: OwnedMutPtr::Ptr(size), + initial: T::default(), + } + } + + /// Creates a new [`MapObserver`] from a raw pointer + /// + /// # Safety + /// The observer will dereference the `size` ptr, as well as the `map_ptr`. + /// Dereferences `map_ptr` with up to `max_len` elements of size. + pub unsafe fn from_mut_ptr( + name: &'static str, + map_ptr: *mut T, + max_len: usize, + size: *mut usize, + ) -> Self { + Self::from_mut_slice( + name, + OwnedMutSlice::from_raw_parts_mut(map_ptr, max_len), + size, + ) + } +} diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index 5158a9a6b0..093f45f422 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -1,11 +1,6 @@ //! Observers give insights about runs of a target, such as coverage, timing, stack depth, and more. - -pub mod map; - use alloc::borrow::Cow; -pub use map::*; - pub mod cmp; pub use cmp::*; @@ -20,6 +15,8 @@ pub mod stacktrace; pub use stacktrace::*; pub mod concolic; +pub mod map; +pub use map::*; pub mod value;