cmp observer and feedback
This commit is contained in:
parent
f81a52e14d
commit
8437c4adb7
@ -21,7 +21,6 @@ where
|
|||||||
{
|
{
|
||||||
primary: A,
|
primary: A,
|
||||||
secondary: B,
|
secondary: B,
|
||||||
exec_tmout: Duration,
|
|
||||||
phantom: PhantomData<I>,
|
phantom: PhantomData<I>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +79,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, EM, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z> for TimeoutExecutor<A, B, I>
|
impl<A, B, EM, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z> for CombinedExecutor<A, B, I>
|
||||||
where
|
where
|
||||||
A: Executor<I> + HasObservers<OT>,
|
A: Executor<I> + HasObservers<OT>,
|
||||||
B: Executor<I>,
|
B: Executor<I>,
|
||||||
@ -89,9 +88,9 @@ where
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for TimeoutExecutor<A, B, I>
|
impl<A, B, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for CombinedExecutor<A, B, I>
|
||||||
where
|
where
|
||||||
A: Executor<I> + HasObservers<OT>,
|
A: Executor<I> + HasExecHooks<EM, I, S, Z>,
|
||||||
B: Executor<I>,
|
B: Executor<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
use alloc::{
|
use alloc::string::{String, ToString};
|
||||||
string::{String, ToString},
|
|
||||||
};
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use num::Integer;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::tuples::Named,
|
bolts::{tuples::Named, AsSlice},
|
||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
feedbacks::{Feedback, FeedbackState, FeedbackStatesTuple},
|
feedbacks::Feedback,
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
observers::{CmpObserver, ObserversTuple},
|
observers::{CmpMap, CmpObserver, CmpValues, ObserversTuple},
|
||||||
state::{HasFeedbackStates, HasMetadata},
|
state::HasMetadata,
|
||||||
utils::AsSlice,
|
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -20,15 +16,15 @@ use crate::{
|
|||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct CmpValuesMetadata {
|
pub struct CmpValuesMetadata {
|
||||||
/// A `list` of values.
|
/// A `list` of values.
|
||||||
pub list: Vec<(u64, u64)>,
|
pub list: Vec<CmpValues>,
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::impl_serdeany!(CmpValuesMetadata);
|
crate::impl_serdeany!(CmpValuesMetadata);
|
||||||
|
|
||||||
impl AsSlice<(u64, u64)> for CmpValuesMetadata {
|
impl AsSlice<CmpValues> for CmpValuesMetadata {
|
||||||
/// Convert to a slice
|
/// Convert to a slice
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn as_slice(&self) -> &[(u64, u64)] {
|
fn as_slice(&self) -> &[CmpValues] {
|
||||||
self.list.as_slice()
|
self.list.as_slice()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,24 +32,31 @@ impl AsSlice<(u64, u64)> for CmpValuesMetadata {
|
|||||||
impl CmpValuesMetadata {
|
impl CmpValuesMetadata {
|
||||||
/// Creates a new [`struct@CmpValuesMetadata`]
|
/// Creates a new [`struct@CmpValuesMetadata`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(list: Vec<(u64, u64)>) -> Self {
|
pub fn new() -> Self {
|
||||||
Self { list }
|
Self { list: vec![] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct CmpFeedback<T> {
|
pub struct CmpFeedback<CM, CO>
|
||||||
|
where
|
||||||
|
CO: CmpObserver<CM>,
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
name: String,
|
name: String,
|
||||||
phantom: PhantomData<T>
|
phantom: PhantomData<(CM, CO)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, S, T> Feedback<I, S> for CmpFeedback<T>
|
impl<CM, CO, I, S> Feedback<I, S> for CmpFeedback<CM, CO>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
CO: CmpObserver<CM>,
|
||||||
|
CM: CmpMap,
|
||||||
|
S: HasMetadata,
|
||||||
{
|
{
|
||||||
fn is_interesting<OT>(
|
fn is_interesting<OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_state: &mut S,
|
state: &mut S,
|
||||||
_input: &I,
|
_input: &I,
|
||||||
observers: &OT,
|
observers: &OT,
|
||||||
_exit_kind: &ExitKind,
|
_exit_kind: &ExitKind,
|
||||||
@ -61,36 +64,59 @@ where
|
|||||||
where
|
where
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
|
if state.metadata().get::<CmpValuesMetadata>().is_none() {
|
||||||
|
state.add_metadata(CmpValuesMetadata::new());
|
||||||
|
}
|
||||||
|
let meta = state.metadata_mut().get_mut::<CmpValuesMetadata>().unwrap();
|
||||||
|
meta.list.clear();
|
||||||
// TODO Replace with match_name_type when stable
|
// TODO Replace with match_name_type when stable
|
||||||
let observer = observers.match_name::<CmpObserver<T>>(self.name()).unwrap();
|
let observer = observers.match_name::<CO>(self.name()).unwrap();
|
||||||
|
let count = observer.usable_count();
|
||||||
|
for i in 0..count {
|
||||||
|
let execs = observer.map().usable_executions_for(i);
|
||||||
|
if execs > 0 {
|
||||||
|
// Recongize loops and discard
|
||||||
// TODO
|
// TODO
|
||||||
|
for j in 0..execs {
|
||||||
|
meta.list.push(observer.map().values_of(i, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Named for CmpFeedback {
|
impl<CM, CO> Named for CmpFeedback<CM, CO>
|
||||||
|
where
|
||||||
|
CO: CmpObserver<CM>,
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
self.name.as_str()
|
self.name.as_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CmpFeedback {
|
impl<CM, CO> CmpFeedback<CM, CO>
|
||||||
|
where
|
||||||
|
CO: CmpObserver<CM>,
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
/// Creates a new [`CmpFeedback`]
|
/// Creates a new [`CmpFeedback`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(name: &'static str) -> Self {
|
pub fn with_name(name: &'static str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
phantom: PhantomData
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new [`CmpFeedback`]
|
/// Creates a new [`CmpFeedback`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_with_observer(observer: &CmpObserver<T>) -> Self {
|
pub fn new(observer: &CO) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: observer.name().to_string(),
|
name: observer.name().to_string(),
|
||||||
phantom: PhantomData
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
pub mod map;
|
pub mod map;
|
||||||
pub use map::*;
|
pub use map::*;
|
||||||
|
|
||||||
|
pub mod cmp;
|
||||||
|
pub use cmp::*;
|
||||||
|
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -5,34 +5,125 @@ use alloc::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
use core::slice::from_raw_parts_mut;
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{
|
bolts::{ownedref::OwnedRefMut, tuples::Named},
|
||||||
ownedref::{OwnedRefMut, OwnedSliceMut},
|
|
||||||
tuples::Named,
|
|
||||||
},
|
|
||||||
executors::HasExecHooks,
|
executors::HasExecHooks,
|
||||||
observers::Observer,
|
observers::Observer,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A [`CmpObserver`] observes the traced comparisons during the current execution
|
#[derive(Serialize, Deserialize)]
|
||||||
pub trait CmpObserver<T>: Observer {
|
pub enum CmpValues {
|
||||||
/// Get the number of usable cmps (all by default)
|
U8((u8, u8)),
|
||||||
fn usable_count(&self) -> usize;
|
U16((u16, u16)),
|
||||||
|
U32((u32, u32)),
|
||||||
|
U64((u64, u64)),
|
||||||
|
Bytes((Vec<u8>, Vec<u8>)),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [`CmpMap`] traces comparisons during the current execution
|
||||||
|
pub trait CmpMap: Serialize + DeserializeOwned {
|
||||||
/// Get the number of cmps
|
/// Get the number of cmps
|
||||||
fn len(&self) -> usize;
|
fn len(&self) -> usize;
|
||||||
|
|
||||||
fn executions_for(idx: usize) -> usize;
|
fn executions_for(&self, idx: usize) -> usize;
|
||||||
|
|
||||||
fn bytes_for(idx: usize) -> usize;
|
fn usable_executions_for(&self, idx: usize) -> usize;
|
||||||
|
|
||||||
fn values_of(idx: usize, execution: usize) -> (T, T);
|
fn values_of(&self, idx: usize, execution: usize) -> CmpValues;
|
||||||
|
|
||||||
/// Reset the state
|
/// Reset the state
|
||||||
fn reset(&mut self) -> Result<(), Error>;
|
fn reset(&mut self) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A [`CmpObserver`] observes the traced comparisons during the current execution using a [`CmpMap`]
|
||||||
|
pub trait CmpObserver<CM>: Observer
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
/// Get the number of usable cmps (all by default)
|
||||||
|
fn usable_count(&self) -> usize;
|
||||||
|
|
||||||
|
fn map(&self) -> &CM;
|
||||||
|
|
||||||
|
fn map_mut(&mut self) -> &mut CM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A standard [`CmpObserver`] observer
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(bound = "CM: serde::de::DeserializeOwned")]
|
||||||
|
pub struct StdCmpObserver<'a, CM>
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
map: OwnedRefMut<'a, CM>,
|
||||||
|
size: Option<OwnedRefMut<'a, usize>>,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, CM> CmpObserver<CM> for StdCmpObserver<'a, CM>
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
/// Get the number of usable cmps (all by default)
|
||||||
|
fn usable_count(&self) -> usize {
|
||||||
|
match &self.size {
|
||||||
|
None => self.map().len(),
|
||||||
|
Some(o) => *o.as_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map(&self) -> &CM {
|
||||||
|
self.map.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_mut(&mut self) -> &mut CM {
|
||||||
|
self.map.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, CM> Observer for StdCmpObserver<'a, CM> where CM: CmpMap {}
|
||||||
|
|
||||||
|
impl<'a, CM, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for StdCmpObserver<'a, CM>
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
fn pre_exec(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut S,
|
||||||
|
_mgr: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.map.as_mut().reset()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, CM> Named for StdCmpObserver<'a, CM>
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, CM> StdCmpObserver<'a, CM>
|
||||||
|
where
|
||||||
|
CM: CmpMap,
|
||||||
|
{
|
||||||
|
/// Creates a new [`CmpObserver`] with the given name.
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(name: &'static str, map: &'a mut CM) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
size: None,
|
||||||
|
map: OwnedRefMut::Ref(map),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO with_size
|
||||||
|
}
|
||||||
|
@ -25,4 +25,4 @@ cc = { version = "1.0", features = ["parallel"] }
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rangemap = "0.1.10"
|
rangemap = "0.1.10"
|
||||||
libafl = { path = "../libafl", version = "0.2.1", features = [] }
|
libafl = { path = "../libafl", version = "0.3", features = [] }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user