pub mod inprocess;
pub use inprocess::InProcessExecutor;
pub mod timeout;
pub use timeout::TimeoutExecutor;
use core::marker::PhantomData;
use crate::{
bolts::serdeany::SerdeAny,
inputs::{HasTargetBytes, Input},
observers::ObserversTuple,
Error,
};
use alloc::boxed::Box;
pub trait CustomExitKind: core::fmt::Debug + SerdeAny + 'static {}
#[derive(Debug)]
pub enum ExitKind {
Ok,
Crash,
Oom,
Timeout,
Custom(Box<dyn CustomExitKind>),
}
pub trait HasExecHooks<EM, I, S> {
#[inline]
fn pre_exec(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
Ok(())
}
#[inline]
fn post_exec(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
Ok(())
}
}
pub trait HasExecHooksTuple<EM, I, S> {
fn pre_exec_all(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error>;
fn post_exec_all(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error>;
}
impl<EM, I, S> HasExecHooksTuple<EM, I, S> for () {
fn pre_exec_all(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
Ok(())
}
fn post_exec_all(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
Ok(())
}
}
impl<EM, I, S, Head, Tail> HasExecHooksTuple<EM, I, S> for (Head, Tail)
where
Head: HasExecHooks<EM, I, S>,
Tail: HasExecHooksTuple<EM, I, S>,
{
fn pre_exec_all(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
self.0.pre_exec(state, mgr, input)?;
self.1.pre_exec_all(state, mgr, input)
}
fn post_exec_all(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
self.0.post_exec(state, mgr, input)?;
self.1.post_exec_all(state, mgr, input)
}
}
pub trait HasObservers<OT>
where
OT: ObserversTuple,
{
fn observers(&self) -> &OT;
fn observers_mut(&mut self) -> &mut OT;
}
pub trait HasObserversHooks<EM, I, OT, S>: HasObservers<OT>
where
OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
{
#[inline]
fn pre_exec_observers(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
self.observers_mut().pre_exec_all(state, mgr, input)
}
#[inline]
fn post_exec_observers(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
self.observers_mut().post_exec_all(state, mgr, input)
}
}
pub trait Executor<I>
where
I: Input,
{
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error>;
}
struct NopExecutor<EM, I, S> {
phantom: PhantomData<(EM, I, S)>,
}
impl<EM, I, S> Executor<I> for NopExecutor<EM, I, S>
where
I: Input + HasTargetBytes,
{
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
if input.target_bytes().as_slice().is_empty() {
Err(Error::Empty("Input Empty".into()))
} else {
Ok(ExitKind::Ok)
}
}
}
impl<EM, I, S> HasExecHooks<EM, I, S> for NopExecutor<EM, I, S> where I: Input + HasTargetBytes {}
#[cfg(test)]
mod test {
use core::marker::PhantomData;
use super::{Executor, NopExecutor};
use crate::inputs::BytesInput;
#[test]
fn nop_executor() {
let empty_input = BytesInput::new(vec![]);
let nonempty_input = BytesInput::new(vec![1u8]);
let mut executor = NopExecutor::<(), _, ()> {
phantom: PhantomData,
};
assert!(executor.run_target(&empty_input).is_err());
assert!(executor.run_target(&nonempty_input).is_ok());
}
}