use alloc::{boxed::Box, vec::Vec};
use core::{any, marker::PhantomData};
pub use calibrate::CalibrationStage;
pub use colorization::*;
#[cfg(feature = "std")]
pub use concolic::ConcolicTracingStage;
#[cfg(all(feature = "std", feature = "concolic_mutation"))]
pub use concolic::SimpleConcolicMutationalStage;
#[cfg(feature = "std")]
pub use dump::*;
pub use generalization::GeneralizationStage;
use hashbrown::HashSet;
use libafl_bolts::{
impl_serdeany,
tuples::{HasConstLen, IntoVec},
Named,
};
pub use logics::*;
pub use mutational::{MutationalStage, StdMutationalStage};
pub use power::{PowerMutationalStage, StdPowerMutationalStage};
use serde::{Deserialize, Serialize};
pub use stats::AflStatsStage;
#[cfg(feature = "unicode")]
pub use string::*;
#[cfg(feature = "std")]
pub use sync::*;
pub use tmin::{
MapEqualityFactory, MapEqualityFeedback, StdTMinMutationalStage, TMinMutationalStage,
};
pub use tracing::{ShadowTracingStage, TracingStage};
pub use tuneable::*;
use tuple_list::NonEmptyTuple;
use crate::{
corpus::{CorpusId, HasCurrentCorpusIdx},
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
executors::{Executor, HasObservers},
inputs::UsesInput,
observers::ObserversTuple,
schedulers::Scheduler,
stages::push::PushStage,
state::{HasCorpus, HasExecutions, HasLastReportTime, HasRand, State, UsesState},
Error, EvaluatorObservers, ExecutesInput, ExecutionProcessor, HasMetadata, HasNamedMetadata,
HasScheduler,
};
pub mod mutational;
pub mod push;
pub mod tmin;
pub mod calibrate;
pub mod colorization;
#[cfg(feature = "std")]
pub mod concolic;
#[cfg(feature = "std")]
pub mod dump;
pub mod generalization;
pub mod logics;
pub mod power;
pub mod stats;
#[cfg(feature = "unicode")]
pub mod string;
#[cfg(feature = "std")]
pub mod sync;
pub mod tracing;
pub mod tuneable;
pub trait Stage<E, EM, Z>: UsesState
where
E: UsesState<State = Self::State>,
EM: UsesState<State = Self::State>,
Z: UsesState<State = Self::State>,
{
fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result<bool, Error>;
fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error>;
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Self::State,
manager: &mut EM,
) -> Result<(), Error>;
fn perform_restartable(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Self::State,
manager: &mut EM,
) -> Result<(), Error> {
if self.restart_progress_should_run(state)? {
self.perform(fuzzer, executor, state, manager)?;
}
self.clear_restart_progress(state)
}
}
pub trait StagesTuple<E, EM, S, Z>
where
E: UsesState<State = S>,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
S: UsesInput + HasCurrentStage,
{
fn perform_all(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut S,
manager: &mut EM,
) -> Result<(), Error>;
}
impl<E, EM, S, Z> StagesTuple<E, EM, S, Z> for ()
where
E: UsesState<State = S>,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
S: UsesInput + HasCurrentStage,
{
fn perform_all(
&mut self,
_: &mut Z,
_: &mut E,
stage: &mut S,
_: &mut EM,
) -> Result<(), Error> {
if stage.current_stage()?.is_some() {
Err(Error::illegal_state(
"Got to the end of the tuple without completing resume.",
))
} else {
Ok(())
}
}
}
impl<Head, Tail, E, EM, Z> StagesTuple<E, EM, Head::State, Z> for (Head, Tail)
where
Head: Stage<E, EM, Z>,
Tail: StagesTuple<E, EM, Head::State, Z> + HasConstLen,
E: UsesState<State = Head::State>,
EM: UsesState<State = Head::State>,
Z: UsesState<State = Head::State>,
Head::State: HasCurrentStage,
{
fn perform_all(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut Head::State,
manager: &mut EM,
) -> Result<(), Error> {
match state.current_stage()? {
Some(idx) if idx < Self::LEN => {
}
Some(idx) if idx == Self::LEN => {
let stage = &mut self.0;
stage.perform_restartable(fuzzer, executor, state, manager)?;
state.clear_stage()?;
}
Some(idx) if idx > Self::LEN => {
unreachable!("We should clear the stage index before we get here...");
}
_ => {
state.set_stage(Self::LEN)?;
let stage = &mut self.0;
stage.perform_restartable(fuzzer, executor, state, manager)?;
state.clear_stage()?;
}
}
self.1.perform_all(fuzzer, executor, state, manager)
}
}
impl<Head, Tail, E, EM, Z>
IntoVec<Box<dyn Stage<E, EM, Z, State = Head::State, Input = Head::Input>>> for (Head, Tail)
where
Head: Stage<E, EM, Z> + 'static,
Tail: StagesTuple<E, EM, Head::State, Z>
+ HasConstLen
+ IntoVec<Box<dyn Stage<E, EM, Z, State = Head::State, Input = Head::Input>>>,
E: UsesState<State = Head::State>,
EM: UsesState<State = Head::State>,
Z: UsesState<State = Head::State>,
Head::State: HasCurrentStage,
{
fn into_vec_reversed(
self,
) -> Vec<Box<dyn Stage<E, EM, Z, State = Head::State, Input = Head::Input>>> {
let (head, tail) = self.uncons();
let mut ret = tail.0.into_vec_reversed();
ret.push(Box::new(head));
ret
}
fn into_vec(self) -> Vec<Box<dyn Stage<E, EM, Z, State = Head::State, Input = Head::Input>>> {
let mut ret = self.into_vec_reversed();
ret.reverse();
ret
}
}
impl<Tail, E, EM, Z> IntoVec<Box<dyn Stage<E, EM, Z, State = Tail::State, Input = Tail::Input>>>
for (Tail,)
where
Tail: UsesState + IntoVec<Box<dyn Stage<E, EM, Z, State = Tail::State, Input = Tail::Input>>>,
Z: UsesState<State = Tail::State>,
EM: UsesState<State = Tail::State>,
E: UsesState<State = Tail::State>,
{
fn into_vec(self) -> Vec<Box<dyn Stage<E, EM, Z, State = Tail::State, Input = Tail::Input>>> {
self.0.into_vec()
}
}
impl<E, EM, Z> IntoVec<Box<dyn Stage<E, EM, Z, State = Z::State, Input = Z::Input>>>
for Vec<Box<dyn Stage<E, EM, Z, State = Z::State, Input = Z::Input>>>
where
Z: UsesState,
EM: UsesState<State = Z::State>,
E: UsesState<State = Z::State>,
{
fn into_vec(self) -> Vec<Box<dyn Stage<E, EM, Z, State = Z::State, Input = Z::Input>>> {
self
}
}
impl<E, EM, S, Z> StagesTuple<E, EM, S, Z>
for Vec<Box<dyn Stage<E, EM, Z, State = S, Input = S::Input>>>
where
E: UsesState<State = S>,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
S: UsesInput + HasCurrentStage + State,
{
fn perform_all(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut S,
manager: &mut EM,
) -> Result<(), Error> {
self.iter_mut()
.try_for_each(|x| x.perform_restartable(fuzzer, executor, state, manager))
}
}
#[derive(Debug)]
pub struct ClosureStage<CB, E, EM, Z>
where
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM) -> Result<(), Error>,
E: UsesState,
{
closure: CB,
phantom: PhantomData<(E, EM, Z)>,
}
impl<CB, E, EM, Z> UsesState for ClosureStage<CB, E, EM, Z>
where
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM) -> Result<(), Error>,
E: UsesState,
{
type State = E::State;
}
impl<CB, E, EM, Z> Named for ClosureStage<CB, E, EM, Z>
where
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM) -> Result<(), Error>,
E: UsesState,
{
fn name(&self) -> &str {
any::type_name::<Self>()
}
}
impl<CB, E, EM, Z> Stage<E, EM, Z> for ClosureStage<CB, E, EM, Z>
where
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM) -> Result<(), Error>,
E: UsesState,
EM: UsesState<State = E::State>,
Z: UsesState<State = E::State>,
E::State: HasNamedMetadata,
{
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut E::State,
manager: &mut EM,
) -> Result<(), Error> {
(self.closure)(fuzzer, executor, state, manager)
}
#[inline]
fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result<bool, Error> {
RetryRestartHelper::restart_progress_should_run(state, self, 3)
}
#[inline]
fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
RetryRestartHelper::clear_restart_progress(state, self)
}
}
impl<CB, E, EM, Z> ClosureStage<CB, E, EM, Z>
where
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM) -> Result<(), Error>,
E: UsesState,
{
#[must_use]
pub fn new(closure: CB) -> Self {
Self {
closure,
phantom: PhantomData,
}
}
}
impl<CB, E, EM, Z> From<CB> for ClosureStage<CB, E, EM, Z>
where
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM) -> Result<(), Error>,
E: UsesState,
{
#[must_use]
fn from(closure: CB) -> Self {
Self::new(closure)
}
}
#[allow(clippy::type_complexity)]
#[derive(Debug)]
pub struct PushStageAdapter<CS, EM, OT, PS, Z> {
push_stage: PS,
phantom: PhantomData<(CS, EM, OT, Z)>,
}
impl<CS, EM, OT, PS, Z> PushStageAdapter<CS, EM, OT, PS, Z> {
#[must_use]
pub fn new(push_stage: PS) -> Self {
Self {
push_stage,
phantom: PhantomData,
}
}
}
impl<CS, EM, OT, PS, Z> UsesState for PushStageAdapter<CS, EM, OT, PS, Z>
where
CS: UsesState,
{
type State = CS::State;
}
impl<CS, E, EM, OT, PS, Z> Stage<E, EM, Z> for PushStageAdapter<CS, EM, OT, PS, Z>
where
CS: Scheduler,
CS::State:
HasExecutions + HasMetadata + HasRand + HasCorpus + HasLastReportTime + HasCurrentCorpusIdx,
E: Executor<EM, Z> + HasObservers<Observers = OT, State = CS::State>,
EM: EventFirer<State = CS::State>
+ EventRestarter
+ HasEventManagerId
+ ProgressReporter<State = CS::State>,
OT: ObserversTuple<CS::State>,
PS: PushStage<CS, EM, OT, Z>,
Z: ExecutesInput<E, EM, State = CS::State>
+ ExecutionProcessor<OT, State = CS::State>
+ EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>,
{
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut CS::State,
event_mgr: &mut EM,
) -> Result<(), Error> {
let push_stage = &mut self.push_stage;
let Some(corpus_idx) = state.current_corpus_idx()? else {
return Err(Error::illegal_state(
"state is not currently processing a corpus index",
));
};
push_stage.set_current_corpus_idx(corpus_idx);
push_stage.init(fuzzer, state, event_mgr, executor.observers_mut())?;
loop {
let input =
match push_stage.pre_exec(fuzzer, state, event_mgr, executor.observers_mut()) {
Some(Ok(next_input)) => next_input,
Some(Err(err)) => return Err(err),
None => break,
};
let exit_kind = fuzzer.execute_input(state, executor, event_mgr, &input)?;
push_stage.post_exec(
fuzzer,
state,
event_mgr,
executor.observers_mut(),
input,
exit_kind,
)?;
}
self.push_stage
.deinit(fuzzer, state, event_mgr, executor.observers_mut())
}
#[inline]
fn restart_progress_should_run(&mut self, _state: &mut Self::State) -> Result<bool, Error> {
Ok(true)
}
#[inline]
fn clear_restart_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> {
Ok(())
}
}
#[derive(Clone, Deserialize, Serialize, Debug)]
pub struct RetryRestartHelper {
tries_remaining: Option<usize>,
skipped: HashSet<CorpusId>,
}
impl_serdeany!(RetryRestartHelper);
impl RetryRestartHelper {
pub fn restart_progress_should_run<S, ST>(
state: &mut S,
stage: &ST,
max_retries: usize,
) -> Result<bool, Error>
where
S: HasNamedMetadata + HasCurrentCorpusIdx,
ST: Named,
{
let corpus_idx = state.current_corpus_idx()?.ok_or_else(|| {
Error::illegal_state(
"No current_corpus_idx set in State, but called RetryRestartHelper::should_skip",
)
})?;
let initial_tries_remaining = max_retries + 1;
let metadata = state.named_metadata_or_insert_with(stage.name(), || Self {
tries_remaining: Some(initial_tries_remaining),
skipped: HashSet::new(),
});
let tries_remaining = metadata
.tries_remaining
.unwrap_or(initial_tries_remaining)
.checked_sub(1)
.ok_or_else(|| {
Error::illegal_state(
"Attempted further retries after we had already gotten to none remaining.",
)
})?;
metadata.tries_remaining = Some(tries_remaining);
Ok(if tries_remaining == 0 {
metadata.skipped.insert(corpus_idx);
false
} else if metadata.skipped.contains(&corpus_idx) {
false
} else {
true
})
}
pub fn clear_restart_progress<S, ST>(state: &mut S, stage: &ST) -> Result<(), Error>
where
S: HasNamedMetadata,
ST: Named,
{
state
.named_metadata_mut::<Self>(stage.name())?
.tries_remaining = None;
Ok(())
}
}
pub trait HasCurrentStage {
fn set_stage(&mut self, idx: usize) -> Result<(), Error>;
fn clear_stage(&mut self) -> Result<(), Error>;
fn current_stage(&self) -> Result<Option<usize>, Error>;
fn on_restart(&mut self) -> Result<(), Error> {
Ok(())
}
}
pub trait HasNestedStageStatus: HasCurrentStage {
fn enter_inner_stage(&mut self) -> Result<(), Error>;
fn exit_inner_stage(&mut self) -> Result<(), Error>;
}
impl_serdeany!(ExecutionCountRestartHelperMetadata);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionCountRestartHelperMetadata {
started_at_execs: u64,
}
#[derive(Debug, Default, Clone)]
pub struct ExecutionCountRestartHelper {
started_at_execs: Option<u64>,
}
impl ExecutionCountRestartHelper {
#[must_use]
pub fn new() -> Self {
Self {
started_at_execs: None,
}
}
pub fn execs_since_progress_start<S>(&mut self, state: &mut S) -> Result<u64, Error>
where
S: HasMetadata + HasExecutions,
{
let started_at_execs = if let Some(started_at_execs) = self.started_at_execs {
started_at_execs
} else {
state
.metadata::<ExecutionCountRestartHelperMetadata>()
.map(|x| {
self.started_at_execs = Some(x.started_at_execs);
x.started_at_execs
})
.map_err(|err| {
Error::illegal_state(format!(
"The ExecutionCountRestartHelperMetadata should have been set at this point - {err}"
))
})?
};
Ok(state.executions() - started_at_execs)
}
pub fn restart_progress_should_run<S>(&mut self, state: &mut S) -> Result<bool, Error>
where
S: HasMetadata + HasExecutions,
{
let executions = *state.executions();
let metadata = state.metadata_or_insert_with(|| ExecutionCountRestartHelperMetadata {
started_at_execs: executions,
});
self.started_at_execs = Some(metadata.started_at_execs);
Ok(true)
}
pub fn clear_restart_progress<S>(&mut self, state: &mut S) -> Result<(), Error>
where
S: HasMetadata,
{
self.started_at_execs = None;
let _metadata = state.remove_metadata::<ExecutionCountRestartHelperMetadata>();
debug_assert!(_metadata.is_some(), "Called clear_restart_progress, but restart_progress_should_run was not called before (or did mutational stages get nested?)");
Ok(())
}
}
#[cfg(test)]
pub mod test {
use core::marker::PhantomData;
use libafl_bolts::{impl_serdeany, Error, Named};
use serde::{Deserialize, Serialize};
use crate::{
corpus::{Corpus, HasCurrentCorpusIdx, Testcase},
inputs::NopInput,
stages::{RetryRestartHelper, Stage},
state::{test::test_std_state, HasCorpus, State, UsesState},
HasMetadata,
};
#[derive(Debug)]
pub struct ResumeSucceededStage<S> {
phantom: PhantomData<S>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct TestProgress {
count: usize,
}
impl_serdeany!(TestProgress);
impl TestProgress {
#[allow(clippy::unnecessary_wraps)]
fn restart_progress_should_run<S, ST>(state: &mut S, _stage: &ST) -> Result<bool, Error>
where
S: HasMetadata,
{
let metadata = state.metadata_or_insert_with(|| Self { count: 0 });
metadata.count += 1;
assert!(
metadata.count == 1,
"Test failed; we resumed a succeeded stage!"
);
Ok(true)
}
fn clear_restart_progress<S, ST>(state: &mut S, _stage: &ST) -> Result<(), Error>
where
S: HasMetadata,
{
if state.remove_metadata::<Self>().is_none() {
return Err(Error::illegal_state(
"attempted to clear status metadata when none was present",
));
}
Ok(())
}
}
impl<S> UsesState for ResumeSucceededStage<S>
where
S: State,
{
type State = S;
}
impl<E, EM, Z> Stage<E, EM, Z> for ResumeSucceededStage<Z::State>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
Z: UsesState,
Z::State: HasMetadata,
{
fn perform(
&mut self,
_fuzzer: &mut Z,
_executor: &mut E,
_state: &mut Self::State,
_manager: &mut EM,
) -> Result<(), Error> {
Ok(())
}
fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result<bool, Error> {
TestProgress::restart_progress_should_run(state, self)
}
fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
TestProgress::clear_restart_progress(state, self)
}
}
#[test]
fn test_tries_progress() -> Result<(), Error> {
#[cfg(any(not(feature = "serdeany_autoreg"), miri))]
unsafe {
RetryRestartHelper::register();
}
struct StageWithOneTry;
impl Named for StageWithOneTry {
fn name(&self) -> &str {
"TestStage"
}
}
let mut state = test_std_state();
let stage = StageWithOneTry;
let corpus_idx = state.corpus_mut().add(Testcase::new(NopInput {}))?;
state.set_corpus_idx(corpus_idx)?;
for _ in 0..10 {
assert!(RetryRestartHelper::restart_progress_should_run(
&mut state, &stage, 1
)?);
RetryRestartHelper::clear_restart_progress(&mut state, &stage)?;
}
for _ in 0..10 {
assert!(RetryRestartHelper::restart_progress_should_run(
&mut state, &stage, 2
)?);
assert!(RetryRestartHelper::restart_progress_should_run(
&mut state, &stage, 2
)?);
RetryRestartHelper::clear_restart_progress(&mut state, &stage)?;
}
assert!(RetryRestartHelper::restart_progress_should_run(
&mut state, &stage, 2
)?);
assert!(RetryRestartHelper::restart_progress_should_run(
&mut state, &stage, 2
)?);
assert!(!RetryRestartHelper::restart_progress_should_run(
&mut state, &stage, 2
)?);
RetryRestartHelper::clear_restart_progress(&mut state, &stage)?;
assert!(!RetryRestartHelper::restart_progress_should_run(
&mut state, &stage, 2
)?);
RetryRestartHelper::clear_restart_progress(&mut state, &stage)?;
Ok(())
}
}