fuzzer arg missing atm

This commit is contained in:
Andrea Fioraldi 2021-02-19 15:46:39 +01:00
parent 95281dbfef
commit a939f052d3
13 changed files with 530 additions and 585 deletions

View File

@ -5,6 +5,7 @@ pub use testcase::Testcase;
use alloc::{vec::Vec}; use alloc::{vec::Vec};
use core::{cell::RefCell}; use core::{cell::RefCell};
use serde::{Serialize, Deserialize};
use crate::{ use crate::{
inputs::Input, inputs::Input,
@ -101,6 +102,8 @@ impl CorpusScheduler for RandCorpusScheduler {
} }
} }
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct InMemoryCorpus<I> pub struct InMemoryCorpus<I>
where where
I: Input, I: Input,
@ -108,7 +111,7 @@ where
entries: Vec<RefCell<Testcase<I>>>, entries: Vec<RefCell<Testcase<I>>>,
} }
impl<I, SC> Corpus<I> for InMemoryCorpus<I> impl<I> Corpus<I> for InMemoryCorpus<I>
where where
I: Input, I: Input,
{ {
@ -151,54 +154,4 @@ where
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error> { fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error> {
Ok(&self.entries[idx]) Ok(&self.entries[idx])
} }
/*/// Add an entry to the corpus and return its index
#[inline]
fn add<R, S>(state: &mut S, testcase: Testcase<I>) -> Result<usize, Error>
where
S: HasCorpus<Self, I> + HasRand<R>,
R: Rand
{
state.corpus_mut().entries.push(RefCell::new(testcase));
let idx = state.corpus().entries.len() - 1;
// Scheduler hook
SC::on_add(state, idx, state.corpus().entries[idx].borrow())?;
Ok(idx)
}
/// Replaces the testcase at the given idx
#[inline]
fn replace<R, S>(state: &mut S, idx: usize, testcase: Testcase<I>) -> Result<(), Error>
where
S: HasCorpus<Self, I> + HasRand<R>,
R: Rand
{
if state.corpus().entries.len() < idx {
return Err(Error::KeyNotFound(format!("Index {} out of bounds", idx)));
}
state.corpus_mut().entries[idx] = RefCell::new(testcase);
// Scheduler hook
SC::on_replace(state, idx, state.corpus().entries[idx])?;
Ok(())
}
/// Removes an entry from the corpus, returning it if it was present.
#[inline]
fn remove<R, S>(state: &mut S, idx: usize) -> Result<Option<Testcase<I>>, Error>
where
S: HasCorpus<Self, I> + HasRand<R>,
R: Rand
{
let testcase = match state.corpus_mut()
.entries
.iter()
.position(|x| ptr::eq(x.as_ptr(), entry))
{
Some(i) => Some(state.corpus_mut().entries.remove(i).into_inner()),
None => None,
};
// Scheduler hook
SC::on_remove(state, idx, &testcase)?;
Ok(testcase)
}*/
} }

View File

@ -159,6 +159,18 @@ where
} }
} }
/// Create a new Testcase instace given an input and a fitness
#[inline]
pub fn with_fitness(input: I, fitness: u32) -> Self {
Testcase {
input: Some(input.into()),
filename: None,
fitness: fitness,
metadatas: SerdeAnyMap::new(),
exec_time: None,
}
}
#[inline] #[inline]
pub fn default() -> Self { pub fn default() -> Self {
Testcase { Testcase {

View File

@ -1,6 +1,7 @@
use crate::bolts::llmp::LlmpSender; use crate::bolts::llmp::LlmpSender;
use alloc::{string::ToString, vec::Vec}; use alloc::{string::ToString, vec::Vec};
use core::{marker::PhantomData, time::Duration}; use core::{marker::PhantomData, time::Duration};
use serde::{Serialize, de::DeserializeOwned};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::bolts::llmp::LlmpReceiver; use crate::bolts::llmp::LlmpReceiver;
@ -16,16 +17,13 @@ use crate::{
llmp::{self, LlmpClient, LlmpClientDescription, Tag}, llmp::{self, LlmpClient, LlmpClientDescription, Tag},
shmem::ShMem, shmem::ShMem,
}, },
corpus::Corpus,
events::{BrokerEventResult, Event, EventManager}, events::{BrokerEventResult, Event, EventManager},
executors::ExitKind, executors::ExitKind,
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
feedbacks::FeedbacksTuple,
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
state::State, state::{IfInteresting},
stats::Stats, stats::Stats,
utils::Rand,
Error, Error,
}; };
@ -250,21 +248,17 @@ where
} }
// Handle arriving events in the client // Handle arriving events in the client
fn handle_in_client<C, E, FT, OC, OFT, OT, R>( fn handle_in_client<E, OT, S>(
&mut self, &mut self,
state: &mut State<C, FT, I, OC, OFT, R>, state: &mut S,
sender_id: u32, sender_id: u32,
event: Event<I>, event: Event<I>,
_executor: &mut E, _executor: &mut E,
) -> Result<(), Error> ) -> Result<(), Error>
where where
C: Corpus<I, R>,
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple, OT: ObserversTuple,
S: IfInteresting<I>
{ {
match event { match event {
Event::NewTestcase { Event::NewTestcase {
@ -284,7 +278,7 @@ where
// TODO include ExitKind in NewTestcase // TODO include ExitKind in NewTestcase
let fitness = state.is_interesting(&input, &observers, ExitKind::Ok)?; let fitness = state.is_interesting(&input, &observers, ExitKind::Ok)?;
if fitness > 0 { if fitness > 0 {
if !state.add_if_interesting(input, fitness)?.is_none() { if !state.add_if_interesting(&input, fitness)?.is_none() {
#[cfg(feature = "std")] #[cfg(feature = "std")]
println!("Added received Testcase"); println!("Added received Testcase");
} }
@ -317,19 +311,15 @@ where
} }
} }
fn process<C, E, FT, OC, OFT, OT, R>( fn process<E, OT, S>(
&mut self, &mut self,
state: &mut State<C, FT, I, OC, OFT, R>, state: &mut S,
executor: &mut E, executor: &mut E,
) -> Result<usize, Error> ) -> Result<usize, Error>
where where
C: Corpus<I, R>,
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple, OT: ObserversTuple,
S: IfInteresting<I>
{ {
// TODO: Get around local event copy by moving handle_in_client // TODO: Get around local event copy by moving handle_in_client
let mut events = vec![]; let mut events = vec![];
@ -358,19 +348,11 @@ where
Ok(count) Ok(count)
} }
fn fire<C, FT, OC, OFT, R>( fn fire<S>(
&mut self, &mut self,
_state: &mut State<C, FT, I, OC, OFT, R>, _state: &mut S,
event: Event<I>, event: Event<I>,
) -> Result<(), Error> ) -> Result<(), Error> {
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
I: Input,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
let serialized = postcard::to_allocvec(&event)?; let serialized = postcard::to_allocvec(&event)?;
self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?;
Ok(()) Ok(())
@ -380,17 +362,13 @@ where
/// Serialize the current state and corpus during an executiont to bytes. /// Serialize the current state and corpus during an executiont to bytes.
/// On top, add the current llmp event manager instance to be restored /// On top, add the current llmp event manager instance to be restored
/// This method is needed when the fuzzer run crashes and has to restart. /// This method is needed when the fuzzer run crashes and has to restart.
pub fn serialize_state_mgr<C, FT, I, OC, OFT, R, SH, ST>( pub fn serialize_state_mgr<I, S, SH, ST>(
state: &State<C, FT, I, OC, OFT, R>, state: &S,
mgr: &LlmpEventManager<I, SH, ST>, mgr: &LlmpEventManager<I, SH, ST>,
) -> Result<Vec<u8>, Error> ) -> Result<Vec<u8>, Error>
where where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
I: Input, I: Input,
R: Rand, S: Serialize,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
SH: ShMem, SH: ShMem,
ST: Stats, ST: Stats,
{ {
@ -398,20 +376,16 @@ where
} }
/// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)` /// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)`
pub fn deserialize_state_mgr<C, FT, I, OC, OFT, R, SH, ST>( pub fn deserialize_state_mgr<I, S, SH, ST>(
state_corpus_serialized: &[u8], state_corpus_serialized: &[u8],
) -> Result<(State<C, FT, I, OC, OFT, R>, LlmpEventManager<I, SH, ST>), Error> ) -> Result<(S, LlmpEventManager<I, SH, ST>), Error>
where where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
I: Input, I: Input,
R: Rand, S: DeserializeOwned,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
SH: ShMem, SH: ShMem,
ST: Stats, ST: Stats,
{ {
let tuple: (State<C, FT, I, OC, OFT, R>, _) = postcard::from_bytes(&state_corpus_serialized)?; let tuple: (S, _) = postcard::from_bytes(&state_corpus_serialized)?;
Ok(( Ok((
tuple.0, tuple.0,
LlmpEventManager::existing_client_from_description(&tuple.1)?, LlmpEventManager::existing_client_from_description(&tuple.1)?,
@ -447,16 +421,12 @@ where
} }
/// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner. /// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner.
fn on_restart<C, FT, OC, OFT, R>( fn on_restart<S>(
&mut self, &mut self,
state: &mut State<C, FT, I, OC, OFT, R>, state: &mut S,
) -> Result<(), Error> ) -> Result<(), Error>
where where
C: Corpus<I, R>, S: Serialize,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{ {
// First, reset the page to 0 so the next iteration can read read from the beginning of this page // First, reset the page to 0 so the next iteration can read read from the beginning of this page
unsafe { self.sender.reset() }; unsafe { self.sender.reset() };
@ -465,35 +435,24 @@ where
.send_buf(_LLMP_TAG_RESTART, &state_corpus_serialized) .send_buf(_LLMP_TAG_RESTART, &state_corpus_serialized)
} }
fn process<C, E, FT, OC, OFT, OT, R>( fn process<E, OT, S>(
&mut self, &mut self,
state: &mut State<C, FT, I, OC, OFT, R>, state: &mut S,
executor: &mut E, executor: &mut E,
) -> Result<usize, Error> ) -> Result<usize, Error>
where where
C: Corpus<I, R>,
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple, OT: ObserversTuple,
S: IfInteresting<I>
{ {
self.llmp_mgr.process(state, executor) self.llmp_mgr.process(state, executor)
} }
fn fire<C, FT, OC, OFT, R>( fn fire<S>(
&mut self, &mut self,
state: &mut State<C, FT, I, OC, OFT, R>, state: &mut S,
event: Event<I>, event: Event<I>,
) -> Result<(), Error> ) -> Result<(), Error> {
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
// Check if we are going to crash in the event, in which case we store our current state for the next runner // Check if we are going to crash in the event, in which case we store our current state for the next runner
self.llmp_mgr.fire(state, event) self.llmp_mgr.fire(state, event)
} }
@ -530,24 +489,20 @@ where
/// A restarting state is a combination of restarter and runner, that can be used on systems without `fork`. /// A restarting state is a combination of restarter and runner, that can be used on systems without `fork`.
/// The restarter will start a new process each time the child crashes or timeouts. /// The restarter will start a new process each time the child crashes or timeouts.
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn setup_restarting_mgr<I, C, FT, OC, OFT, R, SH, ST>( pub fn setup_restarting_mgr<I, S, SH, ST>(
//mgr: &mut LlmpEventManager<I, SH, ST>, //mgr: &mut LlmpEventManager<I, SH, ST>,
stats: ST, stats: ST,
broker_port: u16, broker_port: u16,
) -> Result< ) -> Result<
( (
Option<State<C, FT, I, OC, OFT, R>>, Option<S>,
LlmpRestartingEventManager<I, SH, ST>, LlmpRestartingEventManager<I, SH, ST>,
), ),
Error, Error,
> >
where where
I: Input, I: Input,
C: Corpus<I, R>, S: DeserializeOwned,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
SH: ShMem, SH: ShMem,
ST: Stats, ST: Stats,
{ {
@ -607,7 +562,7 @@ where
// Restoring from a previous run, deserialize state and corpus. // Restoring from a previous run, deserialize state and corpus.
Some((_sender, _tag, msg)) => { Some((_sender, _tag, msg)) => {
println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len()); println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len());
let (state, mgr): (State<C, FT, I, OC, OFT, R>, LlmpEventManager<I, SH, ST>) = let (state, mgr): (S, LlmpEventManager<I, SH, ST>) =
deserialize_state_mgr(&msg)?; deserialize_state_mgr(&msg)?;
(Some(state), LlmpRestartingEventManager::new(mgr, sender)) (Some(state), LlmpRestartingEventManager::new(mgr, sender))

View File

@ -3,15 +3,10 @@ use alloc::{string::ToString, vec::Vec};
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg(unix)] #[cfg(unix)]
use crate::{ use crate::{
corpus::Corpus,
events::{BrokerEventResult, Event, EventManager}, events::{BrokerEventResult, Event, EventManager},
executors::{Executor, HasObservers}, executors::{Executor},
feedbacks::FeedbacksTuple,
inputs::Input, inputs::Input,
observers::ObserversTuple,
state::State,
stats::Stats, stats::Stats,
utils::Rand,
Error, Error,
}; };
@ -33,19 +28,13 @@ where
I: Input, I: Input,
ST: Stats, //CE: CustomEvent<I, OT>, ST: Stats, //CE: CustomEvent<I, OT>,
{ {
fn process<C, E, FT, OC, OFT, OT, R>( fn process<E, S>(
&mut self, &mut self,
state: &mut State<C, FT, I, OC, OFT, R>, state: &mut S,
_executor: &mut E, _executor: &mut E,
) -> Result<usize, Error> ) -> Result<usize, Error>
where where
C: Corpus<I, R>, E: Executor<I>
E: Executor<I> + HasObservers<OT>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
{ {
let count = self.events.len(); let count = self.events.len();
while self.events.len() > 0 { while self.events.len() > 0 {
@ -55,17 +44,11 @@ where
Ok(count) Ok(count)
} }
fn fire<C, FT, OC, OFT, R>( fn fire<S>(
&mut self, &mut self,
_state: &mut State<C, FT, I, OC, OFT, R>, _state: &mut S,
event: Event<I>, event: Event<I>,
) -> Result<(), Error> ) -> Result<(), Error>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{ {
match Self::handle_in_broker(&mut self.stats, &event)? { match Self::handle_in_broker(&mut self.stats, &event)? {
BrokerEventResult::Forward => self.events.push(event), BrokerEventResult::Forward => self.events.push(event),
@ -132,18 +115,11 @@ where
} }
// Handle arriving events in the client // Handle arriving events in the client
fn handle_in_client<C, FT, OC, OFT, R>( fn handle_in_client<S>(
&mut self, &mut self,
_state: &mut State<C, FT, I, OC, OFT, R>, _state: &mut S,
event: Event<I>, event: Event<I>,
) -> Result<(), Error> ) -> Result<(), Error> {
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
match event { match event {
_ => Err(Error::Unknown(format!( _ => Err(Error::Unknown(format!(
"Received illegal message that message should not have arrived: {:?}.", "Received illegal message that message should not have arrived: {:?}.",

View File

@ -9,13 +9,9 @@ use core::{fmt, marker::PhantomData, time::Duration};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
corpus::Corpus, executors::{Executor},
executors::{Executor, HasObservers},
feedbacks::FeedbacksTuple,
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
state::State,
utils::Rand,
Error, Error,
}; };
@ -162,19 +158,13 @@ where
/// Lookup for incoming events and process them. /// Lookup for incoming events and process them.
/// Return the number of processes events or an error /// Return the number of processes events or an error
fn process<C, E, FT, OC, OFT, OT, R>( fn process<E, S>(
&mut self, &mut self,
state: &mut State<C, FT, I, OC, OFT, R>, state: &mut S,
executor: &mut E, executor: &mut E,
) -> Result<usize, Error> ) -> Result<usize, Error>
where where
C: Corpus<I, R>, E: Executor<I>;
E: Executor<I> + HasObservers<OT>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple;
/// Serialize all observers for this type and manager /// Serialize all observers for this type and manager
fn serialize_observers<OT>(&mut self, observers: &OT) -> Result<Vec<u8>, Error> fn serialize_observers<OT>(&mut self, observers: &OT) -> Result<Vec<u8>, Error>
@ -194,17 +184,10 @@ where
/// For restarting event managers, implement a way to forward state to their next peers. /// For restarting event managers, implement a way to forward state to their next peers.
#[inline] #[inline]
fn on_restart<C, FT, OC, OFT, R>( fn on_restart<S>(
&mut self, &mut self,
_state: &mut State<C, FT, I, OC, OFT, R>, _state: &mut S,
) -> Result<(), Error> ) -> Result<(), Error> {
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
Ok(()) Ok(())
} }
@ -213,17 +196,11 @@ where
fn await_restart_safe(&mut self) {} fn await_restart_safe(&mut self) {}
/// Send off an event to the broker /// Send off an event to the broker
fn fire<C, FT, OC, OFT, R>( fn fire<S>(
&mut self, &mut self,
_state: &mut State<C, FT, I, OC, OFT, R>, state: &mut S,
event: Event<I>, event: Event<I>,
) -> Result<(), Error> ) -> Result<(), Error>;
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>;
} }
/// An eventmgr for tests, and as placeholder if you really don't need an event manager. /// An eventmgr for tests, and as placeholder if you really don't need an event manager.
@ -235,35 +212,22 @@ impl<I> EventManager<I> for NopEventManager<I>
where where
I: Input, I: Input,
{ {
fn process<C, E, FT, OC, OFT, OT, R>( fn process<E, S>(
&mut self, &mut self,
_state: &mut State<C, FT, I, OC, OFT, R>, _state: &mut S,
_executor: &mut E, _executor: &mut E,
) -> Result<usize, Error> ) -> Result<usize, Error>
where where
C: Corpus<I, R>, E: Executor<I>,
E: Executor<I> + HasObservers<OT>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
{ {
Ok(0) Ok(0)
} }
fn fire<C, FT, OC, OFT, R>( fn fire<S>(
&mut self, &mut self,
_state: &mut State<C, FT, I, OC, OFT, R>, _state: &mut S,
_event: Event<I>, _event: Event<I>,
) -> Result<(), Error> ) -> Result<(), Error> {
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
Ok(()) Ok(())
} }
} }

View File

@ -54,52 +54,42 @@ where
OT: ObserversTuple, OT: ObserversTuple,
{ {
#[inline] #[inline]
fn pre_exec<C, EM, FT, OC, OFT, R>( fn pre_exec<EM, S>(
&mut self, &mut self,
_state: &mut State<C, FT, I, OC, OFT, R>, state: &mut S,
_event_mgr: &mut EM, event_mgr: &mut EM,
_input: &I, input: &I,
) -> Result<(), Error> ) -> Result<(), Error>
where where
R: Rand,
FT: FeedbacksTuple<I>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
C: Corpus<I, R>,
EM: EventManager<I>, EM: EventManager<I>,
{ {
#[cfg(unix)] #[cfg(unix)]
#[cfg(feature = "std")] #[cfg(feature = "std")]
unsafe { unsafe {
set_oncrash_ptrs::<C, EM, FT, I, OC, OFT, OT, R>( set_oncrash_ptrs(
_state, state,
_event_mgr, event_mgr,
self.observers(), self.observers(),
_input, input,
); );
} }
Ok(()) Ok(())
} }
#[inline] #[inline]
fn post_exec<C, EM, FT, OC, OFT, R>( fn post_exec<EM, S>(
&mut self, &mut self,
_state: &State<C, FT, I, OC, OFT, R>, _state: &S,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_input: &I, _input: &I,
) -> Result<(), Error> ) -> Result<(), Error>
where where
R: Rand,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
EM: EventManager<I>, EM: EventManager<I>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{ {
#[cfg(unix)] #[cfg(unix)]
#[cfg(feature = "std")] #[cfg(feature = "std")]
unsafe { unsafe {
reset_oncrash_ptrs::<C, EM, FT, I, OT, R>(); reset_oncrash_ptrs();
} }
Ok(()) Ok(())
} }
@ -148,8 +138,6 @@ where
/// depnding on different corpus or state. /// depnding on different corpus or state.
/// * `name` - the name of this executor (to address it along the way) /// * `name` - the name of this executor (to address it along the way)
/// * `harness_fn` - the harness, executiong the function /// * `harness_fn` - the harness, executiong the function
/// * `on_crash_fn` - When an in-mem harness crashes, it may safe some state to continue fuzzing later.
/// Do that that in this function. The program will crash afterwards.
/// * `observers` - the observers observing the target during execution /// * `observers` - the observers observing the target during execution
pub fn new<C, EM, FT, OC, OFT, R>( pub fn new<C, EM, FT, OC, OFT, R>(
name: &'static str, name: &'static str,
@ -161,9 +149,9 @@ where
where where
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
OC: Corpus<I, R>, OC: Corpus<I>,
OFT: FeedbacksTuple<I>, OFT: FeedbacksTuple<I>,
C: Corpus<I, R>, C: Corpus<I>,
EM: EventManager<I>, EM: EventManager<I>,
{ {
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -181,25 +169,6 @@ where
} }
} }
/*
unsafe fn tidy_up_on_exit<EM>(mgr: &EM)
where
EM: EventManager<I>,
I: Input,
{
match manager.llmp {
IsClient { client } => {
let map = client.out_maps.last().unwrap();
/// wait until we can drop the message safely.
map.await_save_to_unmap_blocking();
/// Make sure all pages are unmapped.
drop(manager);
}
_ => (),
}
}*/
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg(unix)] #[cfg(unix)]
pub mod unix_signals { pub mod unix_signals {
@ -242,15 +211,15 @@ pub mod unix_signals {
/// This is needed for certain non-rust side effects, as well as unix signal handling. /// This is needed for certain non-rust side effects, as well as unix signal handling.
static mut CURRENT_INPUT_PTR: *const c_void = ptr::null(); static mut CURRENT_INPUT_PTR: *const c_void = ptr::null();
pub unsafe extern "C" fn libaflrs_executor_inmem_handle_crash<C, EM, FT, I, OC, OFT, OT, R>( unsafe fn inmem_handle_crash<C, EM, FT, I, OC, OFT, OT, R>(
_sig: c_int, _sig: c_int,
info: siginfo_t, info: siginfo_t,
_void: c_void, _void: c_void,
) where ) where
EM: EventManager<I>, EM: EventManager<I>,
C: Corpus<I, R>, C: Corpus<I>,
OT: ObserversTuple, OT: ObserversTuple,
OC: Corpus<I, R>, OC: Corpus<I>,
OFT: FeedbacksTuple<I>, OFT: FeedbacksTuple<I>,
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
I: Input, I: Input,
@ -324,14 +293,14 @@ pub mod unix_signals {
std::process::exit(1); std::process::exit(1);
} }
pub unsafe extern "C" fn libaflrs_executor_inmem_handle_timeout<C, EM, FT, I, OC, OFT, OT, R>( unsafe fn inmem_handle_timeout<C, EM, FT, I, OC, OFT, OT, R>(
_sig: c_int, _sig: c_int,
_info: siginfo_t, _info: siginfo_t,
_void: c_void, _void: c_void,
) where ) where
EM: EventManager<I>, EM: EventManager<I>,
C: Corpus<I, R>, C: Corpus<I>,
OC: Corpus<I, R>, OC: Corpus<I>,
OFT: FeedbacksTuple<I>, OFT: FeedbacksTuple<I>,
OT: ObserversTuple, OT: ObserversTuple,
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
@ -384,21 +353,12 @@ pub mod unix_signals {
} }
#[inline] #[inline]
pub unsafe fn set_oncrash_ptrs<C, EM, FT, I, OC, OFT, OT, R>( pub unsafe fn set_oncrash_ptrs<EM, I, OT, S>(
state: &mut State<C, FT, I, OC, OFT, R>, state: &mut S,
event_mgr: &mut EM, event_mgr: &mut EM,
observers: &OT, observers: &OT,
input: &I, input: &I,
) where ) {
EM: EventManager<I>,
C: Corpus<I, R>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
I: Input,
R: Rand,
{
CURRENT_INPUT_PTR = input as *const _ as *const c_void; CURRENT_INPUT_PTR = input as *const _ as *const c_void;
STATE_PTR = state as *mut _ as *mut c_void; STATE_PTR = state as *mut _ as *mut c_void;
EVENT_MGR_PTR = event_mgr as *mut _ as *mut c_void; EVENT_MGR_PTR = event_mgr as *mut _ as *mut c_void;
@ -406,19 +366,18 @@ pub mod unix_signals {
} }
#[inline] #[inline]
pub unsafe fn reset_oncrash_ptrs<C, EM, FT, I, OT, R>() { pub unsafe fn reset_oncrash_ptrs() {
CURRENT_INPUT_PTR = ptr::null(); CURRENT_INPUT_PTR = ptr::null();
STATE_PTR = ptr::null_mut(); STATE_PTR = ptr::null_mut();
EVENT_MGR_PTR = ptr::null_mut(); EVENT_MGR_PTR = ptr::null_mut();
OBSERVERS_PTR = ptr::null_mut(); OBSERVERS_PTR = ptr::null();
} }
// TODO clearly state that manager should be static (maybe put the 'static lifetime?)
pub unsafe fn setup_crash_handlers<C, EM, FT, I, OC, OFT, OT, R>() pub unsafe fn setup_crash_handlers<C, EM, FT, I, OC, OFT, OT, R>()
where where
EM: EventManager<I>, EM: EventManager<I>,
C: Corpus<I, R>, C: Corpus<I>,
OC: Corpus<I, R>, OC: Corpus<I>,
OFT: FeedbacksTuple<I>, OFT: FeedbacksTuple<I>,
OT: ObserversTuple, OT: ObserversTuple,
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
@ -441,7 +400,7 @@ pub mod unix_signals {
libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t); libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t);
sa.sa_flags = SA_NODEFER | SA_SIGINFO | SA_ONSTACK; sa.sa_flags = SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
sa.sa_sigaction = sa.sa_sigaction =
libaflrs_executor_inmem_handle_crash::<C, EM, FT, I, OC, OFT, OT, R> as usize; inmem_handle_crash::<C, EM, FT, I, OC, OFT, OT, R> as usize;
for (sig, msg) in &[ for (sig, msg) in &[
(SIGSEGV, "segfault"), (SIGSEGV, "segfault"),
(SIGBUS, "sigbus"), (SIGBUS, "sigbus"),
@ -456,7 +415,7 @@ pub mod unix_signals {
} }
sa.sa_sigaction = sa.sa_sigaction =
libaflrs_executor_inmem_handle_timeout::<C, EM, FT, I, OC, OFT, OT, R> as usize; inmem_handle_timeout::<C, EM, FT, I, OC, OFT, OT, R> as usize;
if sigaction(SIGUSR2, &mut sa as *mut sigaction, ptr::null_mut()) < 0 { if sigaction(SIGUSR2, &mut sa as *mut sigaction, ptr::null_mut()) < 0 {
panic!("Could not set up sigusr2 handler for timeouts"); panic!("Could not set up sigusr2 handler for timeouts");
} }

View File

@ -10,13 +10,9 @@ use core::marker::PhantomData;
use crate::{ use crate::{
bolts::tuples::{MatchNameAndType, MatchType, Named, TupleList}, bolts::tuples::{MatchNameAndType, MatchType, Named, TupleList},
corpus::Corpus,
events::EventManager, events::EventManager,
feedbacks::FeedbacksTuple,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::ObserversTuple, observers::ObserversTuple,
state::State,
utils::Rand,
Error, Error,
}; };
@ -84,18 +80,13 @@ where
{ {
#[inline] #[inline]
/// Called right before exexution starts /// Called right before exexution starts
fn pre_exec<C, EM, FT, OC, OFT, R>( fn pre_exec<EM, S>(
&mut self, &mut self,
_state: &mut State<C, FT, I, OC, OFT, R>, _state: &mut S,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_input: &I, _input: &I,
) -> Result<(), Error> ) -> Result<(), Error>
where where
R: Rand,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
EM: EventManager<I>, EM: EventManager<I>,
{ {
Ok(()) Ok(())
@ -103,18 +94,13 @@ where
#[inline] #[inline]
/// Called right after execution finished. /// Called right after execution finished.
fn post_exec<C, EM, FT, OC, OFT, R>( fn post_exec<EM, S>(
&mut self, &mut self,
_state: &State<C, FT, I, OC, OFT, R>, _state: &S,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_input: &I, _input: &I,
) -> Result<(), Error> ) -> Result<(), Error>
where where
R: Rand,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
EM: EventManager<I>, EM: EventManager<I>,
{ {
Ok(()) Ok(())

View File

@ -6,7 +6,7 @@ use crate::{
executors::{Executor}, executors::{Executor},
inputs::Input, inputs::Input,
stages::StagesTuple, stages::StagesTuple,
state::{HasRand, HasCorpus}, state::{HasRand, HasCorpus, HasExecutions},
utils::{Rand, current_milliseconds, current_time}, utils::{Rand, current_milliseconds, current_time},
Error Error
}; };
@ -70,6 +70,7 @@ where
{ {
scheduler: CS, scheduler: CS,
stages: ST, stages: ST,
phantom: PhantomData<I>
} }
impl<CS, ST, I> HasStages<ST, I> for StdFuzzer<CS, ST, I> impl<CS, ST, I> HasStages<ST, I> for StdFuzzer<CS, ST, I>
@ -139,7 +140,7 @@ where
where where
EM: EventManager<I>, EM: EventManager<I>,
E: Executor<I>, E: Executor<I>,
S: HasCorpus<C, I> + HasRand<R>, S: HasCorpus<C, I> + HasRand<R> + HasExecutions,
C: Corpus<I>, C: Corpus<I>,
R: Rand R: Rand
{ {
@ -152,7 +153,7 @@ where
manager.fire( manager.fire(
state, state,
Event::UpdateStats { Event::UpdateStats {
executions: state.executions(), executions: *state.executions(),
time: current_time(), time: current_time(),
phantom: PhantomData, phantom: PhantomData,
}, },
@ -173,6 +174,7 @@ where
Self { Self {
scheduler: scheduler, scheduler: scheduler,
stages: stages, stages: stages,
phantom: PhantomData
} }
} }
} }

View File

@ -116,6 +116,7 @@ impl From<ParseIntError> for Error {
} }
} }
/*
// TODO: no_std test // TODO: no_std test
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg(test)] #[cfg(test)]
@ -198,3 +199,4 @@ mod tests {
assert_eq!(state.corpus().count(), corpus_deserialized.count()); assert_eq!(state.corpus().count(), corpus_deserialized.count());
} }
} }
*/

View File

@ -175,7 +175,7 @@ where
R: Rand, R: Rand,
{ {
scheduled: SM, scheduled: SM,
phantom: PhantomData<(I, R, S)>, phantom: PhantomData<(C, I, R, S)>,
} }
impl<C, I, R, S, SM> Mutator<I> for HavocBytesMutator<C, I, R, S, SM> impl<C, I, R, S, SM> Mutator<I> for HavocBytesMutator<C, I, R, S, SM>
@ -258,9 +258,8 @@ where
} }
} }
impl<C, I, R, S, SM> Default for HavocBytesMutator<C, I, R, S, StdScheduledMutator<I, R, S>> impl<C, I, R, S> Default for HavocBytesMutator<C, I, R, S, StdScheduledMutator<I, R, S>>
where where
SM: ScheduledMutator<I, S> + HasMaxSize,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata, S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
C: Corpus<I>, C: Corpus<I>,

View File

@ -3,7 +3,7 @@
use crate::{ use crate::{
inputs::{HasBytesVec, Input}, inputs::{HasBytesVec, Input},
state::{HasRand, HasCorpus, HasMetadata}, state::{HasRand, HasMetadata},
mutators::*, mutators::*,
utils::Rand, utils::Rand,
Error, Error,

View File

@ -9,7 +9,7 @@ use crate::{
stages::Stage, stages::Stage,
state::{HasRand}, state::{HasRand},
utils::Rand, utils::Rand,
state::HasCorpus, state::{HasCorpus, Evaluator},
Error, Error,
}; };
@ -43,7 +43,7 @@ where
where where
EM: EventManager<I>, EM: EventManager<I>,
E: Executor<I>, E: Executor<I>,
S: HasCorpus<C, I>, S: HasCorpus<C, I> + Evaluator<I>,
C: Corpus<I> C: Corpus<I>
{ {
let num = self.iterations(state); let num = self.iterations(state);
@ -57,7 +57,7 @@ where
self.mutator_mut() self.mutator_mut()
.mutate(state, &mut input_mut, i as i32)?; .mutate(state, &mut input_mut, i as i32)?;
let fitness = state.process_input(input_mut, executor, manager)?; let fitness = state.evaluate_input(input_mut, executor, manager)?;
self.mutator_mut().post_exec(state, fitness, i as i32)?; self.mutator_mut().post_exec(state, fitness, i as i32)?;
} }
@ -121,7 +121,7 @@ where
where where
EM: EventManager<I>, EM: EventManager<I>,
E: Executor<I>, E: Executor<I>,
S: HasCorpus<C, I>, S: HasCorpus<C, I> + Evaluator<I>,
C: Corpus<I> C: Corpus<I>
{ {
self.perform_mutational(executor, state, manager, corpus_idx) self.perform_mutational(executor, state, manager, corpus_idx)

View File

@ -1,6 +1,6 @@
//! The fuzzer, and state are the core pieces of every good fuzzer //! The fuzzer, and state are the core pieces of every good fuzzer
use core::{fmt::Debug, marker::PhantomData}; use core::{fmt::Debug, marker::PhantomData, time::Duration};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::{ use std::{
@ -36,6 +36,18 @@ where
fn corpus_mut(&mut self) -> &mut C; fn corpus_mut(&mut self) -> &mut C;
} }
/// Trait for elements offering a corpus of solutions
pub trait HasSolutions<C, I>
where
C: Corpus<I>,
I: Input,
{
/// The solutions corpus
fn solutions(&self) -> &C;
/// The solutions corpus (mut)
fn solutions_mut(&mut self) -> &mut C;
}
/// Trait for elements offering a rand /// Trait for elements offering a rand
pub trait HasRand<R> pub trait HasRand<R>
where where
@ -64,46 +76,409 @@ pub trait HasMetadata {
} }
} }
/// Trait for elements offering a feedbacks tuple
pub trait HasFeedbacks<FT, I>
where
FT: FeedbacksTuple<I>,
I: Input
{
/// The feedbacks tuple
fn feedbacks(&self) -> &FT;
/// The feedbacks tuple (mut)
fn feedbacks_mut(&mut self) -> &mut FT;
/// Resets all metadata holds by feedbacks
#[inline]
fn discard_feedbacks_metadata(&mut self, input: &I) -> Result<(), Error> {
// TODO: This could probably be automatic in the feedback somehow?
self.feedbacks_mut().discard_metadata_all(&input)
}
/// Creates a new testcase, appending the metadata from each feedback
#[inline]
fn testcase_with_feedbacks_metadata(&mut self, input: I, fitness: u32) -> Result<Testcase<I>, Error> {
let mut testcase = Testcase::with_fitness(input, fitness);
self.feedbacks_mut().append_metadata_all(&mut testcase)?;
Ok(testcase)
}
}
/// Trait for elements offering an objective feedbacks tuple
pub trait HasObjectives<FT, I>
where
FT: FeedbacksTuple<I>,
I: Input
{
/// The objective feedbacks tuple
fn objectives(&self) -> &FT;
/// The objective feedbacks tuple (mut)
fn objectives_mut(&mut self) -> &mut FT;
}
/// Trait for the execution counter
pub trait HasExecutions
{
/// The executions counter
fn executions(&self) -> &usize;
/// The executions counter (mut)
fn executions_mut(&mut self) -> &mut usize;
}
/// Trait for the starting time
pub trait HasStartTime
{
/// The starting time
fn start_time(&self) -> &Duration;
/// The starting time (mut)
fn start_time_mut(&mut self) -> &mut Duration;
}
/// Add to the state if interesting
pub trait IfInteresting<I>
where
I: Input
{
/// Evaluate if a set of observation channels has an interesting state
fn is_interesting<OT>(
&mut self,
input: &I,
observers: &OT,
exit_kind: ExitKind,
) -> Result<u32, Error>
where
OT: ObserversTuple;
/// Adds this input to the corpus, if it's intersting, and return the index
fn add_if_interesting(&mut self, input: &I, fitness: u32) -> Result<Option<usize>, Error>;
}
/// Evaluate an input modyfing the state of the fuzzer and returning a fitness
pub trait Evaluator<I>
where
I: Input,
{
/// Runs the input and triggers observers and feedback
fn evaluate_input<E, EM>(
&mut self,
input: I,
executor: &mut E,
event_mgr: &mut EM,
) -> Result<u32, Error>
where
E: Executor<I>,
EM: EventManager<I>;
}
/// The state a fuzz run. /// The state a fuzz run.
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "FT: serde::de::DeserializeOwned")] #[serde(bound = "FT: serde::de::DeserializeOwned")]
pub struct State<C, FT, I, OC, OFT, R> pub struct State<C, FT, I, OFT, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
OC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OFT: FeedbacksTuple<I>,
{ {
/// RNG instance /// RNG instance
rand: R, rand: R,
/// How many times the executor ran the harness/target /// How many times the executor ran the harness/target
executions: usize, executions: usize,
/// At what time the fuzzing started
start_time: Duration,
/// The corpus /// The corpus
corpus: C, corpus: C,
// TODO use Duration
/// At what time the fuzzing started
start_time: u64,
/// Metadata stored for this state by one of the components
metadata: SerdeAnyMap,
/// Feedbacks used to evaluate an input /// Feedbacks used to evaluate an input
feedbacks: FT, feedbacks: FT,
// Objective corpus // Solutions corpus
objective_corpus: OC, solutions: SC,
/// Objective Feedbacks /// Objective Feedbacks
objective_feedbacks: OFT, objectives: OFT,
/// Metadata stored for this state by one of the components
metadata: SerdeAnyMap,
phantom: PhantomData<I>, phantom: PhantomData<I>,
} }
impl<C, FT, I, OFT, R, SC> HasRand<R> for State<C, FT, I, OFT, R, SC>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
SC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// The rand instance
#[inline]
fn rand(&self) -> &R {
&self.rand
}
/// The rand instance (mut)
#[inline]
fn rand_mut(&mut self) -> &mut R {
&mut self.rand
}
}
impl<C, FT, I, OFT, R, SC> HasCorpus<C, I> for State<C, FT, I, OFT, R, SC>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
SC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// Returns the corpus
#[inline]
fn corpus(&self) -> &C {
&self.corpus
}
/// Returns the mutable corpus
#[inline]
fn corpus_mut(&mut self) -> &mut C {
&mut self.corpus
}
}
impl<C, FT, I, OFT, R, SC> HasSolutions<SC, I> for State<C, FT, I, OFT, R, SC>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
SC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// Returns the solutions corpus
#[inline]
fn solutions(&self) -> &SC {
&self.solutions
}
/// Returns the solutions corpus (mut)
#[inline]
fn solutions_mut(&mut self) -> &mut SC {
&mut self.solutions
}
}
impl<C, FT, I, OFT, R, SC> HasMetadata for State<C, FT, I, OFT, R, SC>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
SC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// Get all the metadata into an HashMap
#[inline]
fn metadata(&self) -> &SerdeAnyMap {
&self.metadata
}
/// Get all the metadata into an HashMap (mutable)
#[inline]
fn metadata_mut(&mut self) -> &mut SerdeAnyMap {
&mut self.metadata
}
}
impl<C, FT, I, OFT, R, SC> HasFeedbacks<FT, I> for State<C, FT, I, OFT, R, SC>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
SC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// The feedbacks tuple
#[inline]
fn feedbacks(&self) -> &FT {
&self.feedbacks
}
/// The feedbacks tuple (mut)
#[inline]
fn feedbacks_mut(&mut self) -> &mut FT {
&mut self.feedbacks
}
}
impl<C, FT, I, OFT, R, SC> HasObjectives<OFT, I> for State<C, FT, I, OFT, R, SC>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
SC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// The objective feedbacks tuple
#[inline]
fn objectives(&self) -> &OFT {
&self.objectives
}
/// The objective feedbacks tuple (mut)
#[inline]
fn objectives_mut(&mut self) -> &mut OFT {
&mut self.objectives
}
}
impl<C, FT, I, OFT, R, SC> HasExecutions for State<C, FT, I, OFT, R, SC>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
SC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// The executions counter
#[inline]
fn executions(&self) -> &usize {
&self.executions
}
/// The executions counter (mut)
#[inline]
fn executions_mut(&mut self) -> &mut usize {
&mut self.executions
}
}
impl<C, FT, I, OFT, R, SC> HasStartTime for State<C, FT, I, OFT, R, SC>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
SC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// The starting time
#[inline]
fn start_time(&self) -> &Duration {
&self.start_time
}
/// The starting time (mut)
#[inline]
fn start_time_mut(&mut self) -> &mut Duration {
&mut self.start_time
}
}
impl<C, FT, I, OFT, R, SC> IfInteresting<I> for State<C, FT, I, OFT, R, SC>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
SC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// Evaluate if a set of observation channels has an interesting state
fn is_interesting<OT>(
&mut self,
input: &I,
observers: &OT,
exit_kind: ExitKind,
) -> Result<u32, Error>
where
OT: ObserversTuple,
{
Ok(self
.feedbacks_mut()
.is_interesting_all(input, observers, exit_kind)?)
}
/// Adds this input to the corpus, if it's intersting, and return the index
#[inline]
fn add_if_interesting(&mut self, input: &I, fitness: u32) -> Result<Option<usize>, Error> {
if fitness > 0 {
let testcase = self.testcase_with_feedbacks_metadata(input.clone(), fitness)?;
Ok(Some(self.corpus.add(testcase)?)) // TODO scheduler hook
} else {
self.discard_feedbacks_metadata(input)?;
Ok(None)
}
}
}
impl<C, FT, I, OFT, R, SC> Evaluator<I> for State<C, FT, I, OFT, R, SC>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
SC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// Process one input, adding to the respective corpuses if needed and firing the right events
#[inline]
fn evaluate_input<E, EM, OT>(
&mut self,
// TODO probably we can take a ref to input and pass a cloned one to add_if_interesting
input: I,
executor: &mut E,
manager: &mut EM,
) -> Result<u32, Error>
where
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
C: Corpus<I>,
EM: EventManager<I>,
{
let (fitness, is_solution) = self.execute_input(&input, executor, manager)?;
let observers = executor.observers();
if is_solution {
// If the input is a solution, add it to the respective corpus
self.solutions_mut().add(Testcase::new(input.clone()))?;
}
if let idx = Some(self.add_if_interesting(&input, fitness)?) {
let observers_buf = manager.serialize_observers(observers)?;
manager.fire(
self,
Event::NewTestcase {
input: input,
observers_buf,
corpus_size: self.corpus().count() + 1,
client_config: "TODO".into(),
time: crate::utils::current_time(),
executions: *self.executions(),
},
)?;
}
Ok(fitness)
}
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<C, FT, OC, OFT, R> State<C, FT, BytesInput, OC, OFT, R> impl<C, FT, OFT, R, SC> State<C, FT, BytesInput, OFT, R, SC>
where where
C: Corpus<BytesInput>, C: Corpus<BytesInput>,
R: Rand, R: Rand,
FT: FeedbacksTuple<BytesInput>, FT: FeedbacksTuple<BytesInput>,
OC: Corpus<BytesInput>, SC: Corpus<BytesInput>,
OFT: FeedbacksTuple<BytesInput>, OFT: FeedbacksTuple<BytesInput>,
{ {
pub fn load_from_directory<E, OT, EM>( pub fn load_from_directory<E, OT, EM>(
@ -133,12 +508,12 @@ where
println!("Loading file {:?} ...", &path); println!("Loading file {:?} ...", &path);
let bytes = fs::read(&path)?; let bytes = fs::read(&path)?;
let input = BytesInput::new(bytes); let input = BytesInput::new(bytes);
let (fitness, obj_fitness) = self.evaluate_input(&input, executor, manager)?; let (fitness, is_solution) = self.execute_input(&input, executor, manager)?;
if self.add_if_interesting(input, fitness)?.is_none() { if self.add_if_interesting(&input, fitness)?.is_none() {
println!("File {:?} was not interesting, skipped.", &path); println!("File {:?} was not interesting, skipped.", &path);
} }
if obj_fitness > 0 { if is_solution {
println!("File {:?} is an objective, however will be not added as an initial testcase.", &path); println!("File {:?} is a solution, however will be not considered as it is an initial testcase.", &path);
} }
} else if attr.is_dir() { } else if attr.is_dir() {
self.load_from_directory(executor, manager, &path)?; self.load_from_directory(executor, manager, &path)?;
@ -176,159 +551,23 @@ where
} }
} }
impl<C, FT, I, OC, OFT, R> HasRand<R> for State<C, FT, I, OC, OFT, R>
impl<C, FT, I, OFT, R, SC> State<C, FT, I, OFT, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
OC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OFT: FeedbacksTuple<I>,
{ {
/// The rand instance
fn rand(&self) -> &R {
&self.rand
}
/// The rand instance (mut)
fn rand_mut(&mut self) -> &mut R {
&mut self.rand
}
}
impl<C, FT, I, OC, OFT, R> HasCorpus<C, I> for State<C, FT, I, OC, OFT, R>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
OC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// Returns the corpus
fn corpus(&self) -> &C {
&self.corpus
}
/// Returns the mutable corpus
fn corpus_mut(&mut self) -> &mut C {
&mut self.corpus
}
}
/// Trait for elements offering metadata
impl<C, FT, I, OC, OFT, R> HasMetadata for State<C, FT, I, OC, OFT, R>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
OC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// Get all the metadata into an HashMap
#[inline]
fn metadata(&self) -> &SerdeAnyMap {
&self.metadata
}
/// Get all the metadata into an HashMap (mutable)
#[inline]
fn metadata_mut(&mut self) -> &mut SerdeAnyMap {
&mut self.metadata
}
}
impl<C, FT, I, OC, OFT, R> State<C, FT, I, OC, OFT, R>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
OC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
/// Get executions
#[inline]
pub fn executions(&self) -> usize {
self.executions
}
/// Set executions
#[inline]
pub fn set_executions(&mut self, executions: usize) {
self.executions = executions
}
#[inline]
pub fn start_time(&self) -> u64 {
self.start_time
}
#[inline]
pub fn set_start_time(&mut self, ms: u64) {
self.start_time = ms
}
/// Returns vector of feebacks
#[inline]
pub fn feedbacks(&self) -> &FT {
&self.feedbacks
}
/// Returns vector of feebacks (mutable)
#[inline]
pub fn feedbacks_mut(&mut self) -> &mut FT {
&mut self.feedbacks
}
/// Returns vector of objective feebacks
#[inline]
pub fn objective_feedbacks(&self) -> &OFT {
&self.objective_feedbacks
}
/// Returns vector of objective feebacks (mutable)
#[inline]
pub fn objective_feedbacks_mut(&mut self) -> &mut OFT {
&mut self.objective_feedbacks
}
/// Returns the objective corpus
#[inline]
pub fn objective_corpus(&self) -> &OC {
&self.objective_corpus
}
/// Returns the mutable objective corpus
#[inline]
pub fn objective_corpus_mut(&mut self) -> &mut OC {
&mut self.objective_corpus
}
// TODO move some of these, like evaluate_input, to FuzzingEngine
#[inline]
pub fn is_interesting<OT>(
&mut self,
input: &I,
observers: &OT,
exit_kind: ExitKind,
) -> Result<u32, Error>
where
OT: ObserversTuple,
{
Ok(self
.feedbacks_mut()
.is_interesting_all(input, observers, exit_kind)?)
}
/// Runs the input and triggers observers and feedback /// Runs the input and triggers observers and feedback
pub fn evaluate_input<E, EM, OT>( pub fn execute_input<E, EM, OT>(
&mut self, &mut self,
input: &I, input: &I,
executor: &mut E, executor: &mut E,
event_mgr: &mut EM, event_mgr: &mut EM,
) -> Result<(u32, u32), Error> ) -> Result<(u32, bool), Error>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple, OT: ObserversTuple,
@ -341,121 +580,18 @@ where
let exit_kind = executor.run_target(input)?; let exit_kind = executor.run_target(input)?;
executor.post_exec(&self, event_mgr, input)?; executor.post_exec(&self, event_mgr, input)?;
self.set_executions(self.executions() + 1); *self.executions_mut() += 1;
executor.post_exec_observers()?; executor.post_exec_observers()?;
let observers = executor.observers(); let observers = executor.observers();
let objective_fitness =
self.objective_feedbacks
.is_interesting_all(&input, observers, exit_kind.clone())?;
let fitness = self let fitness = self
.feedbacks_mut() .feedbacks_mut()
.is_interesting_all(&input, observers, exit_kind)?; .is_interesting_all(&input, observers, exit_kind)?;
Ok((fitness, objective_fitness))
}
/// Resets all current feedbacks let is_solution = self.objectives_mut().is_interesting_all(&input, observers, exit_kind.clone())? > 0;
#[inline]
pub fn discard_input(&mut self, input: &I) -> Result<(), Error> {
// TODO: This could probably be automatic in the feedback somehow?
self.feedbacks_mut().discard_metadata_all(&input)
}
/// Creates a new testcase, appending the metadata from each feedback Ok((fitness, is_solution))
#[inline]
pub fn input_to_testcase(&mut self, input: I, fitness: u32) -> Result<Testcase<I>, Error> {
let mut testcase = Testcase::new(input);
testcase.set_fitness(fitness);
self.feedbacks_mut().append_metadata_all(&mut testcase)?;
Ok(testcase)
}
/// Create a testcase from this input, if it's intersting
#[inline]
pub fn testcase_if_interesting(
&mut self,
input: I,
fitness: u32,
) -> Result<Option<Testcase<I>>, Error> {
if fitness > 0 {
Ok(Some(self.input_to_testcase(input, fitness)?))
} else {
self.discard_input(&input)?;
Ok(None)
}
}
/// Adds this input to the corpus, if it's intersting
#[inline]
pub fn add_if_interesting(&mut self, input: I, fitness: u32) -> Result<Option<usize>, Error>
where
C: Corpus<I>,
{
if fitness > 0 {
let testcase = self.input_to_testcase(input, fitness)?;
Ok(Some(C::add(self, testcase)?))
} else {
self.discard_input(&input)?;
Ok(None)
}
}
/// Adds this input to the objective corpus, if it's an objective
#[inline]
pub fn add_if_objective(&mut self, input: I, fitness: u32) -> Result<Option<usize>, Error>
where
C: Corpus<I>,
{
if fitness > 0 {
let testcase = self.input_to_testcase(input, fitness)?;
Ok(Some(self.objective_corpus.add(testcase)))
} else {
self.discard_input(&input)?;
Ok(None)
}
}
/// Process one input, adding to the respective corpuses if needed and firing the right events
#[inline]
pub fn process_input<E, EM, OT>(
&mut self,
// TODO probably we can take a ref to input and pass a cloned one to add_if_interesting
input: I,
executor: &mut E,
manager: &mut EM,
) -> Result<u32, Error>
where
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
C: Corpus<I>,
EM: EventManager<I>,
{
let (fitness, obj_fitness) = self.evaluate_input(&input, executor, manager)?;
let observers = executor.observers();
if obj_fitness > 0 {
self.add_if_objective(input.clone(), obj_fitness)?;
}
if fitness > 0 {
let observers_buf = manager.serialize_observers(observers)?;
manager.fire(
self,
Event::NewTestcase {
input: input.clone(),
observers_buf,
corpus_size: self.corpus().count() + 1,
client_config: "TODO".into(),
time: crate::utils::current_time(),
executions: self.executions(),
},
)?;
self.add_if_interesting(input, fitness)?;
} else {
self.discard_input(&input)?;
}
Ok(fitness)
} }
pub fn generate_initial_inputs<G, E, OT, EM>( pub fn generate_initial_inputs<G, E, OT, EM>(
@ -475,8 +611,8 @@ where
{ {
let mut added = 0; let mut added = 0;
for _ in 0..num { for _ in 0..num {
let input = generator.generate(rand)?; let input = generator.generate(self.rand_mut())?;
let fitness = self.process_input(input, executor, manager)?; let fitness = self.evaluate_input(input, executor, manager)?;
if fitness > 0 { if fitness > 0 {
added += 1; added += 1;
} }
@ -493,15 +629,16 @@ where
Ok(()) Ok(())
} }
pub fn new(corpus: C, feedbacks: FT, objective_corpus: OC, objective_feedbacks: OFT) -> Self { pub fn new(rand: R, corpus: C, feedbacks: FT, solutions: SC, objectives: OFT) -> Self {
Self { Self {
corpus, rand,
executions: 0, executions: 0,
start_time: current_milliseconds(), start_time: Duration::from_millis(0),
metadata: SerdeAnyMap::default(), metadata: SerdeAnyMap::default(),
feedbacks: feedbacks, corpus,
objective_corpus: objective_corpus, feedbacks,
objective_feedbacks: objective_feedbacks, solutions,
objectives,
phantom: PhantomData, phantom: PhantomData,
} }
} }