From b0248461e27f35f26ca375cb257aa45311babd4f Mon Sep 17 00:00:00 2001 From: Langston Barrett Date: Sat, 27 Apr 2024 12:36:56 -0400 Subject: [PATCH] Allow for AsIter(Mut)/AsSlice(Mut) to be implemented in safe Rust (#2120) * Generalize `AsIter` to allow iterating over contents of a `RefCell` Towards `MapObserver`s in safe Rust. * Helpers for `RefCellValueObserver` * MapObserver: Return owned Self::Entry from .get() `Self::Entry` is `Copy`, so there's not much value in returning a reference from `get()`. Futhermore, returning a reference limits the possible implementations of `MapObserver`, because it forces the borrow/reset to outlive the body of the method. * MapObserver: Replace `.get_mut()` with `.set(idx, val)` Like the previous commit, this is intended to expand the possible implementations of `MapObserver` to types with interior mutability, which can't necessarily loan out their content. * Make `RefCellValueObserver` into a safe `MapObserver` * as iter mut * as slice (mut): allow for non-& refs * nostd * CI round 1 * cleanup + AsSlice defs for RefCellValueObserver * clippy fixes * avoid unnecessary imports * whoops, too aggressive * use deref instead of as slice * whoops * fix as slice conditional importing in stable --------- Co-authored-by: Addison Crump --- libafl/src/corpus/minimizer.rs | 2 +- libafl/src/feedbacks/map.rs | 49 +- libafl/src/mutators/scheduled.rs | 19 +- libafl/src/mutators/token_mutations.rs | 8 +- libafl/src/observers/cmp.rs | 27 +- libafl/src/observers/map.rs | 439 ++++-------------- libafl/src/observers/value.rs | 268 ++++++++++- libafl/src/schedulers/accounting.rs | 25 +- libafl/src/schedulers/minimizer.rs | 18 +- libafl_bolts/src/lib.rs | 129 ++--- libafl_bolts/src/llmp.rs | 10 +- libafl_bolts/src/os/unix_shmem_server.rs | 51 +- libafl_bolts/src/ownedref.rs | 33 +- libafl_bolts/src/shmem.rs | 171 +++---- .../symcc_runtime/src/filter/coverage.rs | 4 +- .../libafl_libfuzzer_runtime/src/observers.rs | 19 +- libafl_targets/src/sancov_8bit.rs | 19 +- 17 files changed, 620 insertions(+), 671 deletions(-) diff --git a/libafl/src/corpus/minimizer.rs b/libafl/src/corpus/minimizer.rs index 8793455f27..4cc57ba6fb 100644 --- a/libafl/src/corpus/minimizer.rs +++ b/libafl/src/corpus/minimizer.rs @@ -165,7 +165,7 @@ where // Store coverage, mapping coverage map indices to hit counts (if present) and the // associated seeds for the map indices with those hit counts. - for (i, e) in obs.as_iter().copied().enumerate() { + for (i, e) in obs.as_iter().map(|x| *x).enumerate() { if e != obs.initial() { cov_map .entry(i) diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index 98d9af8d1f..506b3ea9a9 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -6,12 +6,14 @@ use core::simd::prelude::SimdOrd; use core::{ fmt::Debug, marker::PhantomData, - ops::{BitAnd, BitOr}, + ops::{BitAnd, BitOr, Deref, DerefMut}, }; +#[rustversion::nightly] +use libafl_bolts::AsSlice; use libafl_bolts::{ tuples::{MatchNameRef, Reference, Referenceable}, - AsIter, AsSlice, AsSliceMut, HasRefCnt, Named, + AsIter, HasRefCnt, Named, }; use num_traits::PrimInt; use serde::{de::DeserializeOwned, Deserialize, Serialize}; @@ -235,19 +237,18 @@ pub struct MapIndexesMetadata { libafl_bolts::impl_serdeany!(MapIndexesMetadata); -impl AsSlice for MapIndexesMetadata { - type Entry = usize; +impl Deref for MapIndexesMetadata { + type Target = [usize]; /// Convert to a slice - fn as_slice(&self) -> &[usize] { - self.list.as_slice() + fn deref(&self) -> &[usize] { + &self.list } } -impl AsSliceMut for MapIndexesMetadata { - type Entry = usize; +impl DerefMut for MapIndexesMetadata { /// Convert to a slice - fn as_slice_mut(&mut self) -> &mut [usize] { - self.list.as_slice_mut() + fn deref_mut(&mut self) -> &mut [usize] { + &mut self.list } } @@ -282,21 +283,20 @@ pub struct MapNoveltiesMetadata { libafl_bolts::impl_serdeany!(MapNoveltiesMetadata); -impl AsSlice for MapNoveltiesMetadata { - type Entry = usize; +impl Deref for MapNoveltiesMetadata { + type Target = [usize]; /// Convert to a slice #[must_use] - fn as_slice(&self) -> &[usize] { - self.list.as_slice() + fn deref(&self) -> &[usize] { + &self.list } } -impl AsSliceMut for MapNoveltiesMetadata { - type Entry = usize; +impl DerefMut for MapNoveltiesMetadata { /// Convert to a slice #[must_use] - fn as_slice_mut(&mut self) -> &mut [usize] { - self.list.as_slice_mut() + fn deref_mut(&mut self) -> &mut [usize] { + &mut self.list } } @@ -469,13 +469,13 @@ where map_state.history_map.resize(len, observer.initial()); } - let history_map = map_state.history_map.as_slice_mut(); + let history_map = &mut map_state.history_map; if C::INDICES { let mut indices = Vec::new(); for (i, value) in observer .as_iter() - .copied() + .map(|x| *x) .enumerate() .filter(|(_, value)| *value != initial) { @@ -490,7 +490,7 @@ where } else { for (i, value) in observer .as_iter() - .copied() + .map(|x| *x) .enumerate() .filter(|(_, value)| *value != initial) { @@ -539,8 +539,7 @@ where #[rustversion::nightly] impl Feedback for MapFeedback where - O: MapObserver + AsSlice, - for<'it> O: AsIter<'it, Item = u8>, + O: MapObserver + for<'a> AsSlice<'a, Entry = u8> + for<'a> AsIter<'a, Item = u8>, S: State + HasNamedMetadata, C: CanTrack + AsRef + Observer, { @@ -756,7 +755,7 @@ where novelties.clear(); for (i, item) in observer .as_iter() - .copied() + .map(|x| *x) .enumerate() .filter(|(_, item)| *item != initial) { @@ -770,7 +769,7 @@ where } else { for (i, item) in observer .as_iter() - .copied() + .map(|x| *x) .enumerate() .filter(|(_, item)| *item != initial) { diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index f9e0ca8251..a4a5f095e5 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -4,12 +4,13 @@ use alloc::{borrow::Cow, vec::Vec}; use core::{ fmt::{self, Debug}, marker::PhantomData, + ops::{Deref, DerefMut}, }; use libafl_bolts::{ rands::Rand, tuples::{tuple_list, tuple_list_type, Merge, NamedTuple}, - AsSlice, AsSliceMut, Named, + Named, }; use serde::{Deserialize, Serialize}; @@ -45,18 +46,16 @@ pub struct LogMutationMetadata { libafl_bolts::impl_serdeany!(LogMutationMetadata); -impl AsSlice for LogMutationMetadata { - type Entry = Cow<'static, str>; - #[must_use] - fn as_slice(&self) -> &[Cow<'static, str>] { - self.list.as_slice() +impl Deref for LogMutationMetadata { + type Target = [Cow<'static, str>]; + fn deref(&self) -> &[Cow<'static, str>] { + &self.list } } -impl AsSliceMut for LogMutationMetadata { - type Entry = Cow<'static, str>; +impl DerefMut for LogMutationMetadata { #[must_use] - fn as_slice_mut(&mut self) -> &mut [Cow<'static, str>] { - self.list.as_slice_mut() + fn deref_mut(&mut self) -> &mut [Cow<'static, str>] { + &mut self.list } } diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 740ebb6c34..03d221a64a 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -6,7 +6,7 @@ use core::slice::from_raw_parts; use core::{ fmt::Debug, mem::size_of, - ops::{Add, AddAssign}, + ops::{Add, AddAssign, Deref}, slice::Iter, }; #[cfg(feature = "std")] @@ -272,9 +272,9 @@ where } } -impl AsSlice for Tokens { - type Entry = Vec; - fn as_slice(&self) -> &[Vec] { +impl Deref for Tokens { + type Target = [Vec]; + fn deref(&self) -> &[Vec] { self.tokens() } } diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index 294a04e5be..d438093a19 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -1,11 +1,15 @@ //! The `CmpObserver` provides access to the logged values of CMP instructions use alloc::{borrow::Cow, vec::Vec}; -use core::{fmt::Debug, marker::PhantomData}; +use core::{ + fmt::Debug, + marker::PhantomData, + ops::{Deref, DerefMut}, +}; use c2rust_bitfields::BitfieldStruct; use hashbrown::HashMap; -use libafl_bolts::{ownedref::OwnedRefMut, serdeany::SerdeAny, AsSlice, AsSliceMut, Named}; +use libafl_bolts::{ownedref::OwnedRefMut, serdeany::SerdeAny, Named}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{executors::ExitKind, inputs::UsesInput, observers::Observer, Error, HasMetadata}; @@ -83,21 +87,16 @@ pub struct CmpValuesMetadata { libafl_bolts::impl_serdeany!(CmpValuesMetadata); -impl AsSlice for CmpValuesMetadata { - type Entry = CmpValues; - /// Convert to a slice - #[must_use] - fn as_slice(&self) -> &[CmpValues] { - self.list.as_slice() +impl Deref for CmpValuesMetadata { + type Target = [CmpValues]; + fn deref(&self) -> &[CmpValues] { + &self.list } } -impl AsSliceMut for CmpValuesMetadata { - type Entry = CmpValues; - /// Convert to a slice - #[must_use] - fn as_slice_mut(&mut self) -> &mut [CmpValues] { - self.list.as_slice_mut() +impl DerefMut for CmpValuesMetadata { + fn deref_mut(&mut self) -> &mut [CmpValues] { + &mut self.list } } diff --git a/libafl/src/observers/map.rs b/libafl/src/observers/map.rs index aceb48d622..c62fc61a04 100644 --- a/libafl/src/observers/map.rs +++ b/libafl/src/observers/map.rs @@ -5,8 +5,8 @@ use core::{ fmt::Debug, hash::{Hash, Hasher}, iter::Flatten, - marker::PhantomData, mem::size_of, + ops::{Deref, DerefMut}, slice::{self, Iter, IterMut}, }; @@ -414,10 +414,10 @@ pub trait MapObserver: type Entry: Bounded + PartialEq + Default + Copy + Debug + Hash + 'static; /// Get the value at `idx` - fn get(&self, idx: usize) -> &Self::Entry; + fn get(&self, idx: usize) -> Self::Entry; - /// Get the value at `idx` (mutable) - fn get_mut(&mut self, idx: usize) -> &mut 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; @@ -459,64 +459,6 @@ where } } -/// A Simple iterator calling `MapObserver::get` -#[derive(Debug)] -pub struct MapObserverSimpleIterator<'a, O> -where - O: 'a + MapObserver, -{ - index: usize, - observer: *const O, - phantom: PhantomData<&'a u8>, -} - -impl<'a, O> Iterator for MapObserverSimpleIterator<'a, O> -where - O: 'a + MapObserver, -{ - type Item = &'a O::Entry; - fn next(&mut self) -> Option { - unsafe { - if self.index >= self.observer.as_ref().unwrap().usable_count() { - None - } else { - let i = self.index; - self.index += 1; - Some(self.observer.as_ref().unwrap().get(i)) - } - } - } -} - -/// A Simple iterator calling `MapObserver::get_mut` -#[derive(Debug)] -pub struct MapObserverSimpleIteratorMut<'a, O> -where - O: 'a + MapObserver, -{ - index: usize, - observer: *mut O, - phantom: PhantomData<&'a u8>, -} - -impl<'a, O> Iterator for MapObserverSimpleIteratorMut<'a, O> -where - O: 'a + MapObserver, -{ - type Item = &'a O::Entry; - fn next(&mut self) -> Option { - unsafe { - if self.index >= self.observer.as_ref().unwrap().usable_count() { - None - } else { - let i = self.index; - self.index += 1; - Some(self.observer.as_mut().unwrap().get_mut(i)) - } - } - } -} - /// 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. @@ -585,48 +527,6 @@ where } } -impl<'a, 'it, T, const DIFFERENTIAL: bool> AsIter<'it> for StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Item = T; - type IntoIter = Iter<'it, T>; - - fn as_iter(&'it self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice()[..cnt].iter() - } -} - -impl<'a, 'it, T, const DIFFERENTIAL: bool> AsIterMut<'it> for StdMapObserver<'a, T, DIFFERENTIAL> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Item = T; - type IntoIter = IterMut<'it, T>; - - fn as_iter_mut(&'it mut self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice_mut()[..cnt].iter_mut() - } -} - impl<'a, 'it, T, const DIFFERENTIAL: bool> IntoIterator for &'it StdMapObserver<'a, T, DIFFERENTIAL> where T: Bounded @@ -744,13 +644,12 @@ where type Entry = T; #[inline] - fn get(&self, pos: usize) -> &T { - &self.as_slice()[pos] + fn get(&self, pos: usize) -> T { + self.as_slice()[pos] } - #[inline] - fn get_mut(&mut self, idx: usize) -> &mut T { - &mut self.as_slice_mut()[idx] + fn set(&mut self, pos: usize, val: T) { + self.map.as_slice_mut()[pos] = val; } /// Count the set bytes in the map @@ -829,27 +728,22 @@ where } } -impl<'a, T, const DIFFERENTIAL: bool> AsSlice for StdMapObserver<'a, T, DIFFERENTIAL> +impl<'a, T, const DIFFERENTIAL: bool> Deref for StdMapObserver<'a, T, DIFFERENTIAL> where T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, { - type Entry = T; - #[must_use] - #[inline] - fn as_slice(&self) -> &[T] { - self.map.as_slice() + type Target = [T]; + fn deref(&self) -> &[T] { + &self.map } } -impl<'a, T, const DIFFERENTIAL: bool> AsSliceMut for StdMapObserver<'a, T, DIFFERENTIAL> +impl<'a, T, const DIFFERENTIAL: bool> DerefMut for StdMapObserver<'a, T, DIFFERENTIAL> where T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, { - type Entry = T; - #[must_use] - #[inline] - fn as_slice_mut(&mut self) -> &mut [T] { - self.map.as_slice_mut() + fn deref_mut(&mut self) -> &mut [T] { + &mut self.map } } @@ -1114,48 +1008,6 @@ where } } -impl<'a, 'it, T, const N: usize> AsIter<'it> for ConstMapObserver<'a, T, N> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Item = T; - type IntoIter = Iter<'it, T>; - - fn as_iter(&'it self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice()[..cnt].iter() - } -} - -impl<'a, 'it, T, const N: usize> AsIterMut<'it> for ConstMapObserver<'a, T, N> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug, -{ - type Item = T; - type IntoIter = IterMut<'it, T>; - - fn as_iter_mut(&'it mut self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice_mut()[..cnt].iter_mut() - } -} - impl<'a, 'it, T, const N: usize> IntoIterator for &'it ConstMapObserver<'a, T, N> where T: Bounded @@ -1276,13 +1128,13 @@ where } #[inline] - fn get(&self, idx: usize) -> &T { - &self.as_slice()[idx] + fn get(&self, idx: usize) -> T { + self.as_slice()[idx] } #[inline] - fn get_mut(&mut self, idx: usize) -> &mut T { - &mut self.as_slice_mut()[idx] + fn set(&mut self, idx: usize, val: T) { + self.map.as_slice_mut()[idx] = val; } /// Count the set bytes in the map @@ -1340,25 +1192,22 @@ where } } -impl<'a, T, const N: usize> AsSlice for ConstMapObserver<'a, T, N> +impl<'a, T, const N: usize> Deref for ConstMapObserver<'a, T, N> where T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, { - type Entry = T; - #[inline] - fn as_slice(&self) -> &[T] { - self.map.as_slice() + type Target = [T]; + fn deref(&self) -> &[T] { + &self.map } } -impl<'a, T, const N: usize> AsSliceMut for ConstMapObserver<'a, T, N> +impl<'a, T, const N: usize> DerefMut for ConstMapObserver<'a, T, N> where T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, { - type Entry = T; - #[inline] - fn as_slice_mut(&mut self) -> &mut [T] { - self.map.as_slice_mut() + fn deref_mut(&mut self) -> &mut [T] { + &mut self.map } } @@ -1459,52 +1308,6 @@ where } } -impl<'a, 'it, T> AsIter<'it> for VariableMapObserver<'a, T> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug - + PartialEq - + Bounded, -{ - type Item = T; - type IntoIter = Iter<'it, T>; - - fn as_iter(&'it self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice()[..cnt].iter() - } -} - -impl<'a, 'it, T> AsIterMut<'it> for VariableMapObserver<'a, T> -where - T: Bounded - + PartialEq - + Default - + Copy - + Hash - + 'static - + Serialize - + serde::de::DeserializeOwned - + Debug - + PartialEq - + Bounded, -{ - type Item = T; - type IntoIter = IterMut<'it, T>; - - fn as_iter_mut(&'it mut self) -> Self::IntoIter { - let cnt = self.usable_count(); - self.as_slice_mut()[..cnt].iter_mut() - } -} - impl<'a, 'it, T> IntoIterator for &'it VariableMapObserver<'a, T> where T: Bounded @@ -1595,6 +1398,7 @@ where self.as_slice().hash(hasher); } } + impl<'a, T> AsRef for VariableMapObserver<'a, T> where T: Default + Copy + 'static + Serialize + PartialEq + Bounded, @@ -1639,12 +1443,12 @@ where *self.size.as_ref() } - fn get(&self, idx: usize) -> &T { - &self.map.as_slice()[idx] + fn get(&self, idx: usize) -> T { + self.map.as_slice()[idx] } - fn get_mut(&mut self, idx: usize) -> &mut T { - &mut self.map.as_slice_mut()[idx] + fn set(&mut self, idx: usize, val: T) { + self.map.as_slice_mut()[idx] = val; } /// Count the set bytes in the map @@ -1697,7 +1501,7 @@ where } } -impl<'a, T> AsSlice for VariableMapObserver<'a, T> +impl<'a, T> Deref for VariableMapObserver<'a, T> where T: Bounded + PartialEq @@ -1711,15 +1515,14 @@ where + PartialEq + Bounded, { - type Entry = T; - #[inline] - fn as_slice(&self) -> &[T] { + type Target = [T]; + fn deref(&self) -> &[T] { let cnt = self.usable_count(); - &self.map.as_slice()[..cnt] + &self.map[..cnt] } } -impl<'a, T> AsSliceMut for VariableMapObserver<'a, T> +impl<'a, T> DerefMut for VariableMapObserver<'a, T> where T: 'static + Default @@ -1731,11 +1534,9 @@ where + PartialEq + Bounded, { - type Entry = T; - #[inline] - fn as_slice_mut(&mut self) -> &mut [T] { + fn deref_mut(&mut self) -> &mut [T] { let cnt = self.usable_count(); - &mut self.map.as_slice_mut()[..cnt] + &mut self.map[..cnt] } } @@ -1795,7 +1596,7 @@ where impl Observer for HitcountsMapObserver where - M: MapObserver + Observer + AsSliceMut, + M: MapObserver + Observer + for<'a> AsSliceMut<'a, Entry = u8>, S: UsesInput, { #[inline] @@ -1811,7 +1612,7 @@ where input: &S::Input, exit_kind: &ExitKind, ) -> Result<(), Error> { - let map = self.as_slice_mut(); + let mut map = self.as_slice_mut(); let mut len = map.len(); let align_offset = map.as_ptr().align_offset(size_of::()); @@ -1849,6 +1650,8 @@ where } } + drop(map); + self.base.post_exec(state, input, exit_kind) } } @@ -1908,13 +1711,13 @@ where } #[inline] - fn get(&self, idx: usize) -> &u8 { + fn get(&self, idx: usize) -> u8 { self.base.get(idx) } #[inline] - fn get_mut(&mut self, idx: usize) -> &mut u8 { - self.base.get_mut(idx) + fn set(&mut self, idx: usize, val: u8) { + self.base.set(idx, val); } /// Count the set bytes in the map @@ -1950,24 +1753,26 @@ where } } -impl AsSlice for HitcountsMapObserver +impl<'a, M> AsSlice<'a> for HitcountsMapObserver where - M: MapObserver + AsSlice, + M: MapObserver + AsSlice<'a>, { - type Entry = ::Entry; + type Entry = >::Entry; + type SliceRef = >::SliceRef; + #[inline] - fn as_slice(&self) -> &[Self::Entry] { + fn as_slice(&'a self) -> Self::SliceRef { self.base.as_slice() } } -impl AsSliceMut for HitcountsMapObserver +impl<'a, M> AsSliceMut<'a> for HitcountsMapObserver where - M: MapObserver + AsSliceMut, + M: MapObserver + AsSliceMut<'a>, { - type Entry = ::Entry; + type SliceRefMut = >::SliceRefMut; #[inline] - fn as_slice_mut(&mut self) -> &mut [Self::Entry] { + fn as_slice_mut(&'a mut self) -> Self::SliceRefMut { self.base.as_slice_mut() } } @@ -1983,30 +1788,6 @@ where } } -impl<'it, M> AsIter<'it> for HitcountsMapObserver -where - M: Named + Serialize + serde::de::DeserializeOwned + AsIter<'it, Item = u8>, -{ - type Item = u8; - type IntoIter = >::IntoIter; - - fn as_iter(&'it self) -> Self::IntoIter { - self.base.as_iter() - } -} - -impl<'it, M> AsIterMut<'it> for HitcountsMapObserver -where - M: Named + Serialize + serde::de::DeserializeOwned + AsIterMut<'it, Item = u8>, -{ - type Item = u8; - type IntoIter = >::IntoIter; - - fn as_iter_mut(&'it mut self) -> Self::IntoIter { - self.base.as_iter_mut() - } -} - impl<'it, M> IntoIterator for &'it HitcountsMapObserver where M: Serialize + serde::de::DeserializeOwned, @@ -2060,7 +1841,7 @@ where M: DifferentialObserver + MapObserver + Serialize - + AsSliceMut, + + for<'a> AsSliceMut<'a, Entry = u8>, OTA: ObserversTuple, OTB: ObserversTuple, S: UsesInput, @@ -2113,7 +1894,7 @@ where input: &S::Input, exit_kind: &ExitKind, ) -> Result<(), Error> { - for item in self.as_iter_mut() { + for mut item in self.as_iter_mut() { *item = unsafe { *COUNT_CLASS_LOOKUP.get_unchecked((*item) as usize) }; } @@ -2179,13 +1960,13 @@ where } #[inline] - fn get(&self, idx: usize) -> &u8 { + fn get(&self, idx: usize) -> u8 { self.base.get(idx) } #[inline] - fn get_mut(&mut self, idx: usize) -> &mut u8 { - self.base.get_mut(idx) + fn set(&mut self, idx: usize, val: u8) { + self.base.set(idx, val); } /// Count the set bytes in the map @@ -2221,28 +2002,6 @@ where } } -impl AsSlice for HitcountsIterableMapObserver -where - M: MapObserver + AsSlice, -{ - type Entry = ::Entry; - #[inline] - fn as_slice(&self) -> &[Self::Entry] { - self.base.as_slice() - } -} - -impl AsSliceMut for HitcountsIterableMapObserver -where - M: MapObserver + AsSliceMut, -{ - type Entry = ::Entry; - #[inline] - fn as_slice_mut(&mut self) -> &mut [Self::Entry] { - self.base.as_slice_mut() - } -} - impl HitcountsIterableMapObserver where M: Serialize + serde::de::DeserializeOwned, @@ -2259,6 +2018,7 @@ 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 { @@ -2270,10 +2030,10 @@ impl<'it, M> AsIterMut<'it> for HitcountsIterableMapObserver where M: Named + Serialize + serde::de::DeserializeOwned + AsIterMut<'it, Item = u8>, { - type Item = u8; - type IntoIter = >::IntoIter; + type RefMut = >::RefMut; + type IntoIterMut = >::IntoIterMut; - fn as_iter_mut(&'it mut self) -> Self::IntoIter { + fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { self.base.as_iter_mut() } } @@ -2457,19 +2217,19 @@ where type Entry = T; #[inline] - fn get(&self, idx: usize) -> &T { + 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] + self.maps[i].as_slice()[j] } #[inline] - fn get_mut(&mut self, idx: usize) -> &mut T { + 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; - &mut self.maps[i].as_slice_mut()[j] + self.maps[i].as_slice_mut()[j] = val; } #[inline] @@ -2513,7 +2273,7 @@ where let cnt = self.usable_count(); let mut res = Vec::with_capacity(cnt); for i in 0..cnt { - res.push(*self.get(i)); + res.push(self.get(i)); } res } @@ -2524,7 +2284,7 @@ where let cnt = self.usable_count(); let mut res = 0; for i in indexes { - if *i < cnt && *self.get(*i) != initial { + if *i < cnt && self.get(*i) != initial { res += 1; } } @@ -2611,6 +2371,7 @@ where 'a: 'it, { type Item = T; + type Ref = &'it T; type IntoIter = Flatten>>; fn as_iter(&'it self) -> Self::IntoIter { @@ -2623,10 +2384,10 @@ where T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, 'a: 'it, { - type Item = T; - type IntoIter = Flatten>>; + type RefMut = &'it mut T; + type IntoIterMut = Flatten>>; - fn as_iter_mut(&'it mut self) -> Self::IntoIter { + fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { self.maps.iter_mut().flatten() } } @@ -2727,30 +2488,6 @@ where } } -impl<'it, T> AsIter<'it> for OwnedMapObserver -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - type Item = T; - type IntoIter = Iter<'it, T>; - - fn as_iter(&'it self) -> Self::IntoIter { - self.as_slice().iter() - } -} - -impl<'it, T> AsIterMut<'it> for OwnedMapObserver -where - T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, -{ - type Item = T; - type IntoIter = IterMut<'it, T>; - - fn as_iter_mut(&'it mut self) -> Self::IntoIter { - self.as_slice_mut().iter_mut() - } -} - impl<'it, T> IntoIterator for &'it OwnedMapObserver where T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, @@ -2833,13 +2570,13 @@ where type Entry = T; #[inline] - fn get(&self, pos: usize) -> &T { - &self.as_slice()[pos] + fn get(&self, pos: usize) -> T { + self.as_slice()[pos] } #[inline] - fn get_mut(&mut self, idx: usize) -> &mut T { - &mut self.as_slice_mut()[idx] + fn set(&mut self, pos: usize, val: Self::Entry) { + self.as_slice_mut()[pos] = val; } /// Count the set bytes in the map @@ -2901,27 +2638,23 @@ where } } -impl AsSlice for OwnedMapObserver +impl Deref for OwnedMapObserver where T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, { - type Entry = T; - #[must_use] - #[inline] - fn as_slice(&self) -> &[T] { - self.map.as_slice() + type Target = [T]; + + fn deref(&self) -> &[T] { + &self.map } } -impl AsSliceMut for OwnedMapObserver +impl DerefMut for OwnedMapObserver where T: 'static + Default + Copy + Serialize + serde::de::DeserializeOwned + Debug, { - type Entry = T; - #[must_use] - #[inline] - fn as_slice_mut(&mut self) -> &mut [T] { - self.map.as_slice_mut() + fn deref_mut(&mut self) -> &mut [T] { + &mut self.map } } diff --git a/libafl/src/observers/value.rs b/libafl/src/observers/value.rs index d6c84f8d12..d23e3856d8 100644 --- a/libafl/src/observers/value.rs +++ b/libafl/src/observers/value.rs @@ -1,15 +1,15 @@ //! A simple observer with a single value. -use alloc::{borrow::Cow, boxed::Box}; +use alloc::{borrow::Cow, boxed::Box, vec::Vec}; use core::{ - cell::{Ref, RefCell}, + cell::{Ref, RefCell, RefMut}, fmt::Debug, - hash::Hash, - ops::Deref, + hash::{Hash, Hasher}, + ops::{Deref, DerefMut}, }; use ahash::RandomState; -use libafl_bolts::{ownedref::OwnedRef, Named}; +use libafl_bolts::{ownedref::OwnedRef, AsIter, AsIterMut, AsSlice, AsSliceMut, Named}; use serde::{Deserialize, Serialize}; use super::Observer; @@ -100,21 +100,15 @@ where /// A simple observer with a single [`RefCell`]'d value. #[derive(Serialize, Deserialize, Debug)] -#[serde(bound = "T: serde::de::DeserializeOwned")] -pub struct RefCellValueObserver<'a, T> -where - T: Debug + Serialize, -{ +#[serde(bound = "T: serde::de::DeserializeOwned + serde::Serialize")] +pub struct RefCellValueObserver<'a, T> { /// The name of this observer. name: Cow<'static, str>, /// The value. pub value: OwnedRef<'a, RefCell>, } -impl<'a, T> RefCellValueObserver<'a, T> -where - T: Debug + Serialize + serde::de::DeserializeOwned, -{ +impl<'a, T> RefCellValueObserver<'a, T> { /// Creates a new [`RefCellValueObserver`] with the given name. #[must_use] pub fn new(name: &'static str, value: OwnedRef<'a, RefCell>) -> Self { @@ -125,6 +119,8 @@ where } /// Get a reference to the underlying value. + /// + /// Panics if it can't borrow. #[must_use] pub fn get_ref<'b>(&'b self) -> Ref<'a, T> where @@ -133,6 +129,17 @@ where self.value.as_ref().borrow() } + /// Get a mutable reference to the underlying value. + /// + /// Panics if it can't borrow. + #[must_use] + pub fn get_ref_mut<'b>(&'b self) -> RefMut<'a, T> + where + 'b: 'a, + { + self.value.as_ref().borrow_mut() + } + /// Set the value. pub fn set(&mut self, new_value: T) { self.value.as_ref().replace(new_value); @@ -156,27 +163,246 @@ where impl<'a, S, T> Observer for RefCellValueObserver<'a, T> where S: UsesInput, - T: Debug + Serialize + serde::de::DeserializeOwned, { fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { Ok(()) } } -impl<'a, T> Named for RefCellValueObserver<'a, T> -where - T: Debug + Serialize + serde::de::DeserializeOwned, -{ +impl<'a, T> Named for RefCellValueObserver<'a, T> { fn name(&self) -> &Cow<'static, str> { &self.name } } -impl<'a, T: Hash> ObserverWithHashField for RefCellValueObserver<'a, T> +impl<'a, T> ObserverWithHashField for RefCellValueObserver<'a, T> where - T: Debug + Serialize + serde::de::DeserializeOwned, + T: Hash, { fn hash(&self) -> Option { Some(RandomState::with_seeds(1, 2, 3, 4).hash_one(&*self.value.as_ref().borrow())) } } + +/// [`Iterator`] over [`RefCellValueObserver`] of a [`Deref`] to `[T]`. +#[derive(Debug)] +pub struct RefCellValueObserverIter<'it, T> { + v: Ref<'it, [T]>, +} + +impl<'it, T: 'it, A: Deref> AsSlice<'it> for RefCellValueObserver<'_, A> { + type Entry = T; + type SliceRef = Ref<'it, [T]>; + + fn as_slice(&'it self) -> Self::SliceRef { + Ref::map(self.value.as_ref().borrow(), |s| &**s) + } +} + +impl<'it, T: 'it, A: DerefMut> AsSliceMut<'it> for RefCellValueObserver<'_, A> { + type SliceRefMut = RefMut<'it, [T]>; + + fn as_slice_mut(&'it mut self) -> Self::SliceRefMut { + RefMut::map(self.value.as_ref().borrow_mut(), |s| &mut **s) + } +} + +impl<'it, T: 'it, A: Deref> AsIter<'it> for RefCellValueObserver<'_, A> { + type Item = T; + type Ref = Ref<'it, Self::Item>; + type IntoIter = RefCellValueObserverIter<'it, T>; + + fn as_iter(&'it self) -> Self::IntoIter { + Self::IntoIter { + v: Ref::map(self.value.as_ref().borrow(), Deref::deref), + } + } +} + +impl<'it, T: 'it> Iterator for RefCellValueObserverIter<'it, T> { + type Item = Ref<'it, T>; + + fn next(&mut self) -> Option { + if self.v.is_empty() { + return None; + } + let cloned = Ref::clone(&self.v); + let (next, remainder) = Ref::map_split(cloned, |v| (&v[0], &v[1..])); + self.v = remainder; + Some(next) + } +} + +/// [`Iterator`] over [`RefCellValueObserver`] of a [`DerefMut`] to `[T]`. +#[derive(Debug)] +pub struct RefCellValueObserverIterMut<'it, T> { + v: Option>, +} + +impl<'it, T: 'it, A: Debug + DerefMut + Serialize> AsIterMut<'it> + for RefCellValueObserver<'_, A> +{ + type RefMut = RefMut<'it, T>; + type IntoIterMut = RefCellValueObserverIterMut<'it, T>; + + fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { + Self::IntoIterMut { + v: Some(RefMut::map( + self.value.as_ref().borrow_mut(), + DerefMut::deref_mut, + )), + } + } +} + +impl<'it, T: 'it> Iterator for RefCellValueObserverIterMut<'it, T> { + type Item = RefMut<'it, T>; + + fn next(&mut self) -> Option { + if let Some(v) = self.v.take() { + let next_slice = if v.len() > 1 { + let (next, remainder) = RefMut::map_split(v, |v| v.split_at_mut(1)); + self.v = Some(remainder); + next + } else { + v + }; + Some(RefMut::map(next_slice, |v| &mut v[0])) + } else { + None + } + } +} + +impl<'a, T: Hash, A> Hash for RefCellValueObserver<'a, A> +where + T: Debug, + A: Debug + Deref + Serialize + serde::de::DeserializeOwned, +{ + /// Panics if the contained value is already mutably borrowed (calls + /// [`RefCell::borrow`]). + #[inline] + fn hash(&self, hasher: &mut H) { + (*self.get_ref()).hash(hasher); + } +} + +/// Panics if the contained value is already mutably borrowed (calls +/// [`RefCell::borrow`]). +impl libafl_bolts::HasLen for RefCellValueObserver<'_, A> +where + T: Debug, + A: Debug + Deref + Serialize + serde::de::DeserializeOwned, +{ + /// Panics if the contained value is already mutably borrowed (calls + /// [`RefCell::borrow`]). + fn len(&self) -> usize { + self.get_ref().len() + } + + /// Panics if the contained value is already mutably borrowed (calls + /// [`RefCell::borrow`]). + fn is_empty(&self) -> bool { + self.get_ref().is_empty() + } +} + +impl AsMut + for RefCellValueObserver<'_, T> +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + +impl AsRef + for RefCellValueObserver<'_, T> +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl crate::observers::MapObserver for RefCellValueObserver<'_, A> +where + T: Copy + Debug + Default + Eq + Hash + num_traits::bounds::Bounded + 'static, + A: Debug + + Default + + Deref + + DerefMut + + serde::de::DeserializeOwned + + Serialize + + 'static, +{ + type Entry = T; + + /// Panics if the contained value is already mutably borrowed (calls + /// [`RefCell::borrow`]). + fn get(&self, idx: usize) -> Self::Entry { + self.get_ref()[idx] + } + + /// Panics if the contained value is already borrowed (calls + /// [`RefCell::borrow_mut`]). + fn set(&mut self, idx: usize, val: Self::Entry) { + self.get_ref_mut()[idx] = val; + } + + /// Panics if the contained value is already mutably borrowed (calls + /// [`RefCell::borrow`]). + fn hash_simple(&self) -> u64 { + RandomState::with_seeds(0, 0, 0, 0).hash_one(self) + } + + /// Panics if the contained value is already mutably borrowed (calls + /// [`RefCell::borrow`]). + fn usable_count(&self) -> usize { + self.get_ref().len() + } + + /// Panics if the contained value is already mutably borrowed (calls + /// [`RefCell::borrow`]). + fn count_bytes(&self) -> u64 { + let default = Self::Entry::default(); + let mut count = 0; + for entry in self.get_ref().iter() { + if entry != &default { + count += 1; + } + } + count + } + + /// Panics if the contained value is already borrowed (calls + /// [`RefCell::borrow_mut`]). + fn reset_map(&mut self) -> Result<(), Error> { + // This is less than optimal for `Vec`, for which we could use + // `.clear()`. However, it makes the `impl` more general. Worth it? + *self.get_ref_mut() = A::default(); + Ok(()) + } + + /// Panics if the contained value is already mutably borrowed (calls + /// [`RefCell::borrow`]). + fn to_vec(&self) -> Vec { + (*self.get_ref()).to_vec() + } + + /// Panics if the contained value is already mutably borrowed (calls + /// [`RefCell::borrow`]). + fn how_many_set(&self, indexes: &[usize]) -> usize { + let default = Self::Entry::default(); + let mut count = 0; + let arr = self.get_ref(); + for idx in indexes { + if arr[*idx] != default { + count += 1; + } + } + count + } + + fn initial(&self) -> Self::Entry { + Self::Entry::default() + } +} diff --git a/libafl/src/schedulers/accounting.rs b/libafl/src/schedulers/accounting.rs index bae451ce07..e28e71cb82 100644 --- a/libafl/src/schedulers/accounting.rs +++ b/libafl/src/schedulers/accounting.rs @@ -1,10 +1,13 @@ //! Coverage accounting corpus scheduler, more details at use alloc::vec::Vec; -use core::fmt::Debug; +use core::{ + fmt::Debug, + ops::{Deref, DerefMut}, +}; use hashbrown::HashMap; -use libafl_bolts::{rands::Rand, AsSlice, AsSliceMut, HasLen, HasRefCnt}; +use libafl_bolts::{rands::Rand, HasLen, HasRefCnt}; use serde::{Deserialize, Serialize}; use crate::{ @@ -35,19 +38,15 @@ pub struct AccountingIndexesMetadata { libafl_bolts::impl_serdeany!(AccountingIndexesMetadata); -impl AsSlice for AccountingIndexesMetadata { - type Entry = usize; - /// Convert to a slice - fn as_slice(&self) -> &[usize] { - self.list.as_slice() +impl Deref for AccountingIndexesMetadata { + type Target = [usize]; + fn deref(&self) -> &[usize] { + &self.list } } -impl AsSliceMut for AccountingIndexesMetadata { - type Entry = usize; - - /// Convert to a slice - fn as_slice_mut(&mut self) -> &mut [usize] { - self.list.as_slice_mut() +impl DerefMut for AccountingIndexesMetadata { + fn deref_mut(&mut self) -> &mut [usize] { + &mut self.list } } diff --git a/libafl/src/schedulers/minimizer.rs b/libafl/src/schedulers/minimizer.rs index c281e4f931..ddf871185b 100644 --- a/libafl/src/schedulers/minimizer.rs +++ b/libafl/src/schedulers/minimizer.rs @@ -5,7 +5,7 @@ use alloc::vec::Vec; use core::{any::type_name, cmp::Ordering, marker::PhantomData}; use hashbrown::{HashMap, HashSet}; -use libafl_bolts::{rands::Rand, serdeany::SerdeAny, AsSlice, HasRefCnt}; +use libafl_bolts::{rands::Rand, serdeany::SerdeAny, AsIter, HasRefCnt}; use serde::{Deserialize, Serialize}; use crate::{ @@ -89,7 +89,7 @@ impl RemovableScheduler for MinimizerScheduler where CS: RemovableScheduler, F: TestcaseScore, - M: AsSlice + SerdeAny + HasRefCnt, + M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, CS::State: HasCorpus + HasMetadata + HasRand, O: CanTrack, { @@ -130,13 +130,13 @@ where let factor = F::compute(state, &mut *old)?; if let Some(old_map) = old.metadata_map_mut().get_mut::() { let mut e_iter = entries.iter(); - let mut map_iter = old_map.as_slice().iter(); // ASSERTION: guaranteed to be in order? + let mut map_iter = old_map.as_iter(); // ASSERTION: guaranteed to be in order? // manual set intersection let mut entry = e_iter.next(); let mut map_entry = map_iter.next(); while let Some(e) = entry { - if let Some(me) = map_entry { + if let Some(ref me) = map_entry { match e.cmp(me) { Ordering::Less => { entry = e_iter.next(); @@ -197,7 +197,7 @@ impl Scheduler for MinimizerScheduler where CS: Scheduler, F: TestcaseScore, - M: AsSlice + SerdeAny + HasRefCnt, + M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, CS::State: HasCorpus + HasMetadata + HasRand, O: CanTrack, { @@ -253,7 +253,7 @@ impl MinimizerScheduler where CS: Scheduler, F: TestcaseScore, - M: AsSlice + SerdeAny + HasRefCnt, + M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, CS::State: HasCorpus + HasMetadata + HasRand, O: CanTrack, { @@ -276,8 +276,8 @@ where )) })?; let top_rateds = state.metadata_map().get::().unwrap(); - for elem in meta.as_slice() { - if let Some(old_idx) = top_rateds.map.get(elem) { + for elem in meta.as_iter() { + if let Some(old_idx) = top_rateds.map.get(&*elem) { if *old_idx == idx { new_favoreds.push(*elem); // always retain current; we'll drop it later otherwise continue; @@ -350,7 +350,7 @@ where type_name::() )) })?; - for elem in meta.as_slice() { + for elem in meta.as_iter() { acc.insert(*elem); } diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index 0d0ab670e1..6d8b7220c6 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -213,6 +213,7 @@ use core::{ array::TryFromSliceError, fmt::{self, Display}, num::{ParseIntError, TryFromIntError}, + ops::{Deref, DerefMut}, time, }; #[cfg(feature = "std")] @@ -674,68 +675,47 @@ pub trait IntoOwned { } /// Can be converted to a slice -pub trait AsSlice { - /// Type of the entries in this slice - type Entry; +pub trait AsSlice<'a> { + /// Type of the entries of this slice + type Entry: 'a; + /// Type of the reference to this slice + type SliceRef: Deref; + /// Convert to a slice - fn as_slice(&self) -> &[Self::Entry]; + fn as_slice(&'a self) -> Self::SliceRef; +} + +impl<'a, T, R> AsSlice<'a> for R +where + T: 'a, + R: Deref, +{ + type Entry = T; + type SliceRef = &'a [T]; + + fn as_slice(&'a self) -> Self::SliceRef { + &*self + } } /// Can be converted to a mutable slice -pub trait AsSliceMut { - /// Type of the entries in this mut slice - type Entry; +pub trait AsSliceMut<'a>: AsSlice<'a> { + /// Type of the mutable reference to this slice + type SliceRefMut: DerefMut; + /// Convert to a slice - fn as_slice_mut(&mut self) -> &mut [Self::Entry]; + fn as_slice_mut(&'a mut self) -> Self::SliceRefMut; } -#[cfg(feature = "alloc")] -impl AsSlice for Vec { - type Entry = T; +impl<'a, T, R> AsSliceMut<'a> for R +where + T: 'a, + R: DerefMut, +{ + type SliceRefMut = &'a mut [T]; - fn as_slice(&self) -> &[Self::Entry] { - self - } -} - -#[cfg(feature = "alloc")] -impl AsSliceMut for Vec { - type Entry = T; - - fn as_slice_mut(&mut self) -> &mut [Self::Entry] { - self - } -} - -impl AsSlice for &[T] { - type Entry = T; - - fn as_slice(&self) -> &[Self::Entry] { - self - } -} - -impl AsSlice for [T] { - type Entry = T; - - fn as_slice(&self) -> &[Self::Entry] { - self - } -} - -impl AsSliceMut for &mut [T] { - type Entry = T; - - fn as_slice_mut(&mut self) -> &mut [Self::Entry] { - self - } -} - -impl AsSliceMut for [T] { - type Entry = T; - - fn as_slice_mut(&mut self) -> &mut [Self::Entry] { - self + fn as_slice_mut(&'a mut self) -> Self::SliceRefMut { + &mut *self } } @@ -743,22 +723,51 @@ impl AsSliceMut for [T] { pub trait AsIter<'it> { /// The item type type Item: 'it; + /// The ref type + type Ref: Deref; /// The iterator type - type IntoIter: Iterator; + type IntoIter: Iterator; /// Create an iterator from &self fn as_iter(&'it self) -> Self::IntoIter; } +impl<'it, S, T> AsIter<'it> for S +where + S: AsSlice<'it, Entry = T, SliceRef = &'it [T]>, + T: 'it, +{ + type Item = S::Entry; + type Ref = &'it Self::Item; + type IntoIter = core::slice::Iter<'it, Self::Item>; + + fn as_iter(&'it self) -> Self::IntoIter { + self.as_slice().iter() + } +} + /// Create an `Iterator` from a mutable reference -pub trait AsIterMut<'it> { - /// The item type - type Item: 'it; +pub trait AsIterMut<'it>: AsIter<'it> { + /// The ref type + type RefMut: DerefMut; /// The iterator type - type IntoIter: Iterator; + type IntoIterMut: Iterator; /// Create an iterator from &mut self - fn as_iter_mut(&'it mut self) -> Self::IntoIter; + fn as_iter_mut(&'it mut self) -> Self::IntoIterMut; +} + +impl<'it, S, T> AsIterMut<'it> for S +where + S: AsSliceMut<'it, Entry = T, SliceRef = &'it [T], SliceRefMut = &'it mut [T]>, + T: 'it, +{ + type RefMut = &'it mut Self::Item; + type IntoIterMut = core::slice::IterMut<'it, Self::Item>; + + fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { + self.as_slice_mut().iter_mut() + } } /// Has a length field diff --git a/libafl_bolts/src/llmp.rs b/libafl_bolts/src/llmp.rs index b024ae89a0..1ff9ecc5ee 100644 --- a/libafl_bolts/src/llmp.rs +++ b/libafl_bolts/src/llmp.rs @@ -394,14 +394,14 @@ impl Listener { #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn shmem2page_mut(afl_shmem: &mut SHM) -> *mut LlmpPage { - afl_shmem.as_slice_mut().as_mut_ptr() as *mut LlmpPage + afl_shmem.as_mut_ptr() as *mut LlmpPage } /// Get sharedmem from a page #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn shmem2page(afl_shmem: &SHM) -> *const LlmpPage { - afl_shmem.as_slice().as_ptr() as *const LlmpPage + afl_shmem.as_ptr() as *const LlmpPage } /// Return, if a msg is contained in the current page @@ -564,7 +564,7 @@ unsafe fn llmp_next_msg_ptr_checked( alloc_size: usize, ) -> Result<*mut LlmpMsg, Error> { let page = map.page_mut(); - let map_size = map.shmem.as_slice().len(); + let map_size = map.shmem.len(); let msg_begin_min = (page as *const u8).add(size_of::()); // We still need space for this msg (alloc_size). let msg_begin_max = (page as *const u8).add(map_size - alloc_size); @@ -662,7 +662,7 @@ impl LlmpMsg { /// Returns `true`, if the pointer is, indeed, in the page of this shared map. #[inline] pub fn in_shmem(&self, map: &mut LlmpSharedMap) -> bool { - let map_size = map.shmem.as_slice().len(); + let map_size = map.shmem.len(); let buf_ptr = self.buf.as_ptr(); let len = self.buf_len_padded as usize + size_of::(); unsafe { @@ -1970,7 +1970,7 @@ where let offset = offset as usize; let page = unsafe { self.page_mut() }; - let page_size = self.shmem.as_slice().len() - size_of::(); + let page_size = self.shmem.len() - size_of::(); if offset > page_size { Err(Error::illegal_argument(format!( "Msg offset out of bounds (size: {page_size}, requested offset: {offset})" diff --git a/libafl_bolts/src/os/unix_shmem_server.rs b/libafl_bolts/src/os/unix_shmem_server.rs index 07e887f189..38780a27fc 100644 --- a/libafl_bolts/src/os/unix_shmem_server.rs +++ b/libafl_bolts/src/os/unix_shmem_server.rs @@ -10,7 +10,11 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; -use core::{mem::ManuallyDrop, ptr::addr_of}; +use core::{ + mem::ManuallyDrop, + ops::{Deref, DerefMut}, + ptr::addr_of, +}; #[cfg(target_vendor = "apple")] use std::fs; use std::{ @@ -40,7 +44,7 @@ use uds::{UnixListenerExt, UnixSocketAddr, UnixStreamExt}; use crate::{ shmem::{ShMem, ShMemDescription, ShMemId, ShMemProvider}, - AsSlice, AsSliceMut, Error, + Error, }; /// The default server name for our abstract shmem server @@ -79,6 +83,26 @@ where server_fd: i32, } +impl Deref for ServedShMem +where + SH: ShMem, +{ + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for ServedShMem +where + SH: ShMem, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + impl ShMem for ServedShMem where SH: ShMem, @@ -87,29 +111,6 @@ where let client_id = self.inner.id(); ShMemId::from_string(&format!("{}:{client_id}", self.server_fd)) } - - fn len(&self) -> usize { - self.inner.len() - } -} - -impl AsSlice for ServedShMem -where - SH: ShMem, -{ - type Entry = u8; - fn as_slice(&self) -> &[u8] { - self.inner.as_slice() - } -} -impl AsSliceMut for ServedShMem -where - SH: ShMem, -{ - type Entry = u8; - fn as_slice_mut(&mut self) -> &mut [u8] { - self.inner.as_slice_mut() - } } impl ServedShMemProvider diff --git a/libafl_bolts/src/ownedref.rs b/libafl_bolts/src/ownedref.rs index 27726f0263..9cf4e19568 100644 --- a/libafl_bolts/src/ownedref.rs +++ b/libafl_bolts/src/ownedref.rs @@ -6,7 +6,12 @@ use alloc::{ slice::{Iter, IterMut}, vec::Vec, }; -use core::{clone::Clone, fmt::Debug, slice}; +use core::{ + clone::Clone, + fmt::Debug, + ops::{Deref, DerefMut}, + slice, +}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -455,11 +460,10 @@ impl<'a, T> From> for OwnedSlice<'a, T> { } } -impl<'a, T: Sized> AsSlice for OwnedSlice<'a, T> { - type Entry = T; - /// Get the [`OwnedSlice`] as slice. - #[must_use] - fn as_slice(&self) -> &[T] { +impl<'a, T: Sized> Deref for OwnedSlice<'a, T> { + type Target = [T]; + + fn deref(&self) -> &Self::Target { match &self.inner { OwnedSliceInner::Ref(r) => r, OwnedSliceInner::RefRaw(rr, len, _) => unsafe { slice::from_raw_parts(*rr, *len) }, @@ -639,11 +643,10 @@ impl<'a, T: 'a + Sized> OwnedMutSlice<'a, T> { } } -impl<'a, T: Sized> AsSlice for OwnedMutSlice<'a, T> { - type Entry = T; - /// Get the value as slice - #[must_use] - fn as_slice(&self) -> &[T] { +impl<'a, T: Sized> Deref for OwnedMutSlice<'a, T> { + type Target = [T]; + + fn deref(&self) -> &Self::Target { match &self.inner { OwnedMutSliceInner::RefRaw(rr, len, _) => unsafe { slice::from_raw_parts(*rr, *len) }, OwnedMutSliceInner::Ref(r) => r, @@ -651,11 +654,9 @@ impl<'a, T: Sized> AsSlice for OwnedMutSlice<'a, T> { } } } -impl<'a, T: Sized> AsSliceMut for OwnedMutSlice<'a, T> { - type Entry = T; - /// Get the value as mut slice - #[must_use] - fn as_slice_mut(&mut self) -> &mut [T] { + +impl<'a, T: Sized> DerefMut for OwnedMutSlice<'a, T> { + fn deref_mut(&mut self) -> &mut [T] { match &mut self.inner { OwnedMutSliceInner::RefRaw(rr, len, _) => unsafe { slice::from_raw_parts_mut(*rr, *len) diff --git a/libafl_bolts/src/shmem.rs b/libafl_bolts/src/shmem.rs index f46e27a765..e906c486b1 100644 --- a/libafl_bolts/src/shmem.rs +++ b/libafl_bolts/src/shmem.rs @@ -7,7 +7,11 @@ use alloc::{rc::Rc, string::ToString}; use core::fmt::Display; #[cfg(feature = "alloc")] use core::{cell::RefCell, fmt, mem::ManuallyDrop}; -use core::{fmt::Debug, mem}; +use core::{ + fmt::Debug, + mem, + ops::{Deref, DerefMut}, +}; #[cfg(feature = "std")] use std::env; #[cfg(all(unix, feature = "std", not(target_os = "haiku")))] @@ -31,7 +35,7 @@ pub use win32_shmem::{Win32ShMem, Win32ShMemProvider}; use crate::os::pipes::Pipe; #[cfg(all(feature = "std", unix, not(target_os = "haiku")))] pub use crate::os::unix_shmem_server::{ServedShMemProvider, ShMemService}; -use crate::{AsSlice, AsSliceMut, Error}; +use crate::Error; /// The standard sharedmem provider #[cfg(all(windows, feature = "std"))] @@ -168,9 +172,10 @@ impl ShMemId { alloc::str::from_utf8(&self.id[..self.null_pos()]).unwrap() } } -impl AsSlice for ShMemId { - type Entry = u8; - fn as_slice(&self) -> &[u8] { + +impl Deref for ShMemId { + type Target = [u8]; + fn deref(&self) -> &[u8] { &self.id } } @@ -192,23 +197,15 @@ impl Display for ShMemId { /// A [`ShMem`] is an interface to shared maps. /// They are the backbone of [`crate::llmp`] for inter-process communication. /// All you need for scaling on a new target is to implement this interface, as well as the respective [`ShMemProvider`]. -pub trait ShMem: Sized + Debug + Clone + AsSlice + AsSliceMut { +pub trait ShMem: Sized + Debug + Clone + DerefMut { /// Get the id of this shared memory mapping fn id(&self) -> ShMemId; - /// Get the size of this mapping - fn len(&self) -> usize; - - /// Check if the mapping is empty - fn is_empty(&self) -> bool { - self.len() == 0 - } - /// Convert to a ptr of a given type, checking the size. /// If the map is too small, returns `None` fn as_ptr_of(&self) -> Option<*const T> { if self.len() >= mem::size_of::() { - Some(self.as_slice().as_ptr() as *const T) + Some(self.as_ptr() as *const T) } else { None } @@ -218,7 +215,7 @@ pub trait ShMem: Sized + Debug + Clone + AsSlice + AsSliceMut(&mut self) -> Option<*mut T> { if self.len() >= mem::size_of::() { - Some(self.as_slice_mut().as_mut_ptr() as *mut T) + Some(self.as_mut_ptr() as *mut T) } else { None } @@ -339,31 +336,27 @@ where fn id(&self) -> ShMemId { self.internal.id() } +} - fn len(&self) -> usize { - self.internal.len() +#[cfg(feature = "alloc")] +impl Deref for RcShMem +where + T: ShMemProvider + Debug, +{ + type Target = [u8]; + + fn deref(&self) -> &[u8] { + &self.internal } } #[cfg(feature = "alloc")] -impl AsSlice for RcShMem +impl DerefMut for RcShMem where T: ShMemProvider + Debug, { - type Entry = u8; - fn as_slice(&self) -> &[u8] { - self.internal.as_slice() - } -} - -#[cfg(feature = "alloc")] -impl AsSliceMut for RcShMem -where - T: ShMemProvider + Debug, -{ - type Entry = u8; - fn as_slice_mut(&mut self) -> &mut [u8] { - self.internal.as_slice_mut() + fn deref_mut(&mut self) -> &mut [u8] { + &mut self.internal } } @@ -562,6 +555,13 @@ where /// Is needed on top. #[cfg(all(unix, feature = "std", not(target_os = "haiku")))] pub mod unix_shmem { + /// Mmap [`ShMem`] for Unix + #[cfg(not(target_os = "android"))] + pub use default::MmapShMem; + /// Mmap [`ShMemProvider`] for Unix + #[cfg(not(target_os = "android"))] + pub use default::MmapShMemProvider; + #[cfg(doc)] use crate::shmem::{ShMem, ShMemProvider}; @@ -578,18 +578,13 @@ pub mod unix_shmem { #[cfg(not(target_os = "android"))] pub type UnixShMem = default::CommonUnixShMem; - /// Mmap [`ShMem`] for Unix - #[cfg(not(target_os = "android"))] - pub use default::MmapShMem; - /// Mmap [`ShMemProvider`] for Unix - #[cfg(not(target_os = "android"))] - pub use default::MmapShMemProvider; - #[cfg(all(unix, feature = "std", not(target_os = "android")))] mod default { - use alloc::string::ToString; - use core::{ptr, slice}; + use core::{ + ops::{Deref, DerefMut}, + ptr, slice, + }; use std::{io::Write, process}; use libc::{ @@ -600,7 +595,7 @@ pub mod unix_shmem { use crate::{ rands::{Rand, RandomSeed, StdRand}, shmem::{ShMem, ShMemId, ShMemProvider}, - AsSlice, AsSliceMut, Error, + Error, }; // This is macOS's limit @@ -769,22 +764,18 @@ pub mod unix_shmem { fn id(&self) -> ShMemId { self.id } - - fn len(&self) -> usize { - self.map_size - } } - impl AsSlice for MmapShMem { - type Entry = u8; - fn as_slice(&self) -> &[u8] { + impl Deref for MmapShMem { + type Target = [u8]; + + fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.map, self.map_size) } } } - impl AsSliceMut for MmapShMem { - type Entry = u8; - fn as_slice_mut(&mut self) -> &mut [u8] { + impl DerefMut for MmapShMem { + fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.map, self.map_size) } } } @@ -881,22 +872,18 @@ pub mod unix_shmem { fn id(&self) -> ShMemId { self.id } - - fn len(&self) -> usize { - self.map_size - } } - impl AsSlice for CommonUnixShMem { - type Entry = u8; - fn as_slice(&self) -> &[u8] { + impl Deref for CommonUnixShMem { + type Target = [u8]; + + fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.map, self.map_size) } } } - impl AsSliceMut for CommonUnixShMem { - type Entry = u8; - fn as_slice_mut(&mut self) -> &mut [u8] { + impl DerefMut for CommonUnixShMem { + fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.map, self.map_size) } } } @@ -954,7 +941,10 @@ pub mod unix_shmem { #[cfg(all(unix, feature = "std"))] pub mod ashmem { use alloc::string::ToString; - use core::{ptr, slice}; + use core::{ + ops::{Deref, DerefMut}, + ptr, slice, + }; use std::ffi::CString; use libc::{ @@ -964,7 +954,7 @@ pub mod unix_shmem { use crate::{ shmem::{ShMem, ShMemId, ShMemProvider}, - AsSlice, AsSliceMut, Error, + Error, }; /// An ashmem based impl for linux/android @@ -1091,23 +1081,18 @@ pub mod unix_shmem { fn id(&self) -> ShMemId { self.id } - - fn len(&self) -> usize { - self.map_size - } } - impl AsSlice for AshmemShMem { - type Entry = u8; - fn as_slice(&self) -> &[u8] { + impl Deref for AshmemShMem { + type Target = [u8]; + + fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.map, self.map_size) } } } - impl AsSliceMut for AshmemShMem { - type Entry = u8; - - fn as_slice_mut(&mut self) -> &mut [u8] { + impl DerefMut for AshmemShMem { + fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.map, self.map_size) } } } @@ -1177,23 +1162,15 @@ pub mod unix_shmem { /// Then `win32` implementation for shared memory. #[cfg(all(feature = "std", windows))] pub mod win32_shmem { - use alloc::string::String; use core::{ ffi::c_void, fmt::{self, Debug, Formatter}, + ops::{Deref, DerefMut}, slice, }; use uuid::Uuid; - - use crate::{ - shmem::{ShMem, ShMemId, ShMemProvider}, - AsSlice, AsSliceMut, Error, - }; - - const INVALID_HANDLE_VALUE: isize = -1; - use windows::{ core::PCSTR, Win32::{ @@ -1205,6 +1182,13 @@ pub mod win32_shmem { }, }; + use crate::{ + shmem::{ShMem, ShMemId, ShMemProvider}, + Error, + }; + + const INVALID_HANDLE_VALUE: isize = -1; + /// The default [`ShMem`] impl for Windows using `shmctl` & `shmget` #[derive(Clone)] pub struct Win32ShMem { @@ -1291,21 +1275,16 @@ pub mod win32_shmem { fn id(&self) -> ShMemId { self.id } - - fn len(&self) -> usize { - self.map_size - } } - impl AsSlice for Win32ShMem { - type Entry = u8; - fn as_slice(&self) -> &[u8] { + impl Deref for Win32ShMem { + type Target = [u8]; + fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.map, self.map_size) } } } - impl AsSliceMut for Win32ShMem { - type Entry = u8; - fn as_slice_mut(&mut self) -> &mut [u8] { + impl DerefMut for Win32ShMem { + fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.map, self.map_size) } } } @@ -1395,6 +1374,7 @@ impl ShMemCursor { /// Slice from the current location on this map to the end, mutable fn empty_slice_mut(&mut self) -> &mut [u8] { + use crate::AsSliceMut; &mut (self.inner.as_slice_mut()[self.pos..]) } } @@ -1442,6 +1422,7 @@ impl std::io::Seek for ShMemCursor { let effective_new_pos = match pos { std::io::SeekFrom::Start(s) => s, std::io::SeekFrom::End(offset) => { + use crate::AsSlice; let map_len = self.inner.as_slice().len(); let signed_pos = i64::try_from(map_len).unwrap(); let effective = signed_pos.checked_add(offset).unwrap(); diff --git a/libafl_concolic/symcc_runtime/src/filter/coverage.rs b/libafl_concolic/symcc_runtime/src/filter/coverage.rs index 59872ea555..1a56557a93 100644 --- a/libafl_concolic/symcc_runtime/src/filter/coverage.rs +++ b/libafl_concolic/symcc_runtime/src/filter/coverage.rs @@ -195,9 +195,7 @@ where // # Safety // The index is modulo by the length, therefore it is always in bounds let len = self.hitcounts_map.len(); - self.hitcounts_map - .as_slice_mut() - .get_unchecked_mut(hash % len) + self.hitcounts_map.get_unchecked_mut(hash % len) }; *val = val.saturating_add(1); } diff --git a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/observers.rs b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/observers.rs index d363adb33a..a3f95e69a4 100644 --- a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/observers.rs +++ b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/observers.rs @@ -2,6 +2,7 @@ use std::{ borrow::Cow, fmt::Debug, hash::{Hash, Hasher}, + ops::Deref, }; use ahash::AHasher; @@ -107,16 +108,16 @@ where { type Entry = O::ValueType; - fn get(&self, idx: usize) -> &Self::Entry { + fn get(&self, idx: usize) -> Self::Entry { let initial = self.inner.initial(); - if *self.inner.get(idx) == initial { - self.value_observer.default_value() + if self.inner.get(idx) == initial { + *self.value_observer.default_value() } else { - self.value_observer.value() + *self.value_observer.value() } } - fn get_mut(&mut self, _idx: usize) -> &mut Self::Entry { + fn set(&mut self, _idx: usize, _val: Self::Entry) { unimplemented!("Impossible to implement for a proxy map.") } @@ -148,7 +149,7 @@ where let value = *self.value_observer.value(); self.inner .as_iter() - .map(|&e| if e == initial { default } else { value }) + .map(|e| if *e == initial { default } else { value }) .collect() } @@ -202,9 +203,10 @@ impl<'it, I, O, T> MappedEdgeMapIter<'it, I, O, T> { } } -impl<'it, I, O, T> Iterator for MappedEdgeMapIter<'it, I, O, T> +impl<'it, I, O, R, T> Iterator for MappedEdgeMapIter<'it, I, O, T> where - I: Iterator, + I: Iterator, + R: Deref, T: PartialEq + 'it, O: ValueObserver, { @@ -225,6 +227,7 @@ where O: ValueObserver + 'it, { type Item = O::ValueType; + type Ref = &'it Self::Item; type IntoIter = MappedEdgeMapIter<'it, >::IntoIter, O, M::Entry>; fn as_iter(&'it self) -> Self::IntoIter { diff --git a/libafl_targets/src/sancov_8bit.rs b/libafl_targets/src/sancov_8bit.rs index de2e428f38..89f7118a2c 100644 --- a/libafl_targets/src/sancov_8bit.rs +++ b/libafl_targets/src/sancov_8bit.rs @@ -185,19 +185,19 @@ mod observers { type Entry = u8; #[inline] - fn get(&self, idx: usize) -> &u8 { + fn get(&self, idx: usize) -> u8 { let elem = self.intervals.query(idx..=idx).next().unwrap(); let i = elem.value; let j = idx - elem.interval.start; - unsafe { &(*addr_of!(COUNTERS_MAPS[*i])).as_slice()[j] } + unsafe { (*addr_of!(COUNTERS_MAPS[*i])).as_slice()[j] } } #[inline] - fn get_mut(&mut self, idx: usize) -> &mut u8 { + fn set(&mut self, idx: usize, val: u8) { let elem = self.intervals.query_mut(idx..=idx).next().unwrap(); let i = elem.value; let j = idx - elem.interval.start; - unsafe { &mut (*addr_of_mut!(COUNTERS_MAPS[*i])).as_slice_mut()[j] } + unsafe { (*addr_of_mut!(COUNTERS_MAPS[*i])).as_slice_mut()[j] = val }; } #[inline] @@ -241,7 +241,7 @@ mod observers { let cnt = self.usable_count(); let mut res = Vec::with_capacity(cnt); for i in 0..cnt { - res.push(*self.get(i)); + res.push(self.get(i)); } res } @@ -252,7 +252,7 @@ mod observers { let cnt = self.usable_count(); let mut res = 0; for i in indexes { - if *i < cnt && *self.get(*i) != initial { + if *i < cnt && self.get(*i) != initial { res += 1; } } @@ -322,6 +322,7 @@ mod observers { impl<'it, const DIFFERENTIAL: bool> AsIter<'it> for CountersMultiMapObserver { type Item = u8; + type Ref = &'it Self::Item; type IntoIter = Flatten>>; fn as_iter(&'it self) -> Self::IntoIter { @@ -330,10 +331,10 @@ mod observers { } impl<'it, const DIFFERENTIAL: bool> AsIterMut<'it> for CountersMultiMapObserver { - type Item = u8; - type IntoIter = Flatten>>; + type RefMut = &'it mut Self::Item; + type IntoIterMut = Flatten>>; - fn as_iter_mut(&'it mut self) -> Self::IntoIter { + fn as_iter_mut(&'it mut self) -> Self::IntoIterMut { unsafe { COUNTERS_MAPS.iter_mut().flatten() } } }