added time observer

This commit is contained in:
Dominik Maier 2021-01-06 04:30:07 +01:00
parent 95fff9d740
commit db5183d43f
7 changed files with 120 additions and 46 deletions

View File

@ -220,7 +220,7 @@ where
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple, OT: ObserversTuple,
{ {
executor.reset_observers()?; executor.pre_exec_observers()?;
executor.run_target(&input)?; executor.run_target(&input)?;
self.set_executions(self.executions() + 1); self.set_executions(self.executions() + 1);
executor.post_exec_observers()?; executor.post_exec_observers()?;

View File

@ -31,8 +31,8 @@ where
/// Reset the state of all the observes linked to this executor /// Reset the state of all the observes linked to this executor
#[inline] #[inline]
fn reset_observers(&mut self) -> Result<(), AflError> { fn pre_exec_observers(&mut self) -> Result<(), AflError> {
self.observers_mut().reset_all() self.observers_mut().pre_exec_all()
} }
/// Run the post exec hook for all the observes linked to this executor /// Run the post exec hook for all the observes linked to this executor

View File

@ -309,6 +309,8 @@ where
} }
} }
// TODO: TimeFeedback
/* /*
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct MapNoveltiesMetadata { pub struct MapNoveltiesMetadata {

View File

@ -6,35 +6,6 @@ use crate::{
AflError, AflError,
}; };
/// The result of a mutation.
/// If the mutation got skipped, the target
/// will not be executed with the returned input.
pub enum MutationResult {
Mutated,
Skipped,
}
// TODO maybe the mutator arg is not needed
/// The generic function type that identifies mutations
pub type MutationFunction<M, C, I, R> =
fn(&mut M, &mut R, &C, &mut I) -> Result<MutationResult, AflError>;
pub trait ComposedByMutations<C, I, R>
where
C: Corpus<I, R>,
I: Input,
R: Rand,
{
/// Get a mutation by index
fn mutation_by_idx(&self, index: usize) -> MutationFunction<Self, C, I, R>;
/// Get the number of mutations
fn mutations_count(&self) -> usize;
/// Add a mutation
fn add_mutation(&mut self, mutation: MutationFunction<Self, C, I, R>);
}
const ARITH_MAX: u64 = 35; const ARITH_MAX: u64 = 35;
const INTERESTING_8: [i8; 9] = [-128, -1, 0, 1, 16, 32, 64, 100, 127]; const INTERESTING_8: [i8; 9] = [-128, -1, 0, 1, 16, 32, 64, 100, 127];
@ -71,6 +42,36 @@ const INTERESTING_32: [i32; 27] = [
2147483647, 2147483647,
]; ];
/// The result of a mutation.
/// If the mutation got skipped, the target
/// will not be executed with the returned input.
#[derive(Clone, Copy, Debug)]
pub enum MutationResult {
Mutated,
Skipped,
}
// TODO maybe the mutator arg is not needed
/// The generic function type that identifies mutations
pub type MutationFunction<M, C, I, R> =
fn(&mut M, &mut R, &C, &mut I) -> Result<MutationResult, AflError>;
pub trait ComposedByMutations<C, I, R>
where
C: Corpus<I, R>,
I: Input,
R: Rand,
{
/// Get a mutation by index
fn mutation_by_idx(&self, index: usize) -> MutationFunction<Self, C, I, R>;
/// Get the number of mutations
fn mutations_count(&self) -> usize;
/// Add a mutation
fn add_mutation(&mut self, mutation: MutationFunction<Self, C, I, R>);
}
#[inline] #[inline]
fn self_mem_move(data: &mut [u8], from: usize, to: usize, len: usize) { fn self_mem_move(data: &mut [u8], from: usize, to: usize, len: usize) {
debug_assert!(from + len <= data.len()); debug_assert!(from + len <= data.len());

View File

@ -1,5 +1,6 @@
use alloc::vec::Vec; use alloc::vec::Vec;
use core::marker::PhantomData; use core::{fmt, marker::PhantomData};
use fmt::Debug;
use crate::{ use crate::{
inputs::{HasBytesVec, Input}, inputs::{HasBytesVec, Input},
@ -56,6 +57,23 @@ where
max_size: usize, max_size: usize,
} }
impl<C, I, R> Debug for StdScheduledMutator<C, I, R>
where
C: Corpus<I, R>,
I: Input,
R: Rand,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"StdScheduledMutator with {} Mutations, max_size: {}, for Input type {}",
self.mutations.len(),
self.max_size,
core::any::type_name::<I>()
)
}
}
impl<C, I, R> Mutator<C, I, R> for StdScheduledMutator<C, I, R> impl<C, I, R> Mutator<C, I, R> for StdScheduledMutator<C, I, R>
where where
C: Corpus<I, R>, C: Corpus<I, R>,

View File

@ -4,11 +4,13 @@ use alloc::{
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
}; };
use core::time::Duration;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
serde_anymap::{ArrayMut, Cptr}, serde_anymap::{ArrayMut, Cptr},
tuples::{MatchNameAndType, MatchType, Named, TupleList}, tuples::{MatchNameAndType, MatchType, Named, TupleList},
utils::current_time,
AflError, AflError,
}; };
@ -22,7 +24,7 @@ pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'st
} }
/// Resets the observer /// Resets the observer
fn reset(&mut self) -> Result<(), AflError>; fn pre_exec(&mut self) -> Result<(), AflError>;
/// This function is executed after each fuzz run /// This function is executed after each fuzz run
#[inline] #[inline]
@ -48,11 +50,15 @@ pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'st
} }
} }
/// A hastkel-style tuple of observers
pub trait ObserversTuple: pub trait ObserversTuple:
MatchNameAndType + MatchType + serde::Serialize + serde::de::DeserializeOwned MatchNameAndType + MatchType + serde::Serialize + serde::de::DeserializeOwned
{ {
/// Reset all executors in the tuple /// Reset all executors in the tuple
fn reset_all(&mut self) -> Result<(), AflError>; /// This is called right before the next execution.
fn pre_exec_all(&mut self) -> Result<(), AflError>;
/// Do whatever you need to do after a run.
/// This is called right after the last execution
fn post_exec_all(&mut self) -> Result<(), AflError>; fn post_exec_all(&mut self) -> Result<(), AflError>;
//fn for_each(&self, f: fn(&dyn Observer)); //fn for_each(&self, f: fn(&dyn Observer));
//fn for_each_mut(&mut self, f: fn(&mut dyn Observer)); //fn for_each_mut(&mut self, f: fn(&mut dyn Observer));
@ -69,7 +75,7 @@ pub trait ObserversTuple:
} }
impl ObserversTuple for () { impl ObserversTuple for () {
fn reset_all(&mut self) -> Result<(), AflError> { fn pre_exec_all(&mut self) -> Result<(), AflError> {
Ok(()) Ok(())
} }
fn post_exec_all(&mut self) -> Result<(), AflError> { fn post_exec_all(&mut self) -> Result<(), AflError> {
@ -85,9 +91,9 @@ where
Head: Observer, Head: Observer,
Tail: ObserversTuple + TupleList, Tail: ObserversTuple + TupleList,
{ {
fn reset_all(&mut self) -> Result<(), AflError> { fn pre_exec_all(&mut self) -> Result<(), AflError> {
self.0.reset()?; self.0.pre_exec()?;
self.1.reset_all() self.1.pre_exec_all()
} }
fn post_exec_all(&mut self) -> Result<(), AflError> { fn post_exec_all(&mut self) -> Result<(), AflError> {
@ -106,6 +112,44 @@ where
}*/ }*/
} }
/// A simple observer, just overlooking the runtime of the target.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TimeObserver {
name: String,
start_time: Duration,
last_runtime: Option<Duration>,
}
impl TimeObserver {
/// Creates a new TimeObserver with the given name.
pub fn new(name: &'static str) -> Self {
Self {
name: name.to_string(),
start_time: Duration::from_secs(0),
last_runtime: None,
}
}
}
impl Observer for TimeObserver {
fn pre_exec(&mut self) -> Result<(), AflError> {
self.last_runtime = None;
self.start_time = current_time();
Ok(())
}
fn post_exec(&mut self) -> Result<(), AflError> {
self.last_runtime = Some(current_time() - self.start_time);
Ok(())
}
}
impl Named for TimeObserver {
fn name(&self) -> &str {
&self.name
}
}
/// A MapObserver observes the static map, as oftentimes used for afl-like coverage information /// A MapObserver observes the static map, as oftentimes used for afl-like coverage information
pub trait MapObserver<T>: Observer pub trait MapObserver<T>: Observer
where where
@ -163,7 +207,7 @@ where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{ {
#[inline] #[inline]
fn reset(&mut self) -> Result<(), AflError> { fn pre_exec(&mut self) -> Result<(), AflError> {
self.reset_map() self.reset_map()
} }
} }
@ -235,6 +279,7 @@ where
} }
} }
/// Overlooking a variable bitmap
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")] #[serde(bound = "T: serde::de::DeserializeOwned")]
pub struct VariableMapObserver<T> pub struct VariableMapObserver<T>
@ -252,7 +297,7 @@ where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{ {
#[inline] #[inline]
fn reset(&mut self) -> Result<(), AflError> { fn pre_exec(&mut self) -> Result<(), AflError> {
self.reset_map() self.reset_map()
} }
} }
@ -340,17 +385,23 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::observers::StdMapObserver; use crate::{
use crate::tuples::Named; observers::{StdMapObserver, TimeObserver},
tuples::{tuple_list, tuple_list_type, Named},
};
static mut MAP: [u32; 4] = [0; 4]; static mut MAP: [u32; 4] = [0; 4];
#[test] #[test]
fn test_observer_serde() { fn test_observer_serde() {
let obv = StdMapObserver::new("test", unsafe { &mut MAP }); let obv = tuple_list!(
TimeObserver::new("time"),
StdMapObserver::new("map", unsafe { &mut MAP })
);
let vec = postcard::to_allocvec(&obv).unwrap(); let vec = postcard::to_allocvec(&obv).unwrap();
println!("{:?}", vec); println!("{:?}", vec);
let obv2: StdMapObserver<u32> = postcard::from_bytes(&vec).unwrap(); let obv2: tuple_list_type!(TimeObserver, StdMapObserver<u32>) =
assert_eq!(obv.name(), obv2.name()); postcard::from_bytes(&vec).unwrap();
assert_eq!(obv.0.name(), obv2.0.name());
} }
} }

View File

@ -91,7 +91,9 @@ where
} }
} }
/// We need fixed names for many parts of this lib.
pub trait Named { pub trait Named {
/// Provide the name of this element.
fn name(&self) -> &str; fn name(&self) -> &str;
} }