diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index 262e7ff7dc..aaf8f5a9a7 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -1,38 +1,17 @@ //! [`BytesSubInput`] is a wrapper input that can be used to mutate parts of a byte slice -use alloc::vec::Vec; +use alloc::vec::{self, Vec}; use core::{ - cmp::{min, Ordering}, - ops::{Bound, Range, RangeBounds}, + cmp::Ordering, + ops::{Range, RangeBounds}, }; -use libafl_bolts::HasLen; +use libafl_bolts::{ + subrange::{end_index, start_index, sub_range}, + HasLen, +}; -use super::HasMutatorBytes; - -/// Gets the relevant concrete start index from [`RangeBounds`] (inclusive) -fn start_index(range: &R) -> usize -where - R: RangeBounds, -{ - match range.start_bound() { - Bound::Unbounded => 0, - Bound::Included(start) => *start, - Bound::Excluded(start) => start + 1, - } -} - -/// Gets the relevant concrete end index from [`RangeBounds`] (exclusive) -fn end_index(range: &R, max_len: usize) -> usize -where - R: RangeBounds, -{ - match range.end_bound() { - Bound::Unbounded => max_len, - Bound::Included(end) => end + 1, - Bound::Excluded(end) => *end, - } -} +use crate::inputs::HasMutatorBytes; /// The [`BytesSubInput`] makes it possible to use [`crate::mutators::Mutator`]`s` that work on /// inputs implementing the [`HasMutatorBytes`] for a sub-range of this input. @@ -85,12 +64,9 @@ where /// assert_eq!(bytes_input.bytes(), [1, 2, 3, 4, 42, 42, 42, 5]); /// ``` /// -/// The input supports all methods in the [`HasMutatorBytes`] trait. +/// The input supports all methods in the [`HasMutatorBytes`] trait if the parent input also implements this trait. #[derive(Debug)] -pub struct BytesSubInput<'a, I> -where - I: HasMutatorBytes + ?Sized, -{ +pub struct BytesSubInput<'a, I: ?Sized> { /// The (complete) parent input we will work on pub(crate) parent_input: &'a mut I, /// The range inside the parent input we will work on @@ -99,7 +75,7 @@ where impl<'a, I> BytesSubInput<'a, I> where - I: HasMutatorBytes + ?Sized + HasLen, + I: HasMutatorBytes + ?Sized, { /// Creates a new [`BytesSubInput`] that's a view on an input with mutator bytes. /// The sub input can then be used to mutate parts of the original input. @@ -117,65 +93,11 @@ where }, } } - - /// The inclusive start index in the parent buffer - fn start_index(&self) -> usize { - self.range.start - } - - /// The exclusive end index in the parent buffer - fn end_index(&self) -> usize { - self.range.end - } - - /// Creates a sub range in the current own range - fn sub_range(&self, range: R2) -> (Bound, Bound) - where - R2: RangeBounds, - { - let start = match (self.range.start_bound(), range.start_bound()) { - (Bound::Unbounded, Bound::Unbounded) => Bound::Unbounded, - (Bound::Excluded(bound), Bound::Unbounded) - | (Bound::Unbounded, Bound::Excluded(bound)) => Bound::Excluded(*bound), - (Bound::Included(bound), Bound::Unbounded) - | (Bound::Unbounded, Bound::Included(bound)) => Bound::Included(*bound), - (Bound::Included(own), Bound::Included(other)) => Bound::Included(own + other), - (Bound::Included(own), Bound::Excluded(other)) - | (Bound::Excluded(own), Bound::Included(other)) => Bound::Excluded(own + other), - (Bound::Excluded(own), Bound::Excluded(other)) => Bound::Excluded(own + other + 1), - }; - - let end = match (self.range.end_bound(), range.end_bound()) { - (Bound::Unbounded, Bound::Unbounded) => Bound::Unbounded, - (Bound::Excluded(bound), Bound::Unbounded) => Bound::Excluded(*bound), - (Bound::Unbounded, Bound::Excluded(bound)) => { - Bound::Excluded(self.end_index() - *bound) - } - (Bound::Included(bound), Bound::Unbounded) => Bound::Included(*bound), - (Bound::Unbounded, Bound::Included(bound)) => { - Bound::Included(self.end_index() - *bound) - } - (Bound::Included(own), Bound::Included(other)) => { - Bound::Included(min(*own, self.start_index() + other)) - } - (Bound::Included(own), Bound::Excluded(other)) => { - Bound::Included(min(*own, self.start_index() + other - 1)) - } - (Bound::Excluded(own), Bound::Included(other)) => { - Bound::Included(min(*own - 1, self.start_index() + other)) - } - (Bound::Excluded(own), Bound::Excluded(other)) => { - Bound::Excluded(min(*own, self.start_index() + other)) - } - }; - - (start, end) - } } impl<'a, I> HasMutatorBytes for BytesSubInput<'a, I> where - I: HasMutatorBytes + HasLen, + I: HasMutatorBytes, { #[inline] fn bytes(&self) -> &[u8] { @@ -188,8 +110,8 @@ where } fn resize(&mut self, new_len: usize, value: u8) { - let start_index = self.start_index(); - let end_index = self.end_index(); + let start_index = self.range.start; + let end_index = self.range.end; let old_len = end_index - start_index; match new_len.cmp(&old_len) { @@ -238,7 +160,7 @@ where } fn extend<'b, IT: IntoIterator>(&mut self, iter: IT) { - let old_len = self.end_index() - self.start_index(); + let old_len = self.len(); let new_values: Vec = iter.into_iter().copied().collect(); self.resize(old_len + new_values.len(), 0); @@ -249,24 +171,21 @@ where /// with the given `replace_with` iterator and yields the removed items. /// `replace_with` does not need to be the same length as range. /// Refer to the docs of [`Vec::splice`] - fn splice( - &mut self, - range: R2, - replace_with: IT, - ) -> alloc::vec::Splice<'_, IT::IntoIter> + fn splice(&mut self, range: R2, replace_with: IT) -> vec::Splice<'_, IT::IntoIter> where R2: RangeBounds, IT: IntoIterator, { - let range = self.sub_range(range); + let range = sub_range(&self.range, range); self.parent_input.splice(range, replace_with) } - fn drain(&mut self, range: R2) -> alloc::vec::Drain<'_, u8> + fn drain(&mut self, range: R2) -> vec::Drain<'_, u8> where R2: RangeBounds, { - let drain = self.parent_input.drain(self.sub_range(range)); + let sub_range = sub_range(&self.range, range); + let drain = self.parent_input.drain(sub_range); self.range.end -= drain.len(); drain } @@ -274,11 +193,11 @@ where impl<'a, I> HasLen for BytesSubInput<'a, I> where - I: HasMutatorBytes + HasLen, + I: HasMutatorBytes, { #[inline] fn len(&self) -> usize { - self.range.end - self.range.start + self.range.len() } } @@ -303,6 +222,20 @@ mod tests { #[test] fn test_bytessubinput() { + let (bytes_input, _) = init_bytes_input(); + + let sub_input = bytes_input.sub_bytes(0..1); + assert_eq!(*sub_input.as_slice(), [1]); + + let sub_input = bytes_input.sub_bytes(1..=2); + assert_eq!(*sub_input.as_slice(), [2, 3]); + + let sub_input = bytes_input.sub_bytes(..); + assert_eq!(*sub_input.as_slice(), [1, 2, 3, 4, 5, 6, 7]); + } + + #[test] + fn test_mutablebytessubinput() { let (mut bytes_input, len_orig) = init_bytes_input(); let mut sub_input = bytes_input.sub_input(0..1); @@ -413,14 +346,27 @@ mod tests { #[test] fn test_ranges() { + let bytes_input = BytesInput::new(vec![1, 2, 3]); + + assert_eq!(bytes_input.sub_bytes(..1).start_index(), 0); + assert_eq!(bytes_input.sub_bytes(1..=1).start_index(), 1); + assert_eq!(bytes_input.sub_bytes(..1).end_index(), 1); + assert_eq!(bytes_input.sub_bytes(..=1).end_index(), 2); + assert_eq!(bytes_input.sub_bytes(1..=1).end_index(), 2); + assert_eq!(bytes_input.sub_bytes(1..).end_index(), 3); + assert_eq!(bytes_input.sub_bytes(..3).end_index(), 3); + } + + #[test] + fn test_ranges_mut() { let mut bytes_input = BytesInput::new(vec![1, 2, 3]); - assert_eq!(bytes_input.sub_input(..1).start_index(), 0); - assert_eq!(bytes_input.sub_input(1..=1).start_index(), 1); - assert_eq!(bytes_input.sub_input(..1).end_index(), 1); - assert_eq!(bytes_input.sub_input(..=1).end_index(), 2); - assert_eq!(bytes_input.sub_input(1..=1).end_index(), 2); - assert_eq!(bytes_input.sub_input(1..).end_index(), 3); - assert_eq!(bytes_input.sub_input(..3).end_index(), 3); + assert_eq!(bytes_input.sub_bytes_mut(..1).start_index(), 0); + assert_eq!(bytes_input.sub_bytes_mut(1..=1).start_index(), 1); + assert_eq!(bytes_input.sub_bytes_mut(..1).end_index(), 1); + assert_eq!(bytes_input.sub_bytes_mut(..=1).end_index(), 2); + assert_eq!(bytes_input.sub_bytes_mut(1..=1).end_index(), 2); + assert_eq!(bytes_input.sub_bytes_mut(1..).end_index(), 3); + assert_eq!(bytes_input.sub_bytes_mut(..3).end_index(), 3); } } diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index a915d3faf0..75bba866bc 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -34,7 +34,11 @@ use std::{fs::File, hash::Hash, io::Read, path::Path}; #[cfg(feature = "std")] use libafl_bolts::fs::write_file_atomic; -use libafl_bolts::{ownedref::OwnedSlice, Error, HasLen}; +use libafl_bolts::{ + ownedref::{OwnedMutSlice, OwnedSlice}, + subrange::{SubRangeMutSlice, SubRangeSlice}, + Error, HasLen, +}; #[cfg(feature = "nautilus")] pub use nautilus::*; use serde::{Deserialize, Serialize}; @@ -123,7 +127,14 @@ impl HasTargetBytes for NopInput { } } +impl HasLen for NopInput { + fn len(&self) -> usize { + 0 + } +} + // TODO change this to fn target_bytes(&self, buffer: &mut Vec) -> &[u8]; +/// Has a byte representation intended for the target. /// Can be represented with a vector of bytes. /// This representation is not necessarily deserializable. /// Instead, it can be used as bytes input for a target @@ -132,7 +143,7 @@ pub trait HasTargetBytes { fn target_bytes(&self) -> OwnedSlice; } -/// Contains mutateable and resizable bytes +/// Contains mutable and resizable bytes pub trait HasMutatorBytes: HasLen { /// The bytes fn bytes(&self) -> &[u8]; @@ -142,23 +153,39 @@ pub trait HasMutatorBytes: HasLen { /// Resize the mutator bytes to a given new size. /// Use `value` to fill new slots in case the buffer grows. - /// See [`alloc::vec::Vec::splice`]. + /// See [`Vec::splice`]. fn resize(&mut self, new_len: usize, value: u8); /// Extends the given buffer with an iterator. See [`alloc::vec::Vec::extend`] fn extend<'a, I: IntoIterator>(&mut self, iter: I); - /// Splices the given target bytes according to [`alloc::vec::Vec::splice`]'s rules + /// Splices the given target bytes according to [`Vec::splice`]'s rules fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter> where R: RangeBounds, I: IntoIterator; - /// Drains the given target bytes according to [`alloc::vec::Vec::drain`]'s rules + /// Drains the given target bytes according to [`Vec::drain`]'s rules fn drain(&mut self, range: R) -> Drain<'_, u8> where R: RangeBounds; + /// Creates a [`SubRangeSlice`] from this input, that can be used to slice a byte array. + fn sub_bytes(&self, range: R) -> SubRangeSlice + where + R: RangeBounds, + { + SubRangeSlice::new(OwnedSlice::from(self.bytes()), range) + } + + /// Creates a [`SubRangeMutSlice`] from this input, that can be used to slice a byte array. + fn sub_bytes_mut(&mut self, range: R) -> SubRangeMutSlice + where + R: RangeBounds, + { + SubRangeMutSlice::new(OwnedMutSlice::from(self.bytes_mut()), range) + } + /// Creates a [`BytesSubInput`] from this input, that can be used for local mutations. fn sub_input(&mut self, range: R) -> BytesSubInput where diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index 12c6b380ce..42d4959936 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -131,6 +131,8 @@ pub mod serdeany; pub mod shmem; #[cfg(feature = "std")] pub mod staterestore; +#[cfg(feature = "alloc")] +pub mod subrange; // TODO: reenable once ahash works in no-alloc #[cfg(any(feature = "xxh3", feature = "alloc"))] pub mod tuples; @@ -309,7 +311,7 @@ pub enum Error { Unsupported(String, ErrorBacktrace), /// Shutting down, not really an error. ShuttingDown, - /// OS error, wrapping a [`std::io::Error`] + /// OS error, wrapping a [`io::Error`] #[cfg(feature = "std")] OsError(io::Error, String, ErrorBacktrace), /// Something else happened @@ -411,7 +413,7 @@ impl Error { { Error::OsError(err, msg.into(), ErrorBacktrace::new()) } - /// OS error from [`std::io::Error::last_os_error`] with additional message + /// OS error from [`io::Error::last_os_error`] with additional message #[cfg(feature = "std")] #[must_use] pub fn last_os_error(msg: S) -> Self diff --git a/libafl_bolts/src/ownedref.rs b/libafl_bolts/src/ownedref.rs index b939d7ede3..c32051b8b6 100644 --- a/libafl_bolts/src/ownedref.rs +++ b/libafl_bolts/src/ownedref.rs @@ -9,8 +9,9 @@ use alloc::{ use core::{ clone::Clone, fmt::Debug, - ops::{Deref, DerefMut}, + ops::{Deref, DerefMut, RangeBounds}, slice, + slice::SliceIndex, }; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -457,6 +458,17 @@ impl<'a, T> OwnedSlice<'a, T> { pub fn iter(&self) -> Iter<'_, T> { <&Self as IntoIterator>::into_iter(self) } + + /// Returns a subslice of the slice. + #[must_use] + pub fn slice + SliceIndex<[T], Output = [T]>>( + &'a self, + range: R, + ) -> OwnedSlice<'a, T> { + OwnedSlice { + inner: OwnedSliceInner::Ref(&self[range]), + } + } } impl<'a, 'it, T> IntoIterator for &'it OwnedSlice<'a, T> { diff --git a/libafl_bolts/src/rands/mod.rs b/libafl_bolts/src/rands/mod.rs index 308fb243e1..800d558549 100644 --- a/libafl_bolts/src/rands/mod.rs +++ b/libafl_bolts/src/rands/mod.rs @@ -1,10 +1,8 @@ //! The random number generators of `LibAFL` -use core::{ - debug_assert, - fmt::Debug, - sync::atomic::{AtomicUsize, Ordering}, -}; +#[cfg(target_has_atomic = "ptr")] +use core::sync::atomic::Ordering; +use core::{debug_assert, fmt::Debug, sync::atomic::AtomicUsize}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; diff --git a/libafl_bolts/src/subrange.rs b/libafl_bolts/src/subrange.rs new file mode 100644 index 0000000000..cb994e025b --- /dev/null +++ b/libafl_bolts/src/subrange.rs @@ -0,0 +1,375 @@ +//! Subrange of things. +//! Convenient wrappers to handle sub-slices efficiently. + +use core::{ + cmp::min, + ops::{Bound, Range, RangeBounds}, +}; + +use crate::{ + ownedref::{OwnedMutSlice, OwnedSlice}, + HasLen, +}; + +/// An immutable contiguous subslice of a byte slice. +/// It is mostly useful to cheaply wrap a subslice of a given input. +/// +/// A mutable version is available: [`SubRangeMutSlice`]. +#[derive(Debug)] +pub struct SubRangeSlice<'a, T> { + /// The (complete) parent input we will work on + parent_slice: OwnedSlice<'a, T>, + /// The range inside the parent input we will work on + range: Range, +} + +/// A mutable contiguous subslice of a byte slice. +/// It is mostly useful to cheaply wrap a subslice of a given input. +/// +/// An immutable version is available: [`SubRangeSlice`]. +#[derive(Debug)] +pub struct SubRangeMutSlice<'a, T> { + /// The (complete) parent input we will work on + parent_slice: OwnedMutSlice<'a, T>, + /// The range inside the parent input we will work on + range: Range, +} + +/// Slice wrapper keeping track of the current read position. +/// Convenient wrapper when the slice must be split in multiple sub-slices and read sequentially. +#[derive(Debug)] +pub struct SliceReader<'a, T> { + parent_slice: &'a [T], + pos: usize, +} + +impl<'a, T> SliceReader<'a, T> { + /// Create a new [`SliceReader`]. + /// The position of the reader is initialized to 0. + #[must_use] + pub fn new(parent_slice: &'a [T]) -> Self { + Self { + parent_slice, + pos: 0, + } + } + + /// Read an immutable sub-slice from the parent slice, from the current cursor position up to `limit` elements. + /// If the resulting slice would go beyond the end of the parent slice, it will be truncated to the length of the parent slice. + /// This function does not provide any feedback on whether the slice was cropped or not. + #[must_use] + pub fn next_sub_slice_truncated(&mut self, limit: usize) -> SubRangeSlice<'a, T> { + let sub_slice = SubRangeSlice::with_slice(self.parent_slice, self.pos..(self.pos + limit)); + + self.pos += sub_slice.len(); + + sub_slice + } + + /// Read an immutable sub-slice from the parent slice, from the current cursor position up to `limit` bytes. + /// If the resulting slice would go beyond the end of the parent slice, it will be limited to the length of the parent slice. + /// The function returns + /// - `Ok(Slice)` if the returned slice has `limit` elements. + /// - `Err(Partial(slice))` if the returned slice has strictly less than `limit` elements and is not empty. + /// - `Err(Empty)` if the reader was already at the end or `limit` equals zero. + pub fn next_sub_input( + &mut self, + limit: usize, + ) -> Result, PartialSubRangeSlice<'a, T>> { + let slice_to_return = self.next_sub_slice_truncated(limit); + + let real_len = slice_to_return.len(); + + if real_len == 0 { + Err(PartialSubRangeSlice::Empty) + } else if real_len < limit { + Err(PartialSubRangeSlice::Partial(slice_to_return)) + } else { + Ok(slice_to_return) + } + } +} + +impl<'a, T> From<&'a [T]> for SliceReader<'a, T> { + fn from(input: &'a [T]) -> Self { + Self::new(input) + } +} + +impl<'a, T> HasLen for SubRangeSlice<'a, T> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } +} + +impl<'a, T> HasLen for SubRangeMutSlice<'a, T> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } +} + +/// Gets the relevant concrete start index from [`RangeBounds`] (inclusive) +pub fn start_index(range: &R) -> usize +where + R: RangeBounds, +{ + match range.start_bound() { + Bound::Unbounded => 0, + Bound::Included(start) => *start, + Bound::Excluded(start) => start + 1, + } +} + +/// Gets the relevant concrete end index from [`RangeBounds`] (exclusive) +pub fn end_index(range: &R, max_len: usize) -> usize +where + R: RangeBounds, +{ + let end = match range.end_bound() { + Bound::Unbounded => max_len, + Bound::Included(end) => end + 1, + Bound::Excluded(end) => *end, + }; + + min(end, max_len) +} + +/// Gets the relevant subrange of a [`Range`] from [`RangeBounds`]. +pub fn sub_range(outer_range: &Range, inner_range: R) -> (Bound, Bound) +where + R: RangeBounds, +{ + let start = + match (outer_range.start_bound(), inner_range.start_bound()) { + (Bound::Unbounded, Bound::Unbounded) => Bound::Unbounded, + (Bound::Excluded(bound), Bound::Unbounded) + | (Bound::Unbounded, Bound::Excluded(bound)) => Bound::Excluded(*bound), + (Bound::Included(bound), Bound::Unbounded) + | (Bound::Unbounded, Bound::Included(bound)) => Bound::Included(*bound), + (Bound::Included(own), Bound::Included(other)) => Bound::Included(own + other), + (Bound::Included(own), Bound::Excluded(other)) + | (Bound::Excluded(own), Bound::Included(other)) => Bound::Excluded(own + other), + (Bound::Excluded(own), Bound::Excluded(other)) => Bound::Excluded(own + other + 1), + }; + + let end = match (outer_range.end_bound(), inner_range.end_bound()) { + (Bound::Unbounded, Bound::Unbounded) => Bound::Unbounded, + (Bound::Excluded(bound), Bound::Unbounded) => Bound::Excluded(*bound), + (Bound::Unbounded, Bound::Excluded(bound)) => Bound::Excluded(outer_range.end - *bound), + (Bound::Included(bound), Bound::Unbounded) => Bound::Included(*bound), + (Bound::Unbounded, Bound::Included(bound)) => Bound::Included(outer_range.end - *bound), + (Bound::Included(own), Bound::Included(other)) => { + Bound::Included(min(*own, outer_range.start + other)) + } + (Bound::Included(own), Bound::Excluded(other)) => { + Bound::Included(min(*own, outer_range.start + other - 1)) + } + (Bound::Excluded(own), Bound::Included(other)) => { + Bound::Included(min(*own - 1, outer_range.start + other)) + } + (Bound::Excluded(own), Bound::Excluded(other)) => { + Bound::Excluded(min(*own, outer_range.start + other)) + } + }; + + (start, end) +} + +/// Representation of a partial slice +/// This is used when providing a slice smaller than the expected one. +/// It notably happens when trying to read the end of an input. +#[derive(Debug)] +pub enum PartialSubRangeSlice<'a, T> { + /// The slice is empty, and thus not kept + Empty, + /// The slice is strictly smaller than the expected one. + Partial(SubRangeSlice<'a, T>), +} + +impl<'a, T> PartialSubRangeSlice<'a, T> { + /// Consumes `PartialBytesSubInput` and returns true if it was empty, false otherwise. + #[must_use] + pub fn empty(self) -> bool { + matches!(self, PartialSubRangeSlice::Empty) + } + + /// Consumes `PartialBytesSubInput` and returns the partial slice if it was a partial slice, None otherwise. + #[must_use] + pub fn partial(self) -> Option> { + #[allow(clippy::match_wildcard_for_single_variants)] + match self { + PartialSubRangeSlice::Partial(partial_slice) => Some(partial_slice), + _ => None, + } + } +} + +impl<'a, T> SubRangeSlice<'a, T> { + /// Creates a new [`SubRangeSlice`], a sub-slice representation of a byte array. + pub fn new(parent_slice: OwnedSlice<'a, T>, range: R) -> Self + where + R: RangeBounds, + { + let parent_len = parent_slice.len(); + + SubRangeSlice { + parent_slice, + range: Range { + start: start_index(&range), + end: end_index(&range, parent_len), + }, + } + } + + /// Get the sub slice as bytes. + #[must_use] + pub fn as_slice(&self) -> &[T] { + &self.parent_slice[self.range.clone()] + } + + /// Creates a new [`SubRangeSlice`] that's a sliced view on a bytes slice. + pub fn with_slice(parent_slice: &'a [T], range: R) -> Self + where + R: RangeBounds, + { + Self::new(parent_slice.into(), range) + } + + /// The parent input + #[must_use] + pub fn parent_slice(self) -> OwnedSlice<'a, T> { + self.parent_slice + } + + /// The inclusive start index in the parent buffer + #[must_use] + pub fn start_index(&self) -> usize { + self.range.start + } + + /// The exclusive end index in the parent buffer + #[must_use] + pub fn end_index(&self) -> usize { + self.range.end + } + + /// Creates a sub range in the current own range + pub fn sub_range(&self, range: R) -> (Bound, Bound) + where + R: RangeBounds, + { + sub_range(&self.range, range) + } +} + +impl<'a, T> SubRangeMutSlice<'a, T> { + /// Creates a new [`SubRangeMutSlice`], a sub-slice representation of a byte array. + pub fn new(parent_slice: OwnedMutSlice<'a, T>, range: R) -> Self + where + R: RangeBounds, + { + let parent_len = parent_slice.len(); + + SubRangeMutSlice { + parent_slice, + range: Range { + start: start_index(&range), + end: end_index(&range, parent_len), + }, + } + } + + /// Get the sub slice as bytes. + #[must_use] + pub fn as_slice(&self) -> &[T] { + &self.parent_slice[self.range.clone()] + } + + /// Get the sub slice as bytes. + #[must_use] + pub fn as_slice_mut(&mut self) -> &mut [T] { + &mut self.parent_slice[self.range.clone()] + } + + /// Creates a new [`SubRangeMutSlice`] that's a view on a bytes slice. + /// The sub-slice can then be used to mutate parts of the original bytes. + pub fn with_slice(parent_slice: &'a mut [T], range: R) -> Self + where + R: RangeBounds, + { + Self::new(parent_slice.into(), range) + } + + /// The parent input + #[must_use] + pub fn parent_slice(self) -> OwnedMutSlice<'a, T> { + self.parent_slice + } + + /// The inclusive start index in the parent buffer + #[must_use] + pub fn start_index(&self) -> usize { + self.range.start + } + + /// The exclusive end index in the parent buffer + #[must_use] + pub fn end_index(&self) -> usize { + self.range.end + } + + /// Creates a sub range in the current own range + pub fn sub_range(&self, range: R) -> (Bound, Bound) + where + R: RangeBounds, + { + sub_range(&self.range, range) + } +} + +#[cfg(test)] +mod tests { + use super::SliceReader; + + #[test] + fn test_bytesreader_toslice_unchecked() { + let bytes_input = vec![1, 2, 3, 4, 5, 6, 7]; + let mut bytes_reader = SliceReader::new(&bytes_input); + + let bytes_read = bytes_reader.next_sub_slice_truncated(2); + assert_eq!(*bytes_read.as_slice(), [1, 2]); + + let bytes_read = bytes_reader.next_sub_slice_truncated(3); + assert_eq!(*bytes_read.as_slice(), [3, 4, 5]); + + let bytes_read = bytes_reader.next_sub_slice_truncated(8); + assert_eq!(*bytes_read.as_slice(), [6, 7]); + + let bytes_read = bytes_reader.next_sub_slice_truncated(8); + let bytes_read_ref: &[u8] = &[]; + assert_eq!(&*bytes_read.as_slice(), bytes_read_ref); + } + + #[test] + fn test_bytesreader_toslice() { + let bytes_input = vec![1, 2, 3, 4, 5, 6, 7]; + let mut bytes_reader = SliceReader::new(&bytes_input); + + let bytes_read = bytes_reader.next_sub_input(2); + assert_eq!(*bytes_read.unwrap().as_slice(), [1, 2]); + + let bytes_read = bytes_reader.next_sub_input(3); + assert_eq!(*bytes_read.unwrap().as_slice(), [3, 4, 5]); + + let bytes_read = bytes_reader.next_sub_input(8); + assert_eq!( + *bytes_read.unwrap_err().partial().unwrap().as_slice(), + [6, 7] + ); + + let bytes_read = bytes_reader.next_sub_input(8); + assert!(bytes_read.unwrap_err().empty()); + } +} diff --git a/utils/libafl_benches/benches/hash_speeds.rs b/utils/libafl_benches/benches/hash_speeds.rs index b7b6019908..eb29562336 100644 --- a/utils/libafl_benches/benches/hash_speeds.rs +++ b/utils/libafl_benches/benches/hash_speeds.rs @@ -15,7 +15,7 @@ fn criterion_benchmark(c: &mut Criterion) { } c.bench_function("xxh3", |b| { - b.iter(|| xxh3::xxh3_64_with_seed(black_box(&bench_vec), 0)); + b.iter(|| black_box(xxh3::xxh3_64_with_seed(&bench_vec, 0))); }); /*c.bench_function("const_xxh3", |b| { b.iter(|| const_xxh3::xxh3_64_with_seed(black_box(&bench_vec), 0)) @@ -29,7 +29,7 @@ fn criterion_benchmark(c: &mut Criterion) { }); c.bench_function("fxhash", |b| { b.iter(|| { - let mut hasher = black_box(rustc_hash::FxHasher::default()); + let mut hasher = rustc_hash::FxHasher::default(); hasher.write(black_box(&bench_vec)); black_box(hasher.finish()); });