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>,
OT: ObserversTuple,
{
executor.reset_observers()?;
executor.pre_exec_observers()?;
executor.run_target(&input)?;
self.set_executions(self.executions() + 1);
executor.post_exec_observers()?;

View File

@ -31,8 +31,8 @@ where
/// Reset the state of all the observes linked to this executor
#[inline]
fn reset_observers(&mut self) -> Result<(), AflError> {
self.observers_mut().reset_all()
fn pre_exec_observers(&mut self) -> Result<(), AflError> {
self.observers_mut().pre_exec_all()
}
/// 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)]
pub struct MapNoveltiesMetadata {

View File

@ -6,35 +6,6 @@ use crate::{
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 INTERESTING_8: [i8; 9] = [-128, -1, 0, 1, 16, 32, 64, 100, 127];
@ -71,6 +42,36 @@ const INTERESTING_32: [i32; 27] = [
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]
fn self_mem_move(data: &mut [u8], from: usize, to: usize, len: usize) {
debug_assert!(from + len <= data.len());

View File

@ -1,5 +1,6 @@
use alloc::vec::Vec;
use core::marker::PhantomData;
use core::{fmt, marker::PhantomData};
use fmt::Debug;
use crate::{
inputs::{HasBytesVec, Input},
@ -56,6 +57,23 @@ where
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>
where
C: Corpus<I, R>,

View File

@ -4,11 +4,13 @@ use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::time::Duration;
use serde::{Deserialize, Serialize};
use crate::{
serde_anymap::{ArrayMut, Cptr},
tuples::{MatchNameAndType, MatchType, Named, TupleList},
utils::current_time,
AflError,
};
@ -22,7 +24,7 @@ pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'st
}
/// Resets the observer
fn reset(&mut self) -> Result<(), AflError>;
fn pre_exec(&mut self) -> Result<(), AflError>;
/// This function is executed after each fuzz run
#[inline]
@ -48,11 +50,15 @@ pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'st
}
}
/// A hastkel-style tuple of observers
pub trait ObserversTuple:
MatchNameAndType + MatchType + serde::Serialize + serde::de::DeserializeOwned
{
/// 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 for_each(&self, f: fn(&dyn Observer));
//fn for_each_mut(&mut self, f: fn(&mut dyn Observer));
@ -69,7 +75,7 @@ pub trait ObserversTuple:
}
impl ObserversTuple for () {
fn reset_all(&mut self) -> Result<(), AflError> {
fn pre_exec_all(&mut self) -> Result<(), AflError> {
Ok(())
}
fn post_exec_all(&mut self) -> Result<(), AflError> {
@ -85,9 +91,9 @@ where
Head: Observer,
Tail: ObserversTuple + TupleList,
{
fn reset_all(&mut self) -> Result<(), AflError> {
self.0.reset()?;
self.1.reset_all()
fn pre_exec_all(&mut self) -> Result<(), AflError> {
self.0.pre_exec()?;
self.1.pre_exec_all()
}
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
pub trait MapObserver<T>: Observer
where
@ -163,7 +207,7 @@ where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{
#[inline]
fn reset(&mut self) -> Result<(), AflError> {
fn pre_exec(&mut self) -> Result<(), AflError> {
self.reset_map()
}
}
@ -235,6 +279,7 @@ where
}
}
/// Overlooking a variable bitmap
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")]
pub struct VariableMapObserver<T>
@ -252,7 +297,7 @@ where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{
#[inline]
fn reset(&mut self) -> Result<(), AflError> {
fn pre_exec(&mut self) -> Result<(), AflError> {
self.reset_map()
}
}
@ -340,17 +385,23 @@ where
#[cfg(test)]
mod tests {
use crate::observers::StdMapObserver;
use crate::tuples::Named;
use crate::{
observers::{StdMapObserver, TimeObserver},
tuples::{tuple_list, tuple_list_type, Named},
};
static mut MAP: [u32; 4] = [0; 4];
#[test]
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();
println!("{:?}", vec);
let obv2: StdMapObserver<u32> = postcard::from_bytes(&vec).unwrap();
assert_eq!(obv.name(), obv2.name());
let obv2: tuple_list_type!(TimeObserver, StdMapObserver<u32>) =
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 {
/// Provide the name of this element.
fn name(&self) -> &str;
}