#[cfg(unix)]
use alloc::vec::Vec;
use core::fmt::Debug;
pub use combined::CombinedExecutor;
#[cfg(all(feature = "std", any(unix, doc)))]
pub use command::CommandExecutor;
pub use differential::DiffExecutor;
#[cfg(all(feature = "std", feature = "fork", unix))]
pub use forkserver::{Forkserver, ForkserverExecutor};
pub use inprocess::InProcessExecutor;
#[cfg(all(feature = "std", feature = "fork", unix))]
pub use inprocess_fork::InProcessForkExecutor;
#[cfg(unix)]
use libafl_bolts::os::unix_signals::Signal;
use serde::{Deserialize, Serialize};
pub use shadow::ShadowExecutor;
pub use with_observers::WithObservers;
use crate::{
observers::{ObserversTuple, UsesObservers},
state::UsesState,
Error,
};
pub mod combined;
#[cfg(all(feature = "std", any(unix, doc)))]
pub mod command;
pub mod differential;
#[cfg(all(feature = "std", feature = "fork", unix))]
pub mod forkserver;
pub mod inprocess;
#[cfg(all(feature = "std", unix))]
pub mod inprocess_fork;
pub mod shadow;
pub mod with_observers;
pub mod hooks;
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(
any(not(feature = "serdeany_autoreg"), miri),
allow(clippy::unsafe_derive_deserialize)
)] pub enum ExitKind {
Ok,
Crash,
Oom,
Timeout,
Diff {
primary: DiffExitKind,
secondary: DiffExitKind,
},
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(
any(not(feature = "serdeany_autoreg"), miri),
allow(clippy::unsafe_derive_deserialize)
)] pub enum DiffExitKind {
Ok,
Crash,
Oom,
Timeout,
Diff,
}
libafl_bolts::impl_serdeany!(ExitKind);
impl From<ExitKind> for DiffExitKind {
fn from(exitkind: ExitKind) -> Self {
match exitkind {
ExitKind::Ok => DiffExitKind::Ok,
ExitKind::Crash => DiffExitKind::Crash,
ExitKind::Oom => DiffExitKind::Oom,
ExitKind::Timeout => DiffExitKind::Timeout,
ExitKind::Diff { .. } => DiffExitKind::Diff,
}
}
}
libafl_bolts::impl_serdeany!(DiffExitKind);
pub trait HasObservers: UsesObservers {
fn observers(&self) -> &Self::Observers;
fn observers_mut(&mut self) -> &mut Self::Observers;
}
pub trait Executor<EM, Z>: UsesState
where
EM: UsesState<State = Self::State>,
Z: UsesState<State = Self::State>,
{
fn run_target(
&mut self,
fuzzer: &mut Z,
state: &mut Self::State,
mgr: &mut EM,
input: &Self::Input,
) -> Result<ExitKind, Error>;
fn with_observers<OT>(self, observers: OT) -> WithObservers<Self, OT>
where
Self: Sized,
OT: ObserversTuple<Self::State>,
{
WithObservers::new(self, observers)
}
}
#[cfg(unix)]
#[inline]
#[must_use]
pub fn common_signals() -> Vec<Signal> {
vec![
Signal::SigAlarm,
Signal::SigUser2,
Signal::SigAbort,
Signal::SigBus,
#[cfg(feature = "handle_sigpipe")]
Signal::SigPipe,
Signal::SigFloatingPointException,
Signal::SigIllegalInstruction,
Signal::SigSegmentationFault,
Signal::SigTrap,
]
}
#[cfg(test)]
pub mod test {
use core::marker::PhantomData;
use libafl_bolts::{AsSlice, Error};
use crate::{
events::NopEventManager,
executors::{Executor, ExitKind},
fuzzer::test::NopFuzzer,
inputs::{BytesInput, HasTargetBytes},
state::{HasExecutions, NopState, State, UsesState},
};
#[derive(Debug)]
pub struct NopExecutor<S> {
phantom: PhantomData<S>,
}
impl<S> NopExecutor<S> {
#[must_use]
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
impl<S> Default for NopExecutor<S> {
fn default() -> Self {
Self::new()
}
}
impl<S> UsesState for NopExecutor<S>
where
S: State,
{
type State = S;
}
impl<EM, S, Z> Executor<EM, Z> for NopExecutor<S>
where
EM: UsesState<State = S>,
S: State + HasExecutions,
S::Input: HasTargetBytes,
Z: UsesState<State = S>,
{
fn run_target(
&mut self,
_fuzzer: &mut Z,
state: &mut Self::State,
_mgr: &mut EM,
input: &Self::Input,
) -> Result<ExitKind, Error> {
*state.executions_mut() += 1;
if input.target_bytes().as_slice().is_empty() {
Err(Error::empty("Input Empty"))
} else {
Ok(ExitKind::Ok)
}
}
}
#[test]
fn nop_executor() {
let empty_input = BytesInput::new(vec![]);
let nonempty_input = BytesInput::new(vec![1u8]);
let mut executor = NopExecutor::new();
let mut fuzzer = NopFuzzer::new();
let mut state = NopState::new();
executor
.run_target(
&mut fuzzer,
&mut state,
&mut NopEventManager::new(),
&empty_input,
)
.unwrap_err();
executor
.run_target(
&mut fuzzer,
&mut state,
&mut NopEventManager::new(),
&nonempty_input,
)
.unwrap();
}
}