Add AsSlice, AsMutSlice traits, refactor MapObservers to be iterable, and have associated types (#477)

* from warning

* fix latest clippy

* clippy fixes++

* renamed shmem parameters

* renamed map to shmem

* make forkserver executor work for any (non-system) shmem

* Mem -> ShMem

* rework windows

* fix nit

* fix symbolic

* refacctor map observers

* iterator for map observers

* removed unused ownedptr, added asslice trait to most functions

* make map entry type an associated type

* fix fuzzers

* fix docs

* typo fix

* fix windows, add try_from_slice to shmid

* missing import

* fix fuzzbench

* cleanup

* fmt

* more asslice

* fmt

* added doc link about token-level fuzzing

* cods
This commit is contained in:
Dominik Maier 2022-01-19 00:02:33 +01:00 committed by GitHub
parent b67a7f5b60
commit 77e5965e97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 580 additions and 358 deletions

View File

@ -77,7 +77,10 @@ To start, we create the closure that we want to fuzz. It takes a buffer as input
```rust ```rust
extern crate libafl; extern crate libafl;
use libafl::inputs::{BytesInput, HasTargetBytes}; use libafl::{
bolts::AsSlice,
inputs::{BytesInput, HasTargetBytes},
};
let mut harness = |input: &BytesInput| { let mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
@ -218,6 +221,7 @@ As we don't rely on any instrumentation engine, we have to manually track the sa
```rust ```rust
extern crate libafl; extern crate libafl;
use libafl::{ use libafl::{
bolts::AsSlice,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
executors::ExitKind, executors::ExitKind,
}; };

View File

@ -4,7 +4,7 @@ use std::path::PathBuf;
use std::ptr::write_volatile; use std::ptr::write_volatile;
use libafl::{ use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list}, bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler}, corpus::{InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler},
events::SimpleEventManager, events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind}, executors::{inprocess::InProcessExecutor, ExitKind},

View File

@ -5,7 +5,7 @@
#![cfg_attr(not(any(windows, unix)), feature(default_alloc_error_handler))] #![cfg_attr(not(any(windows, unix)), feature(default_alloc_error_handler))]
use libafl::{ use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list}, bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{InMemoryCorpus, QueueCorpusScheduler}, corpus::{InMemoryCorpus, QueueCorpusScheduler},
events::SimpleEventManager, events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind}, executors::{inprocess::InProcessExecutor, ExitKind},

View File

@ -5,6 +5,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMem, ShMemProvider, StdShMemProvider}, shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::tuple_list, tuples::tuple_list,
AsMutSlice,
}, },
corpus::{ corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -20,6 +20,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice,
}, },
corpus::{ corpus::{
ondisk::OnDiskMetadataFormat, CachedOnDiskCorpus, Corpus, ondisk::OnDiskMetadataFormat, CachedOnDiskCorpus, Corpus,

View File

@ -24,6 +24,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice,
}, },
corpus::{ corpus::{
Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, PowerQueueCorpusScheduler, Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, PowerQueueCorpusScheduler,

View File

@ -21,6 +21,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice,
}, },
corpus::{ corpus::{
Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, PowerQueueCorpusScheduler, Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, PowerQueueCorpusScheduler,

View File

@ -16,6 +16,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice,
}, },
corpus::{ corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -19,6 +19,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice,
}, },
corpus::{ corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -11,6 +11,7 @@ use libafl::{
current_nanos, current_nanos,
rands::StdRand, rands::StdRand,
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice,
}, },
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler}, corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
events::{setup_restarting_mgr_std, EventConfig}, events::{setup_restarting_mgr_std, EventConfig},

View File

@ -12,6 +12,7 @@ use libafl::{
current_nanos, current_nanos,
rands::StdRand, rands::StdRand,
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice,
}, },
corpus::{ corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -18,6 +18,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice,
}, },
corpus::{ corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -18,6 +18,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice,
}, },
corpus::{ corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -7,7 +7,7 @@ static GLOBAL: MiMalloc = MiMalloc;
use std::{env, path::PathBuf}; use std::{env, path::PathBuf};
use libafl::{ use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list}, bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler}, corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
events::{setup_restarting_mgr_std, EventConfig, EventRestarter}, events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
executors::{inprocess::InProcessExecutor, ExitKind}, executors::{inprocess::InProcessExecutor, ExitKind},

View File

@ -7,7 +7,7 @@ static GLOBAL: MiMalloc = MiMalloc;
use std::{env, path::PathBuf}; use std::{env, path::PathBuf};
use libafl::{ use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list}, bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{ corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
QueueCorpusScheduler, QueueCorpusScheduler,

View File

@ -4,7 +4,7 @@ use std::{
env, env,
io::{stdout, Write}, io::{stdout, Write},
path::{Path, PathBuf}, path::{Path, PathBuf},
process::{exit, Command}, process::exit,
}; };
use which::which; use which::which;

View File

@ -13,6 +13,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMem, ShMemProvider, StdShMemProvider}, shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Named}, tuples::{tuple_list, Named},
AsMutSlice, AsSlice,
}, },
corpus::{ corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -3,7 +3,7 @@
use klo_routines::*; use klo_routines::*;
use libafl::inputs::{BytesInput, HasTargetBytes}; use libafl::inputs::{BytesInput, HasTargetBytes};
use libafl::{ use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list}, bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler}, corpus::{InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler},
events::SimpleEventManager, events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind}, executors::{inprocess::InProcessExecutor, ExitKind},

View File

@ -8,7 +8,7 @@ use core::cell::{Cell, RefCell};
use std::{path::PathBuf, rc::Rc}; use std::{path::PathBuf, rc::Rc};
use libafl::{ use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list}, bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{ corpus::{
Corpus, CorpusScheduler, InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler, Testcase, Corpus, CorpusScheduler, InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler, Testcase,
}, },

View File

@ -11,6 +11,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::tuple_list, tuples::tuple_list,
AsSlice,
}, },
corpus::{ corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -7,7 +7,7 @@ use core::time::Duration;
use std::{env, path::PathBuf}; use std::{env, path::PathBuf};
use libafl::{ use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list}, bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, PowerQueueCorpusScheduler}, corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, PowerQueueCorpusScheduler},
events::{setup_restarting_mgr_std, EventConfig, EventRestarter}, events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},

View File

@ -542,7 +542,7 @@ impl LlmpMsg {
/// Gets the buffer from this message as slice, with the corrent length. /// Gets the buffer from this message as slice, with the corrent length.
#[inline] #[inline]
pub fn as_slice<SHM: ShMem>(&self, map: &mut LlmpSharedMap<SHM>) -> Result<&[u8], Error> { pub fn try_as_slice<SHM: ShMem>(&self, map: &mut LlmpSharedMap<SHM>) -> Result<&[u8], Error> {
unsafe { unsafe {
if self.in_shmem(map) { if self.in_shmem(map) {
Ok(self.as_slice_unsafe()) Ok(self.as_slice_unsafe())
@ -1110,7 +1110,7 @@ where
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
let mut end_of_page_msg = (*out).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; let mut end_of_page_msg = (*out).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo;
(*end_of_page_msg).map_size = new_map_shmem.shmem.len(); (*end_of_page_msg).map_size = new_map_shmem.shmem.len();
(*end_of_page_msg).shm_str = *new_map_shmem.shmem.id().as_slice(); (*end_of_page_msg).shm_str = *new_map_shmem.shmem.id().as_array();
/* Send the last msg on the old buf */ /* Send the last msg on the old buf */
self.send(out, true)?; self.send(out, true)?;
@ -1439,7 +1439,7 @@ where
// Map the new page. The old one should be unmapped by Drop // Map the new page. The old one should be unmapped by Drop
self.current_recv_shmem = self.current_recv_shmem =
LlmpSharedMap::existing(self.shmem_provider.shmem_from_id_and_size( LlmpSharedMap::existing(self.shmem_provider.shmem_from_id_and_size(
ShMemId::from_slice(&pageinfo_cpy.shm_str), ShMemId::from_array(&pageinfo_cpy.shm_str),
pageinfo_cpy.map_size, pageinfo_cpy.map_size,
)?); )?);
page = self.current_recv_shmem.page_mut(); page = self.current_recv_shmem.page_mut();
@ -1512,7 +1512,7 @@ where
(*msg).sender, (*msg).sender,
(*msg).tag, (*msg).tag,
(*msg).flags, (*msg).flags,
(*msg).as_slice(&mut self.current_recv_shmem)?, (*msg).try_as_slice(&mut self.current_recv_shmem)?,
)), )),
None => None, None => None,
}) })
@ -1527,7 +1527,7 @@ where
Ok(( Ok((
(*msg).sender, (*msg).sender,
(*msg).tag, (*msg).tag,
(*msg).as_slice(&mut self.current_recv_shmem)?, (*msg).try_as_slice(&mut self.current_recv_shmem)?,
)) ))
} }
} }
@ -1997,7 +1997,7 @@ where
(*msg).tag = LLMP_TAG_NEW_SHM_CLIENT; (*msg).tag = LLMP_TAG_NEW_SHM_CLIENT;
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo;
(*pageinfo).shm_str = *shmem_description.id.as_slice(); (*pageinfo).shm_str = *shmem_description.id.as_array();
(*pageinfo).map_size = shmem_description.size; (*pageinfo).map_size = shmem_description.size;
sender.send(msg, true) sender.send(msg, true)
} }
@ -2329,7 +2329,7 @@ where
let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo; let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo;
match self.shmem_provider.shmem_from_id_and_size( match self.shmem_provider.shmem_from_id_and_size(
ShMemId::from_slice(&(*pageinfo).shm_str), ShMemId::from_array(&(*pageinfo).shm_str),
(*pageinfo).map_size, (*pageinfo).map_size,
) { ) {
Ok(new_shmem) => { Ok(new_shmem) => {
@ -2363,7 +2363,7 @@ where
let mut should_forward_msg = true; let mut should_forward_msg = true;
let map = &mut self.llmp_clients[client_id as usize].current_recv_shmem; let map = &mut self.llmp_clients[client_id as usize].current_recv_shmem;
let msg_buf = (*msg).as_slice(map)?; let msg_buf = (*msg).try_as_slice(map)?;
if let LlmpMsgHookResult::Handled = if let LlmpMsgHookResult::Handled =
(on_new_msg)(client_id, (*msg).tag, (*msg).flags, msg_buf)? (on_new_msg)(client_id, (*msg).tag, (*msg).flags, msg_buf)?
{ {

View File

@ -30,6 +30,12 @@ pub trait AsSlice<T> {
fn as_slice(&self) -> &[T]; fn as_slice(&self) -> &[T];
} }
/// Can be converted to a mutable slice
pub trait AsMutSlice<T> {
/// Convert to a slice
fn as_mut_slice(&mut self) -> &mut [T];
}
/// Has a length field /// Has a length field
pub trait HasLen { pub trait HasLen {
/// The length /// The length

View File

@ -6,7 +6,10 @@ and forwards them over unix domain sockets.
*/ */
use crate::{ use crate::{
bolts::shmem::{ShMem, ShMemDescription, ShMemId, ShMemProvider}, bolts::{
shmem::{ShMem, ShMemDescription, ShMemId, ShMemProvider},
AsMutSlice, AsSlice,
},
Error, Error,
}; };
use core::{mem::ManuallyDrop, ptr::addr_of}; use core::{mem::ManuallyDrop, ptr::addr_of};
@ -88,11 +91,20 @@ where
fn len(&self) -> usize { fn len(&self) -> usize {
self.inner.len() self.inner.len()
} }
}
impl<SH> AsSlice<u8> for ServedShMem<SH>
where
SH: ShMem,
{
fn as_slice(&self) -> &[u8] { fn as_slice(&self) -> &[u8] {
self.inner.as_slice() self.inner.as_slice()
} }
}
impl<SH> AsMutSlice<u8> for ServedShMem<SH>
where
SH: ShMem,
{
fn as_mut_slice(&mut self) -> &mut [u8] { fn as_mut_slice(&mut self) -> &mut [u8] {
self.inner.as_mut_slice() self.inner.as_mut_slice()
} }
@ -124,7 +136,7 @@ where
.recv_fds(&mut shm_slice, &mut fd_buf) .recv_fds(&mut shm_slice, &mut fd_buf)
.expect("Did not receive a response"); .expect("Did not receive a response");
let server_id = ShMemId::from_slice(&shm_slice); let server_id = ShMemId::from_array(&shm_slice);
let server_fd: i32 = server_id.into(); let server_fd: i32 = server_id.into();
Ok((server_fd, fd_buf[0])) Ok((server_fd, fd_buf[0]))
} }

View File

@ -1,7 +1,12 @@
//! Wrappers that abstracts references (or pointers) and owned data accesses. //! Wrappers that abstracts references (or pointers) and owned data accesses.
// The serialization is towards owned, allowing to serialize pointers without troubles. // The serialization is towards owned, allowing to serialize pointers without troubles.
use alloc::{boxed::Box, vec::Vec}; use crate::bolts::{AsMutSlice, AsSlice};
use alloc::{
boxed::Box,
slice::{Iter, IterMut},
vec::Vec,
};
use core::{clone::Clone, fmt::Debug, slice}; use core::{clone::Clone, fmt::Debug, slice};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -234,6 +239,15 @@ impl<'a, T> OwnedSlice<'a, T> {
} }
} }
impl<'a, 'it, T> IntoIterator for &'it OwnedSlice<'a, T> {
type Item = <Iter<'it, T> as Iterator>::Item;
type IntoIter = Iter<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
/// Create a new [`OwnedSlice`] from a vector /// Create a new [`OwnedSlice`] from a vector
impl<'a, T> From<Vec<T>> for OwnedSlice<'a, T> { impl<'a, T> From<Vec<T>> for OwnedSlice<'a, T> {
fn from(vec: Vec<T>) -> Self { fn from(vec: Vec<T>) -> Self {
@ -274,10 +288,10 @@ impl<'a, T> From<OwnedSliceMut<'a, T>> for OwnedSlice<'a, T> {
} }
} }
impl<'a, T: Sized> OwnedSlice<'a, T> { impl<'a, T: Sized> AsSlice<T> for OwnedSlice<'a, T> {
/// Get the [`OwnedSlice`] as slice. /// Get the [`OwnedSlice`] as slice.
#[must_use] #[must_use]
pub fn as_slice(&self) -> &[T] { fn as_slice(&self) -> &[T] {
match &self.inner { match &self.inner {
OwnedSliceInner::Ref(r) => r, OwnedSliceInner::Ref(r) => r,
OwnedSliceInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts(*rr, *len) }, OwnedSliceInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts(*rr, *len) },
@ -361,6 +375,24 @@ pub struct OwnedSliceMut<'a, T: 'a + Sized> {
inner: OwnedSliceMutInner<'a, T>, inner: OwnedSliceMutInner<'a, T>,
} }
impl<'a, 'it, T> IntoIterator for &'it mut OwnedSliceMut<'a, T> {
type Item = <IterMut<'it, T> as Iterator>::Item;
type IntoIter = IterMut<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
impl<'a, 'it, T> IntoIterator for &'it OwnedSliceMut<'a, T> {
type Item = <Iter<'it, T> as Iterator>::Item;
type IntoIter = Iter<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'a, T: 'a + Sized> OwnedSliceMut<'a, T> { impl<'a, T: 'a + Sized> OwnedSliceMut<'a, T> {
/// Create a new [`OwnedSliceMut`] from a raw pointer and length /// Create a new [`OwnedSliceMut`] from a raw pointer and length
/// ///
@ -382,20 +414,21 @@ impl<'a, T: 'a + Sized> OwnedSliceMut<'a, T> {
} }
} }
impl<'a, T: Sized> OwnedSliceMut<'a, T> { impl<'a, T: Sized> AsSlice<T> for OwnedSliceMut<'a, T> {
/// Get the value as slice /// Get the value as slice
#[must_use] #[must_use]
pub fn as_slice(&self) -> &[T] { fn as_slice(&self) -> &[T] {
match &self.inner { match &self.inner {
OwnedSliceMutInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts(*rr, *len) }, OwnedSliceMutInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts(*rr, *len) },
OwnedSliceMutInner::Ref(r) => r, OwnedSliceMutInner::Ref(r) => r,
OwnedSliceMutInner::Owned(v) => v.as_slice(), OwnedSliceMutInner::Owned(v) => v.as_slice(),
} }
} }
}
impl<'a, T: Sized> AsMutSlice<T> for OwnedSliceMut<'a, T> {
/// Get the value as mut slice /// Get the value as mut slice
#[must_use] #[must_use]
pub fn as_mut_slice(&mut self) -> &mut [T] { fn as_mut_slice(&mut self) -> &mut [T] {
match &mut self.inner { match &mut self.inner {
OwnedSliceMutInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts_mut(*rr, *len) }, OwnedSliceMutInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts_mut(*rr, *len) },
OwnedSliceMutInner::Ref(r) => r, OwnedSliceMutInner::Ref(r) => r,
@ -608,140 +641,3 @@ where
} }
} }
} }
/// Wrap a C-style pointer to an array (with size) and convert to a Vec on serialize
#[derive(Clone, Debug)]
pub enum OwnedArrayPtr<T: Sized> {
/// Ptr to a slice
ArrayPtr((*const T, usize)),
/// A owned [`Vec`].
Owned(Vec<T>),
}
impl<T: Sized + Serialize> Serialize for OwnedArrayPtr<T> {
fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.as_slice().serialize(se)
}
}
impl<'de, T: Sized + Serialize> Deserialize<'de> for OwnedArrayPtr<T>
where
Vec<T>: Deserialize<'de>,
{
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(de).map(OwnedArrayPtr::Owned)
}
}
impl<T: Sized> OwnedArrayPtr<T> {
/// Get a slice from this array.
#[must_use]
pub fn as_slice(&self) -> &[T] {
match self {
OwnedArrayPtr::ArrayPtr(p) => unsafe { core::slice::from_raw_parts(p.0, p.1) },
OwnedArrayPtr::Owned(v) => v.as_slice(),
}
}
}
impl<T> IntoOwned for OwnedArrayPtr<T>
where
T: Sized + Clone,
{
#[must_use]
fn is_owned(&self) -> bool {
match self {
OwnedArrayPtr::ArrayPtr(_) => false,
OwnedArrayPtr::Owned(_) => true,
}
}
#[must_use]
fn into_owned(self) -> Self {
match self {
OwnedArrayPtr::ArrayPtr(p) => unsafe {
OwnedArrayPtr::Owned(core::slice::from_raw_parts(p.0, p.1).to_vec())
},
OwnedArrayPtr::Owned(v) => OwnedArrayPtr::Owned(v),
}
}
}
/// Wrap a C-style mutable pointer to an array (with size) and convert to a Vec on serialize
#[derive(Clone, Debug)]
pub enum OwnedArrayPtrMut<T: Sized> {
/// A ptr to the array (or slice).
ArrayPtr((*mut T, usize)),
/// An owned [`Vec`].
Owned(Vec<T>),
}
impl<T: Sized + Serialize> Serialize for OwnedArrayPtrMut<T> {
fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.as_slice().serialize(se)
}
}
impl<'de, T: Sized + Serialize> Deserialize<'de> for OwnedArrayPtrMut<T>
where
Vec<T>: Deserialize<'de>,
{
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(de).map(OwnedArrayPtrMut::Owned)
}
}
impl<T: Sized> OwnedArrayPtrMut<T> {
/// Return this array as slice
#[must_use]
pub fn as_slice(&self) -> &[T] {
match self {
OwnedArrayPtrMut::ArrayPtr(p) => unsafe { core::slice::from_raw_parts(p.0, p.1) },
OwnedArrayPtrMut::Owned(v) => v.as_slice(),
}
}
/// Return this array as mut slice
#[must_use]
pub fn as_mut_slice(&mut self) -> &mut [T] {
match self {
OwnedArrayPtrMut::ArrayPtr(p) => unsafe { core::slice::from_raw_parts_mut(p.0, p.1) },
OwnedArrayPtrMut::Owned(v) => v.as_mut_slice(),
}
}
}
impl<T> IntoOwned for OwnedArrayPtrMut<T>
where
T: Sized + Clone,
{
#[must_use]
fn is_owned(&self) -> bool {
match self {
OwnedArrayPtrMut::ArrayPtr(_) => false,
OwnedArrayPtrMut::Owned(_) => true,
}
}
#[must_use]
fn into_owned(self) -> Self {
match self {
OwnedArrayPtrMut::ArrayPtr(p) => unsafe {
OwnedArrayPtrMut::Owned(core::slice::from_raw_parts(p.0, p.1).to_vec())
},
OwnedArrayPtrMut::Owned(v) => OwnedArrayPtrMut::Owned(v),
}
}
}

View File

@ -3,7 +3,10 @@
#[cfg(all(unix, feature = "std"))] #[cfg(all(unix, feature = "std"))]
use crate::bolts::os::pipes::Pipe; use crate::bolts::os::pipes::Pipe;
use crate::Error; use crate::{
bolts::{AsMutSlice, AsSlice},
Error,
};
use alloc::{rc::Rc, string::ToString}; use alloc::{rc::Rc, string::ToString};
use core::{ use core::{
cell::RefCell, cell::RefCell,
@ -89,10 +92,17 @@ pub struct ShMemId {
} }
impl ShMemId { impl ShMemId {
/// Create a new id from a fixed-size string /// Create a new id from a fixed-size string/bytes array
/// It should contain a valid cstring.
#[must_use] #[must_use]
pub fn from_slice(slice: &[u8; 20]) -> Self { pub fn from_array(array: &[u8; 20]) -> Self {
Self { id: *slice } Self { id: *array }
}
/// Try to create a new id from a bytes string.
/// The slice must have a length of at least 20 bytes and contain a valid cstring.
pub fn try_from_slice(slice: &[u8]) -> Result<Self, Error> {
Ok(Self::from_array(&slice[0..20].try_into()?))
} }
/// Create a new id from an int /// Create a new id from an int
@ -113,7 +123,7 @@ impl ShMemId {
/// Get the id as a fixed-length slice /// Get the id as a fixed-length slice
#[must_use] #[must_use]
pub fn as_slice(&self) -> &[u8; 20] { pub fn as_array(&self) -> &[u8; 20] {
&self.id &self.id
} }
@ -129,6 +139,11 @@ impl ShMemId {
alloc::str::from_utf8(&self.id[..self.null_pos()]).unwrap() alloc::str::from_utf8(&self.id[..self.null_pos()]).unwrap()
} }
} }
impl AsSlice<u8> for ShMemId {
fn as_slice(&self) -> &[u8] {
&self.id
}
}
impl From<ShMemId> for i32 { impl From<ShMemId> for i32 {
fn from(id: ShMemId) -> i32 { fn from(id: ShMemId) -> i32 {
@ -145,7 +160,7 @@ impl Display for ShMemId {
/// A [`ShMem`] is an interface to shared maps. /// A [`ShMem`] is an interface to shared maps.
/// They are the backbone of [`crate::bolts::llmp`] for inter-process communication. /// They are the backbone of [`crate::bolts::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`]. /// 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 { pub trait ShMem: Sized + Debug + Clone + AsSlice<u8> + AsMutSlice<u8> {
/// Get the id of this shared memory mapping /// Get the id of this shared memory mapping
fn id(&self) -> ShMemId; fn id(&self) -> ShMemId;
@ -165,12 +180,6 @@ pub trait ShMem: Sized + Debug + Clone {
} }
} }
/// The actual shared map, in memory
fn as_slice(&self) -> &[u8];
/// The actual shared map, mutable
fn as_mut_slice(&mut self) -> &mut [u8];
/// Write this map's config to env /// Write this map's config to env
#[cfg(feature = "std")] #[cfg(feature = "std")]
fn write_to_env(&self, env_name: &str) -> Result<(), Error> { fn write_to_env(&self, env_name: &str) -> Result<(), Error> {
@ -264,11 +273,21 @@ where
fn len(&self) -> usize { fn len(&self) -> usize {
self.internal.len() self.internal.len()
} }
}
impl<T> AsSlice<u8> for RcShMem<T>
where
T: ShMemProvider + Debug,
{
fn as_slice(&self) -> &[u8] { fn as_slice(&self) -> &[u8] {
self.internal.as_slice() self.internal.as_slice()
} }
}
impl<T> AsMutSlice<u8> for RcShMem<T>
where
T: ShMemProvider + Debug,
{
fn as_mut_slice(&mut self) -> &mut [u8] { fn as_mut_slice(&mut self) -> &mut [u8] {
self.internal.as_mut_slice() self.internal.as_mut_slice()
} }
@ -489,7 +508,10 @@ pub mod unix_shmem {
use std::{io::Write, process}; use std::{io::Write, process};
use crate::{ use crate::{
bolts::shmem::{ShMem, ShMemId, ShMemProvider}, bolts::{
shmem::{ShMem, ShMemId, ShMemProvider},
AsMutSlice, AsSlice,
},
Error, Error,
}; };
#[cfg(unix)] #[cfg(unix)]
@ -691,11 +713,15 @@ pub mod unix_shmem {
fn len(&self) -> usize { fn len(&self) -> usize {
self.map_size self.map_size
} }
}
impl AsSlice<u8> for MmapShMem {
fn as_slice(&self) -> &[u8] { fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.map, self.map_size) } unsafe { slice::from_raw_parts(self.map, self.map_size) }
} }
}
impl AsMutSlice<u8> for MmapShMem {
fn as_mut_slice(&mut self) -> &mut [u8] { fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.map, self.map_size) } unsafe { slice::from_raw_parts_mut(self.map, self.map_size) }
} }
@ -790,11 +816,15 @@ pub mod unix_shmem {
fn len(&self) -> usize { fn len(&self) -> usize {
self.map_size self.map_size
} }
}
impl AsSlice<u8> for CommonUnixShMem {
fn as_slice(&self) -> &[u8] { fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.map, self.map_size) } unsafe { slice::from_raw_parts(self.map, self.map_size) }
} }
}
impl AsMutSlice<u8> for CommonUnixShMem {
fn as_mut_slice(&mut self) -> &mut [u8] { fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.map, self.map_size) } unsafe { slice::from_raw_parts_mut(self.map, self.map_size) }
} }
@ -858,7 +888,10 @@ pub mod unix_shmem {
use std::ffi::CString; use std::ffi::CString;
use crate::{ use crate::{
bolts::shmem::{ShMem, ShMemId, ShMemProvider}, bolts::{
shmem::{ShMem, ShMemId, ShMemProvider},
AsMutSlice, AsSlice,
},
Error, Error,
}; };
@ -992,11 +1025,15 @@ pub mod unix_shmem {
fn len(&self) -> usize { fn len(&self) -> usize {
self.map_size self.map_size
} }
}
impl AsSlice<u8> for AshmemShMem {
fn as_slice(&self) -> &[u8] { fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.map, self.map_size) } unsafe { slice::from_raw_parts(self.map, self.map_size) }
} }
}
impl AsMutSlice<u8> for AshmemShMem {
fn as_mut_slice(&mut self) -> &mut [u8] { fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.map, self.map_size) } unsafe { slice::from_raw_parts_mut(self.map, self.map_size) }
} }
@ -1069,7 +1106,10 @@ pub mod unix_shmem {
pub mod win32_shmem { pub mod win32_shmem {
use crate::{ use crate::{
bolts::shmem::{ShMem, ShMemId, ShMemProvider}, bolts::{
shmem::{ShMem, ShMemId, ShMemProvider},
AsMutSlice, AsSlice,
},
Error, Error,
}; };
@ -1141,7 +1181,7 @@ pub mod win32_shmem {
} }
Ok(Self { Ok(Self {
id: ShMemId::from_slice(&map_str_bytes[0..20].try_into().unwrap()), id: ShMemId::try_from_slice(&map_str_bytes).unwrap(),
handle, handle,
map, map,
map_size, map_size,
@ -1189,11 +1229,14 @@ pub mod win32_shmem {
fn len(&self) -> usize { fn len(&self) -> usize {
self.map_size self.map_size
} }
}
impl AsSlice<u8> for Win32ShMem {
fn as_slice(&self) -> &[u8] { fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.map, self.map_size) } unsafe { slice::from_raw_parts(self.map, self.map_size) }
} }
}
impl AsMutSlice<u8> for Win32ShMem {
fn as_mut_slice(&mut self) -> &mut [u8] { fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.map, self.map_size) } unsafe { slice::from_raw_parts_mut(self.map, self.map_size) }
} }
@ -1348,7 +1391,10 @@ impl<T: ShMem> std::io::Seek for ShMemCursor<T> {
mod tests { mod tests {
use serial_test::serial; use serial_test::serial;
use crate::bolts::shmem::{ShMem, ShMemProvider, StdShMemProvider}; use crate::bolts::{
shmem::{ShMemProvider, StdShMemProvider},
AsMutSlice, AsSlice,
};
#[test] #[test]
#[serial] #[serial]

View File

@ -12,7 +12,10 @@ use std::{
}; };
use crate::{ use crate::{
bolts::shmem::{ShMem, ShMemProvider}, bolts::{
shmem::{ShMem, ShMemProvider},
AsSlice,
},
Error, Error,
}; };

View File

@ -105,7 +105,7 @@ where
/// # Example /// # Example
/// ``` /// ```
/// use std::{io::Write, process::{Stdio, Command, Child}}; /// use std::{io::Write, process::{Stdio, Command, Child}};
/// use libafl::{Error, inputs::{Input, HasTargetBytes}, executors::{Executor, command::CommandConfigurator}}; /// use libafl::{Error, bolts::AsSlice, inputs::{Input, HasTargetBytes}, executors::{Executor, command::CommandConfigurator}};
/// #[derive(Debug)] /// #[derive(Debug)]
/// struct MyExecutor; /// struct MyExecutor;
/// ///

View File

@ -19,6 +19,7 @@ use crate::{
bolts::{ bolts::{
os::{dup2, pipes::Pipe}, os::{dup2, pipes::Pipe},
shmem::{ShMem, ShMemProvider, StdShMemProvider}, shmem::{ShMem, ShMemProvider, StdShMemProvider},
AsMutSlice, AsSlice,
}, },
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
@ -832,6 +833,7 @@ mod tests {
bolts::{ bolts::{
shmem::{ShMem, ShMemProvider, StdShMemProvider}, shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::tuple_list, tuples::tuple_list,
AsMutSlice,
}, },
executors::ForkserverExecutor, executors::ForkserverExecutor,
inputs::NopInput, inputs::NopInput,

View File

@ -32,6 +32,7 @@ pub mod command;
pub use command::CommandExecutor; pub use command::CommandExecutor;
use crate::{ use crate::{
bolts::AsSlice,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::ObserversTuple, observers::ObserversTuple,
Error, Error,

View File

@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::{ bolts::{
tuples::{MatchName, Named}, tuples::{MatchName, Named},
AsSlice, HasRefCnt, AsMutSlice, AsSlice, HasRefCnt,
}, },
corpus::Testcase, corpus::Testcase,
events::{Event, EventFirer}, events::{Event, EventFirer},
@ -214,6 +214,12 @@ impl AsSlice<usize> for MapIndexesMetadata {
self.list.as_slice() self.list.as_slice()
} }
} }
impl AsMutSlice<usize> for MapIndexesMetadata {
/// Convert to a slice
fn as_mut_slice(&mut self) -> &mut [usize] {
self.list.as_mut_slice()
}
}
impl HasRefCnt for MapIndexesMetadata { impl HasRefCnt for MapIndexesMetadata {
fn refcnt(&self) -> isize { fn refcnt(&self) -> isize {
@ -249,6 +255,13 @@ impl AsSlice<usize> for MapNoveltiesMetadata {
self.list.as_slice() self.list.as_slice()
} }
} }
impl AsMutSlice<usize> for MapNoveltiesMetadata {
/// Convert to a slice
#[must_use]
fn as_mut_slice(&mut self) -> &mut [usize] {
self.list.as_mut_slice()
}
}
impl MapNoveltiesMetadata { impl MapNoveltiesMetadata {
/// Creates a new [`struct@MapNoveltiesMetadata`] /// Creates a new [`struct@MapNoveltiesMetadata`]
#[must_use] #[must_use]
@ -308,7 +321,7 @@ where
/// Create new `MapFeedbackState` for the observer type. /// Create new `MapFeedbackState` for the observer type.
pub fn with_observer<O>(map_observer: &O) -> Self pub fn with_observer<O>(map_observer: &O) -> Self
where where
O: MapObserver<T>, O: MapObserver<Entry = T>,
T: Debug, T: Debug,
{ {
Self { Self {
@ -335,7 +348,7 @@ pub struct MapFeedback<I, N, O, R, S, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
R: Reducer<T>, R: Reducer<T>,
O: MapObserver<T>, O: MapObserver,
N: IsNovel<T>, N: IsNovel<T>,
S: HasFeedbackStates, S: HasFeedbackStates,
{ {
@ -355,7 +368,7 @@ impl<I, N, O, R, S, T> Feedback<I, S> for MapFeedback<I, N, O, R, S, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
R: Reducer<T>, R: Reducer<T>,
O: MapObserver<T>, O: MapObserver<Entry = T>,
N: IsNovel<T>, N: IsNovel<T>,
I: Input, I: Input,
S: HasFeedbackStates + HasClientPerfMonitor + Debug, S: HasFeedbackStates + HasClientPerfMonitor + Debug,
@ -464,7 +477,7 @@ where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
R: Reducer<T>, R: Reducer<T>,
N: IsNovel<T>, N: IsNovel<T>,
O: MapObserver<T>, O: MapObserver,
S: HasFeedbackStates, S: HasFeedbackStates,
{ {
#[inline] #[inline]
@ -485,7 +498,7 @@ where
+ Debug, + Debug,
R: Reducer<T>, R: Reducer<T>,
N: IsNovel<T>, N: IsNovel<T>,
O: MapObserver<T>, O: MapObserver,
S: HasFeedbackStates, S: HasFeedbackStates,
{ {
/// Create new `MapFeedback` /// Create new `MapFeedback`
@ -557,7 +570,7 @@ pub struct ReachabilityFeedback<O> {
impl<O> ReachabilityFeedback<O> impl<O> ReachabilityFeedback<O>
where where
O: MapObserver<usize>, O: MapObserver<Entry = usize>,
{ {
/// Creates a new [`ReachabilityFeedback`] for a [`MapObserver`]. /// Creates a new [`ReachabilityFeedback`] for a [`MapObserver`].
#[must_use] #[must_use]
@ -583,7 +596,7 @@ where
impl<I, O, S> Feedback<I, S> for ReachabilityFeedback<O> impl<I, O, S> Feedback<I, S> for ReachabilityFeedback<O>
where where
I: Input, I: Input,
O: MapObserver<usize>, O: MapObserver<Entry = usize>,
S: HasClientPerfMonitor, S: HasClientPerfMonitor,
{ {
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
@ -632,7 +645,7 @@ where
impl<O> Named for ReachabilityFeedback<O> impl<O> Named for ReachabilityFeedback<O>
where where
O: MapObserver<usize>, O: MapObserver<Entry = usize>,
{ {
#[inline] #[inline]
fn name(&self) -> &str { fn name(&self) -> &str {

View File

@ -1,5 +1,6 @@
//! The `EncodedInput` is the "normal" input, a map of codes, that can be sent directly to the client //! The `EncodedInput` is the "normal" input, a map of codes, that can be sent directly to the client
//! (As opposed to other, more abstract, imputs, like an Grammar-Based AST Input) //! (As opposed to other, more abstract, imputs, like an Grammar-Based AST Input)
//! See also [the paper on token-level fuzzing](https://www.usenix.org/system/files/sec21-salls.pdf)
use ahash::AHasher; use ahash::AHasher;
use core::hash::Hasher; use core::hash::Hasher;

View File

@ -113,11 +113,11 @@ pub mod stats {
pub use crate::monitors::UserStats; pub use crate::monitors::UserStats;
} }
use alloc::string::String; use alloc::string::{FromUtf8Error, String};
use core::fmt; use core::{array::TryFromSliceError, fmt, num::ParseIntError, num::TryFromIntError};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::{env::VarError, io, num::ParseIntError, num::TryFromIntError, string::FromUtf8Error}; use std::{env::VarError, io};
/// Main error struct for AFL /// Main error struct for AFL
#[derive(Debug)] #[derive(Debug)]
@ -209,10 +209,9 @@ impl From<io::Error> for Error {
} }
} }
#[cfg(feature = "std")]
impl From<FromUtf8Error> for Error { impl From<FromUtf8Error> for Error {
fn from(err: FromUtf8Error) -> Self { fn from(err: FromUtf8Error) -> Self {
Self::Unknown(format!("Could not convert byte to utf-8: {:?}", err)) Self::Unknown(format!("Could not convert byte / utf-8: {:?}", err))
} }
} }
@ -223,20 +222,24 @@ impl From<VarError> for Error {
} }
} }
#[cfg(feature = "std")]
impl From<ParseIntError> for Error { impl From<ParseIntError> for Error {
fn from(err: ParseIntError) -> Self { fn from(err: ParseIntError) -> Self {
Self::Unknown(format!("Failed to parse Int: {:?}", err)) Self::Unknown(format!("Failed to parse Int: {:?}", err))
} }
} }
#[cfg(feature = "std")]
impl From<TryFromIntError> for Error { impl From<TryFromIntError> for Error {
fn from(err: TryFromIntError) -> Self { fn from(err: TryFromIntError) -> Self {
Self::IllegalState(format!("Expected conversion failed: {:?}", err)) Self::IllegalState(format!("Expected conversion failed: {:?}", err))
} }
} }
impl From<TryFromSliceError> for Error {
fn from(err: TryFromSliceError) -> Self {
Self::IllegalArgument(format!("Could not convert slice: {:?}", err))
}
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error {} impl std::error::Error for Error {}

View File

@ -11,7 +11,7 @@ use crate::{
bolts::{ bolts::{
rands::Rand, rands::Rand,
tuples::{tuple_list, tuple_list_type, NamedTuple}, tuples::{tuple_list, tuple_list_type, NamedTuple},
AsSlice, AsMutSlice, AsSlice,
}, },
corpus::Corpus, corpus::Corpus,
inputs::Input, inputs::Input,
@ -33,10 +33,17 @@ pub struct LogMutationMetadata {
crate::impl_serdeany!(LogMutationMetadata); crate::impl_serdeany!(LogMutationMetadata);
impl AsSlice<String> for LogMutationMetadata { impl AsSlice<String> for LogMutationMetadata {
#[must_use]
fn as_slice(&self) -> &[String] { fn as_slice(&self) -> &[String] {
self.list.as_slice() self.list.as_slice()
} }
} }
impl AsMutSlice<String> for LogMutationMetadata {
#[must_use]
fn as_mut_slice(&mut self) -> &mut [String] {
self.list.as_mut_slice()
}
}
impl LogMutationMetadata { impl LogMutationMetadata {
/// Creates new [`struct@LogMutationMetadata`]. /// Creates new [`struct@LogMutationMetadata`].

View File

@ -8,7 +8,7 @@ use core::fmt::Debug;
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{ use crate::{
bolts::{ownedref::OwnedRefMut, tuples::Named, AsSlice}, bolts::{ownedref::OwnedRefMut, tuples::Named, AsMutSlice, AsSlice},
observers::Observer, observers::Observer,
state::HasMetadata, state::HasMetadata,
Error, Error,
@ -69,6 +69,13 @@ impl AsSlice<CmpValues> for CmpValuesMetadata {
self.list.as_slice() self.list.as_slice()
} }
} }
impl AsMutSlice<CmpValues> for CmpValuesMetadata {
/// Convert to a slice
#[must_use]
fn as_mut_slice(&mut self) -> &mut [CmpValues] {
self.list.as_mut_slice()
}
}
impl CmpValuesMetadata { impl CmpValuesMetadata {
/// Creates a new [`struct@CmpValuesMetadata`] /// Creates a new [`struct@CmpValuesMetadata`]
@ -111,10 +118,10 @@ where
fn usable_count(&self) -> usize; fn usable_count(&self) -> usize;
/// Get the `CmpMap` /// Get the `CmpMap`
fn map(&self) -> &CM; fn cmp_map(&self) -> &CM;
/// Get the `CmpMap` (mut) /// Get the `CmpMap` (mut)
fn map_mut(&mut self) -> &mut CM; fn cmp_map_mut(&mut self) -> &mut CM;
/// Add [`struct@CmpValuesMetadata`] to the State including the logged values. /// Add [`struct@CmpValuesMetadata`] to the State including the logged values.
/// This routine does a basic loop filtering because loop index cmps are not interesting. /// This routine does a basic loop filtering because loop index cmps are not interesting.
@ -132,7 +139,7 @@ where
meta.list.clear(); meta.list.clear();
let count = self.usable_count(); let count = self.usable_count();
for i in 0..count { for i in 0..count {
let execs = self.map().usable_executions_for(i); let execs = self.cmp_map().usable_executions_for(i);
if execs > 0 { if execs > 0 {
// Recongize loops and discard if needed // Recongize loops and discard if needed
if execs > 4 { if execs > 4 {
@ -143,7 +150,7 @@ where
let mut last: Option<CmpValues> = None; let mut last: Option<CmpValues> = None;
for j in 0..execs { for j in 0..execs {
let val = self.map().values_of(i, j); let val = self.cmp_map().values_of(i, j);
if let Some(l) = last.and_then(|x| x.to_u64_tuple()) { if let Some(l) = last.and_then(|x| x.to_u64_tuple()) {
if let Some(v) = val.to_u64_tuple() { if let Some(v) = val.to_u64_tuple() {
if l.0.wrapping_add(1) == v.0 { if l.0.wrapping_add(1) == v.0 {
@ -173,7 +180,7 @@ where
} }
} }
for j in 0..execs { for j in 0..execs {
meta.list.push(self.map().values_of(i, j)); meta.list.push(self.cmp_map().values_of(i, j));
} }
} }
} }
@ -187,7 +194,7 @@ pub struct StdCmpObserver<'a, CM>
where where
CM: CmpMap + Serialize + DeserializeOwned, CM: CmpMap + Serialize + DeserializeOwned,
{ {
map: OwnedRefMut<'a, CM>, cmp_map: OwnedRefMut<'a, CM>,
size: Option<OwnedRefMut<'a, usize>>, size: Option<OwnedRefMut<'a, usize>>,
name: String, name: String,
} }
@ -199,17 +206,17 @@ where
/// Get the number of usable cmps (all by default) /// Get the number of usable cmps (all by default)
fn usable_count(&self) -> usize { fn usable_count(&self) -> usize {
match &self.size { match &self.size {
None => self.map.as_ref().len(), None => self.cmp_map.as_ref().len(),
Some(o) => *o.as_ref(), Some(o) => *o.as_ref(),
} }
} }
fn map(&self) -> &CM { fn cmp_map(&self) -> &CM {
self.map.as_ref() self.cmp_map.as_ref()
} }
fn map_mut(&mut self) -> &mut CM { fn cmp_map_mut(&mut self) -> &mut CM {
self.map.as_mut() self.cmp_map.as_mut()
} }
} }
@ -218,7 +225,7 @@ where
CM: CmpMap + Serialize + DeserializeOwned, CM: CmpMap + Serialize + DeserializeOwned,
{ {
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
self.map.as_mut().reset()?; self.cmp_map.as_mut().reset()?;
Ok(()) Ok(())
} }
} }
@ -242,7 +249,7 @@ where
Self { Self {
name: name.to_string(), name: name.to_string(),
size: None, size: None,
map: OwnedRefMut::Ref(map), cmp_map: OwnedRefMut::Ref(map),
} }
} }
@ -252,7 +259,7 @@ where
Self { Self {
name: name.to_string(), name: name.to_string(),
size: Some(OwnedRefMut::Ref(size)), size: Some(OwnedRefMut::Ref(size)),
map: OwnedRefMut::Ref(map), cmp_map: OwnedRefMut::Ref(map),
} }
} }
} }

View File

@ -5,7 +5,12 @@ use alloc::{
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
}; };
use core::{fmt::Debug, hash::Hasher, slice::from_raw_parts}; use core::{
fmt::Debug,
hash::Hasher,
iter::Flatten,
slice::{from_raw_parts, Iter, IterMut},
};
use intervaltree::IntervalTree; use intervaltree::IntervalTree;
use num_traits::PrimInt; use num_traits::PrimInt;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -14,41 +19,36 @@ use crate::{
bolts::{ bolts::{
ownedref::{OwnedRefMut, OwnedSliceMut}, ownedref::{OwnedRefMut, OwnedSliceMut},
tuples::Named, tuples::Named,
HasLen, AsMutSlice, AsSlice, HasLen,
}, },
observers::Observer, observers::Observer,
Error, Error,
}; };
/// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information /// Compute the hash of a slice
pub trait MapObserver<T>: HasLen + Named + Serialize + serde::de::DeserializeOwned + Debug fn hash_slice<T: PrimInt>(slice: &[T]) -> u64 {
where let mut hasher = AHasher::new_with_keys(0, 0);
T: PrimInt + Default + Copy + Debug, let ptr = slice.as_ptr() as *const u8;
{ let map_size = slice.len() / core::mem::size_of::<T>();
/// Get the map if the observer can be represented with a slice unsafe {
fn map(&self) -> Option<&[T]>; hasher.write(from_raw_parts(ptr, map_size));
}
hasher.finish()
}
/// Get the map (mutable) if the observer can be represented with a slice /// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information
fn map_mut(&mut self) -> Option<&mut [T]>; pub trait MapObserver: HasLen + Named + Serialize + serde::de::DeserializeOwned + Debug {
/// Type of each entry in this map
type Entry: PrimInt + Default + Copy + Debug;
/// Get the value at `idx` /// Get the value at `idx`
fn get(&self, idx: usize) -> &T { fn get(&self, idx: usize) -> &Self::Entry;
&self
.map()
.expect("Cannot get a map that cannot be represented as slice")[idx]
}
/// Get the value at `idx` (mutable) /// Get the value at `idx` (mutable)
fn get_mut(&mut self, idx: usize) -> &mut T { fn get_mut(&mut self, idx: usize) -> &mut Self::Entry;
&mut self
.map_mut()
.expect("Cannot get a map that cannot be represented as slice")[idx]
}
/// Get the number of usable entries in the map (all by default) /// Get the number of usable entries in the map (all by default)
fn usable_count(&self) -> usize { fn usable_count(&self) -> usize;
self.len()
}
/// Count the set bytes in the map /// Count the set bytes in the map
fn count_bytes(&self) -> u64 { fn count_bytes(&self) -> u64 {
@ -64,27 +64,16 @@ where
} }
/// Compute the hash of the map /// Compute the hash of the map
fn hash(&self) -> u64 { fn hash(&self) -> u64;
let mut hasher = AHasher::new_with_keys(0, 0);
let slice = self
.map()
.expect("Cannot hash a map that cannot be represented as slice");
let ptr = slice.as_ptr() as *const u8;
let map_size = slice.len() / core::mem::size_of::<T>();
unsafe {
hasher.write(from_raw_parts(ptr, map_size));
}
hasher.finish()
}
/// Get the initial value for reset() /// Get the initial value for reset()
fn initial(&self) -> T; fn initial(&self) -> Self::Entry;
/// Get the initial value for reset() /// Get the initial value for reset()
fn initial_mut(&mut self) -> &mut T; fn initial_mut(&mut self) -> &mut Self::Entry;
/// Set the initial value for reset() /// Set the initial value for reset()
fn set_initial(&mut self, initial: T); fn set_initial(&mut self, initial: Self::Entry);
/// Reset the map /// Reset the map
#[inline] #[inline]
@ -97,6 +86,16 @@ where
} }
Ok(()) Ok(())
} }
/// Get these observer's contents as [`Vec`]
fn to_vec(&self) -> Vec<Self::Entry> {
let cnt = self.usable_count();
let mut res = Vec::with_capacity(cnt);
for i in 0..cnt {
res.push(*self.get(i));
}
res
}
} }
/// The Map Observer retrieves the state of a map, /// The Map Observer retrieves the state of a map,
@ -117,7 +116,7 @@ where
impl<'a, I, S, T> Observer<I, S> for StdMapObserver<'a, T> impl<'a, I, S, T> Observer<I, S> for StdMapObserver<'a, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver<T>, Self: MapObserver,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
@ -145,18 +144,53 @@ where
} }
} }
impl<'a, T> MapObserver<T> for StdMapObserver<'a, T> impl<'a, 'it, T> IntoIterator for &'it StdMapObserver<'a, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{ {
type Item = <Iter<'it, T> as Iterator>::Item;
type IntoIter = Iter<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'a, 'it, T> IntoIterator for &'it mut StdMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <IterMut<'it, T> as Iterator>::Item;
type IntoIter = IterMut<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
impl<'a, T> MapObserver for StdMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Entry = T;
#[inline] #[inline]
fn map(&self) -> Option<&[T]> { fn get(&self, pos: usize) -> &T {
Some(self.map.as_slice()) &self.as_slice()[pos]
} }
#[inline] #[inline]
fn map_mut(&mut self) -> Option<&mut [T]> { fn get_mut(&mut self, idx: usize) -> &mut T {
Some(self.map.as_mut_slice()) &mut self.as_mut_slice()[idx]
}
#[inline]
fn usable_count(&self) -> usize {
self.as_slice().len()
}
fn hash(&self) -> u64 {
hash_slice(self.as_slice())
} }
#[inline] #[inline]
@ -173,6 +207,31 @@ where
fn set_initial(&mut self, initial: T) { fn set_initial(&mut self, initial: T) {
self.initial = initial; self.initial = initial;
} }
fn to_vec(&self) -> Vec<T> {
self.as_slice().to_vec()
}
}
impl<'a, T> AsSlice<T> for StdMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[must_use]
#[inline]
fn as_slice(&self) -> &[T] {
self.map.as_slice()
}
}
impl<'a, T> AsMutSlice<T> for StdMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[must_use]
#[inline]
fn as_mut_slice(&mut self) -> &mut [T] {
self.map.as_mut_slice()
}
} }
impl<'a, T> StdMapObserver<'a, T> impl<'a, T> StdMapObserver<'a, T>
@ -251,7 +310,7 @@ where
impl<'a, I, S, T, const N: usize> Observer<I, S> for ConstMapObserver<'a, T, N> impl<'a, I, S, T, const N: usize> Observer<I, S> for ConstMapObserver<'a, T, N>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver<T>, Self: MapObserver,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
@ -279,24 +338,35 @@ where
} }
} }
impl<'a, T, const N: usize> MapObserver<T> for ConstMapObserver<'a, T, N> impl<'a, 'it, T, const N: usize> IntoIterator for &'it ConstMapObserver<'a, T, N>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{ {
#[inline] type Item = <Iter<'it, T> as Iterator>::Item;
fn usable_count(&self) -> usize { type IntoIter = Iter<'it, T>;
N
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
} }
#[inline] impl<'a, 'it, T, const N: usize> IntoIterator for &'it mut ConstMapObserver<'a, T, N>
fn map(&self) -> Option<&[T]> { where
Some(self.map.as_slice()) T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <IterMut<'it, T> as Iterator>::Item;
type IntoIter = IterMut<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
} }
#[inline] impl<'a, T, const N: usize> MapObserver for ConstMapObserver<'a, T, N>
fn map_mut(&mut self) -> Option<&mut [T]> { where
Some(self.map.as_mut_slice()) T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
} {
type Entry = T;
#[inline] #[inline]
fn initial(&self) -> T { fn initial(&self) -> T {
@ -312,6 +382,47 @@ where
fn set_initial(&mut self, initial: T) { fn set_initial(&mut self, initial: T) {
self.initial = initial; self.initial = initial;
} }
#[inline]
fn get(&self, idx: usize) -> &T {
&self.as_slice()[idx]
}
#[inline]
fn get_mut(&mut self, idx: usize) -> &mut T {
&mut self.as_mut_slice()[idx]
}
fn usable_count(&self) -> usize {
self.as_slice().len()
}
fn hash(&self) -> u64 {
hash_slice(self.as_slice())
}
fn to_vec(&self) -> Vec<T> {
self.as_slice().to_vec()
}
}
impl<'a, T, const N: usize> AsSlice<T> for ConstMapObserver<'a, T, N>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn as_slice(&self) -> &[T] {
self.map.as_slice()
}
}
impl<'a, T, const N: usize> AsMutSlice<T> for ConstMapObserver<'a, T, N>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn as_mut_slice(&mut self) -> &mut [T] {
self.map.as_mut_slice()
}
} }
impl<'a, T, const N: usize> ConstMapObserver<'a, T, N> impl<'a, T, const N: usize> ConstMapObserver<'a, T, N>
@ -373,7 +484,7 @@ where
impl<'a, I, S, T> Observer<I, S> for VariableMapObserver<'a, T> impl<'a, I, S, T> Observer<I, S> for VariableMapObserver<'a, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver<T>, Self: MapObserver,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
@ -401,24 +512,35 @@ where
} }
} }
impl<'a, T> MapObserver<T> for VariableMapObserver<'a, T> impl<'a, 'it, T> IntoIterator for &'it VariableMapObserver<'a, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{ {
#[inline] type Item = <Iter<'it, T> as Iterator>::Item;
fn map(&self) -> Option<&[T]> { type IntoIter = Iter<'it, T>;
Some(self.map.as_slice())
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
} }
#[inline] impl<'a, 'it, T> IntoIterator for &'it mut VariableMapObserver<'a, T>
fn map_mut(&mut self) -> Option<&mut [T]> { where
Some(self.map.as_mut_slice()) T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <IterMut<'it, T> as Iterator>::Item;
type IntoIter = IterMut<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
} }
#[inline] impl<'a, T> MapObserver for VariableMapObserver<'a, T>
fn usable_count(&self) -> usize { where
*self.size.as_ref() T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
} {
type Entry = T;
#[inline] #[inline]
fn initial(&self) -> T { fn initial(&self) -> T {
@ -434,6 +556,45 @@ where
fn set_initial(&mut self, initial: T) { fn set_initial(&mut self, initial: T) {
self.initial = initial; self.initial = initial;
} }
#[inline]
fn usable_count(&self) -> usize {
*self.size.as_ref()
}
fn get(&self, idx: usize) -> &T {
&self.as_slice()[idx]
}
fn get_mut(&mut self, idx: usize) -> &mut T {
&mut self.as_mut_slice()[idx]
}
fn hash(&self) -> u64 {
hash_slice(self.as_slice())
}
fn to_vec(&self) -> Vec<T> {
self.as_slice().to_vec()
}
}
impl<'a, T> AsSlice<T> for VariableMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn as_slice(&self) -> &[T] {
self.map.as_slice()
}
}
impl<'a, T> AsMutSlice<T> for VariableMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn as_mut_slice(&mut self) -> &mut [T] {
self.map.as_mut_slice()
}
} }
impl<'a, T> VariableMapObserver<'a, T> impl<'a, T> VariableMapObserver<'a, T>
@ -498,7 +659,7 @@ static COUNT_CLASS_LOOKUP: [u8; 256] = [
impl<I, S, M> Observer<I, S> for HitcountsMapObserver<M> impl<I, S, M> Observer<I, S> for HitcountsMapObserver<M>
where where
M: MapObserver<u8> + Observer<I, S>, M: MapObserver<Entry = u8> + Observer<I, S>,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> { fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
@ -527,7 +688,7 @@ where
impl<M> HasLen for HitcountsMapObserver<M> impl<M> HasLen for HitcountsMapObserver<M>
where where
M: MapObserver<u8>, M: MapObserver,
{ {
#[inline] #[inline]
fn len(&self) -> usize { fn len(&self) -> usize {
@ -535,24 +696,11 @@ where
} }
} }
impl<M> MapObserver<u8> for HitcountsMapObserver<M> impl<M> MapObserver for HitcountsMapObserver<M>
where where
M: MapObserver<u8>, M: MapObserver<Entry = u8>,
{ {
#[inline] type Entry = u8;
fn map(&self) -> Option<&[u8]> {
self.base.map()
}
#[inline]
fn map_mut(&mut self) -> Option<&mut [u8]> {
self.base.map_mut()
}
#[inline]
fn usable_count(&self) -> usize {
self.base.usable_count()
}
#[inline] #[inline]
fn initial(&self) -> u8 { fn initial(&self) -> u8 {
@ -568,6 +716,47 @@ where
fn set_initial(&mut self, initial: u8) { fn set_initial(&mut self, initial: u8) {
self.base.set_initial(initial); self.base.set_initial(initial);
} }
#[inline]
fn usable_count(&self) -> usize {
self.base.usable_count()
}
#[inline]
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 hash(&self) -> u64 {
self.base.hash()
}
fn to_vec(&self) -> Vec<u8> {
self.base.to_vec()
}
}
impl<M> AsSlice<u8> for HitcountsMapObserver<M>
where
M: MapObserver + AsSlice<u8>,
{
#[inline]
fn as_slice(&self) -> &[u8] {
self.base.as_slice()
}
}
impl<M> AsMutSlice<u8> for HitcountsMapObserver<M>
where
M: MapObserver + AsMutSlice<u8>,
{
#[inline]
fn as_mut_slice(&mut self) -> &mut [u8] {
self.base.as_mut_slice()
}
} }
impl<M> HitcountsMapObserver<M> impl<M> HitcountsMapObserver<M>
@ -586,19 +775,20 @@ where
#[allow(clippy::unsafe_derive_deserialize)] #[allow(clippy::unsafe_derive_deserialize)]
pub struct MultiMapObserver<'a, T> pub struct MultiMapObserver<'a, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{ {
maps: Vec<OwnedSliceMut<'a, T>>, maps: Vec<OwnedSliceMut<'a, T>>,
intervals: IntervalTree<usize, usize>, intervals: IntervalTree<usize, usize>,
len: usize, len: usize,
initial: T, initial: T,
name: String, name: String,
iter_idx: usize,
} }
impl<'a, I, S, T> Observer<I, S> for MultiMapObserver<'a, T> impl<'a, I, S, T> Observer<I, S> for MultiMapObserver<'a, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver<T>, Self: MapObserver,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
@ -608,7 +798,7 @@ where
impl<'a, T> Named for MultiMapObserver<'a, T> impl<'a, T> Named for MultiMapObserver<'a, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{ {
#[inline] #[inline]
fn name(&self) -> &str { fn name(&self) -> &str {
@ -618,7 +808,7 @@ where
impl<'a, T> HasLen for MultiMapObserver<'a, T> impl<'a, T> HasLen for MultiMapObserver<'a, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{ {
#[inline] #[inline]
fn len(&self) -> usize { fn len(&self) -> usize {
@ -626,19 +816,11 @@ where
} }
} }
impl<'a, T> MapObserver<T> for MultiMapObserver<'a, T> impl<'a, T> MapObserver for MultiMapObserver<'a, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{ {
#[inline] type Entry = T;
fn map(&self) -> Option<&[T]> {
None
}
#[inline]
fn map_mut(&mut self) -> Option<&mut [T]> {
None
}
#[inline] #[inline]
fn get(&self, idx: usize) -> &T { fn get(&self, idx: usize) -> &T {
@ -706,11 +888,15 @@ where
} }
Ok(()) Ok(())
} }
fn usable_count(&self) -> usize {
self.len()
}
} }
impl<'a, T> MultiMapObserver<'a, T> impl<'a, T> MultiMapObserver<'a, T>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{ {
/// Creates a new [`MultiMapObserver`] /// Creates a new [`MultiMapObserver`]
#[must_use] #[must_use]
@ -739,6 +925,7 @@ where
len: idx, len: idx,
name: name.to_string(), name: name.to_string(),
initial, initial,
iter_idx: 0,
} }
} }
@ -769,6 +956,31 @@ where
len: idx, len: idx,
name: name.to_string(), name: name.to_string(),
initial, initial,
iter_idx: 0,
} }
} }
} }
impl<'a, 'it, T> IntoIterator for &'it mut MultiMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <IterMut<'it, T> as Iterator>::Item;
type IntoIter = Flatten<IterMut<'it, OwnedSliceMut<'a, T>>>;
fn into_iter(self) -> Self::IntoIter {
self.maps.iter_mut().flatten()
}
}
impl<'a, 'it, T> IntoIterator for &'it MultiMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <Iter<'it, T> as Iterator>::Item;
type IntoIter = Flatten<Iter<'it, OwnedSliceMut<'a, T>>>;
fn into_iter(self) -> Self::IntoIter {
self.maps.iter().flatten()
}
}

View File

@ -19,34 +19,33 @@ use alloc::{
vec::Vec, vec::Vec,
}; };
use core::{fmt::Debug, marker::PhantomData, time::Duration}; use core::{fmt::Debug, marker::PhantomData, time::Duration};
use num_traits::PrimInt; use num_traits::Bounded;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// The calibration stage will measure the average exec time and the target's stability for this input. /// The calibration stage will measure the average exec time and the target's stability for this input.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CalibrationStage<I, O, OT, S, T> pub struct CalibrationStage<I, O, OT, S>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
I: Input, I: Input,
O: MapObserver<T>, O: MapObserver,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus<I> + HasMetadata, S: HasCorpus<I> + HasMetadata,
{ {
map_observer_name: String, map_observer_name: String,
stage_max: usize, stage_max: usize,
phantom: PhantomData<(I, O, OT, S, T)>, phantom: PhantomData<(I, O, OT, S)>,
} }
const CAL_STAGE_START: usize = 4; const CAL_STAGE_START: usize = 4;
const CAL_STAGE_MAX: usize = 16; const CAL_STAGE_MAX: usize = 16;
impl<E, EM, I, O, OT, S, T, Z> Stage<E, EM, S, Z> for CalibrationStage<I, O, OT, S, T> impl<E, EM, I, O, OT, S, Z> Stage<E, EM, S, Z> for CalibrationStage<I, O, OT, S>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
EM: EventFirer<I>, EM: EventFirer<I>,
I: Input, I: Input,
O: MapObserver<T>, O: MapObserver,
for<'de> <O as MapObserver>::Entry: Serialize + Deserialize<'de> + 'static,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus<I> + HasMetadata + HasFeedbackStates + HasClientPerfMonitor, S: HasCorpus<I> + HasMetadata + HasFeedbackStates + HasClientPerfMonitor,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM, I, S>,
@ -94,8 +93,6 @@ where
.observers() .observers()
.match_name::<O>(&self.map_observer_name) .match_name::<O>(&self.map_observer_name)
.ok_or_else(|| Error::KeyNotFound("MapObserver not found".to_string()))? .ok_or_else(|| Error::KeyNotFound("MapObserver not found".to_string()))?
.map()
.unwrap()
.to_vec(); .to_vec();
// Run CAL_STAGE_START - 1 times, increase by 2 for every time a new // Run CAL_STAGE_START - 1 times, increase by 2 for every time a new
@ -137,19 +134,17 @@ where
.observers() .observers()
.match_name::<O>(&self.map_observer_name) .match_name::<O>(&self.map_observer_name)
.ok_or_else(|| Error::KeyNotFound("MapObserver not found".to_string()))? .ok_or_else(|| Error::KeyNotFound("MapObserver not found".to_string()))?
.map()
.unwrap()
.to_vec(); .to_vec();
let history_map = &mut state let history_map = &mut state
.feedback_states_mut() .feedback_states_mut()
.match_name_mut::<MapFeedbackState<T>>(&self.map_observer_name) .match_name_mut::<MapFeedbackState<O::Entry>>(&self.map_observer_name)
.unwrap() .unwrap()
.history_map; .history_map;
for j in 0..map_len { for j in 0..map_len {
if map_first[j] != map[j] && history_map[j] != T::max_value() { if map_first[j] != map[j] && history_map[j] != O::Entry::max_value() {
history_map[j] = T::max_value(); history_map[j] = O::Entry::max_value();
unstable_entries += 1; unstable_entries += 1;
}; };
} }
@ -306,11 +301,10 @@ impl PowerScheduleMetadata {
crate::impl_serdeany!(PowerScheduleMetadata); crate::impl_serdeany!(PowerScheduleMetadata);
impl<I, O, OT, S, T> CalibrationStage<I, O, OT, S, T> impl<I, O, OT, S> CalibrationStage<I, O, OT, S>
where where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
I: Input, I: Input,
O: MapObserver<T>, O: MapObserver,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus<I> + HasMetadata, S: HasCorpus<I> + HasMetadata,
{ {

View File

@ -2,7 +2,6 @@
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use core::{fmt::Debug, marker::PhantomData}; use core::{fmt::Debug, marker::PhantomData};
use num_traits::PrimInt;
use crate::{ use crate::{
corpus::{Corpus, IsFavoredMetadata, PowerScheduleTestcaseMetaData, Testcase}, corpus::{Corpus, IsFavoredMetadata, PowerScheduleTestcaseMetaData, Testcase},
@ -34,13 +33,12 @@ const HAVOC_MAX_MULT: f64 = 64.0;
/// The mutational stage using power schedules /// The mutational stage using power schedules
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PowerMutationalStage<E, EM, I, M, O, OT, S, T, Z> pub struct PowerMutationalStage<E, EM, I, M, O, OT, S, Z>
where where
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned + Debug,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
I: Input, I: Input,
M: Mutator<I, S>, M: Mutator<I, S>,
O: MapObserver<T>, O: MapObserver,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata, S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM, I, S>,
@ -50,17 +48,16 @@ where
/// The employed power schedule strategy /// The employed power schedule strategy
strat: PowerSchedule, strat: PowerSchedule,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, I, O, OT, S, T, Z)>, phantom: PhantomData<(E, EM, I, O, OT, S, Z)>,
} }
impl<E, EM, I, M, O, OT, S, T, Z> MutationalStage<E, EM, I, M, S, Z> impl<E, EM, I, M, O, OT, S, Z> MutationalStage<E, EM, I, M, S, Z>
for PowerMutationalStage<E, EM, I, M, O, OT, S, T, Z> for PowerMutationalStage<E, EM, I, M, O, OT, S, Z>
where where
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned + Debug,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
I: Input, I: Input,
M: Mutator<I, S>, M: Mutator<I, S>,
O: MapObserver<T>, O: MapObserver,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata, S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM, I, S>,
@ -153,14 +150,12 @@ where
} }
} }
impl<E, EM, I, M, O, OT, S, T, Z> Stage<E, EM, S, Z> impl<E, EM, I, M, O, OT, S, Z> Stage<E, EM, S, Z> for PowerMutationalStage<E, EM, I, M, O, OT, S, Z>
for PowerMutationalStage<E, EM, I, M, O, OT, S, T, Z>
where where
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned + Debug,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
I: Input, I: Input,
M: Mutator<I, S>, M: Mutator<I, S>,
O: MapObserver<T>, O: MapObserver,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata, S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM, I, S>,
@ -180,13 +175,12 @@ where
} }
} }
impl<E, EM, I, M, O, OT, S, T, Z> PowerMutationalStage<E, EM, I, M, O, OT, S, T, Z> impl<E, EM, I, M, O, OT, S, Z> PowerMutationalStage<E, EM, I, M, O, OT, S, Z>
where where
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned + Debug,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
I: Input, I: Input,
M: Mutator<I, S>, M: Mutator<I, S>,
O: MapObserver<T>, O: MapObserver,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata, S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM, I, S>,

View File

@ -13,7 +13,10 @@ use std::{
}; };
use libafl::{ use libafl::{
bolts::shmem::{ShMem, ShMemProvider, StdShMemProvider}, bolts::{
shmem::{ShMem, ShMemProvider, StdShMemProvider},
AsSlice,
},
observers::concolic::{ observers::concolic::{
serialization_format::{MessageFileReader, MessageFileWriter, DEFAULT_ENV_NAME}, serialization_format::{MessageFileReader, MessageFileWriter, DEFAULT_ENV_NAME},
EXPRESSION_PRUNING, HITMAP_ENV_NAME, NO_FLOAT_ENV_NAME, SELECTIVE_SYMBOLICATION_ENV_NAME, EXPRESSION_PRUNING, HITMAP_ENV_NAME, NO_FLOAT_ENV_NAME, SELECTIVE_SYMBOLICATION_ENV_NAME,

View File

@ -1,6 +1,7 @@
//! Generates `DrCov` traces //! Generates `DrCov` traces
use ahash::AHasher; use ahash::AHasher;
use libafl::{ use libafl::{
bolts::AsSlice,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
Error, Error,
}; };

View File

@ -1,6 +1,8 @@
use libafl::inputs::{HasTargetBytes, Input}; use libafl::{
use libafl::Error; bolts::AsSlice,
inputs::{HasTargetBytes, Input},
Error,
};
#[cfg(unix)] #[cfg(unix)]
use libafl_targets::drcov::DrCovBasicBlock; use libafl_targets::drcov::DrCovBasicBlock;

View File

@ -11,6 +11,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMem, ShMemProvider, StdShMemProvider}, shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsMutSlice,
}, },
corpus::{ corpus::{
CachedOnDiskCorpus, Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, CachedOnDiskCorpus, Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -13,6 +13,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice,
}, },
corpus::{ corpus::{
CachedOnDiskCorpus, Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, CachedOnDiskCorpus, Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -12,6 +12,7 @@ use libafl::{
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
AsSlice,
}, },
corpus::{ corpus::{
CachedOnDiskCorpus, Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, CachedOnDiskCorpus, Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -187,11 +187,11 @@ where
} }
} }
fn map(&self) -> &CmpLogMap { fn cmp_map(&self) -> &CmpLogMap {
self.map.as_ref() self.map.as_ref()
} }
fn map_mut(&mut self) -> &mut CmpLogMap { fn cmp_map_mut(&mut self) -> &mut CmpLogMap {
self.map.as_mut() self.map.as_mut()
} }
} }