QoL Types and Changes (#3124)

* Nop executor

* Qol types

* no stage

* A new() for NopStage

* clippy

* clippy again

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
This commit is contained in:
lazymio 2025-04-03 23:25:11 +08:00 committed by GitHub
parent 0fdfa1d7a1
commit db7ce822dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 166 additions and 0 deletions

View File

@ -28,6 +28,7 @@ pub mod differential;
#[cfg(all(feature = "std", feature = "fork", unix))] #[cfg(all(feature = "std", feature = "fork", unix))]
pub mod forkserver; pub mod forkserver;
pub mod inprocess; pub mod inprocess;
pub mod nop;
/// SAND(<https://github.com/wtdcode/sand-aflpp>) implementation /// SAND(<https://github.com/wtdcode/sand-aflpp>) implementation
pub mod sand; pub mod sand;

View File

@ -0,0 +1,75 @@
//! Trivial Constant Executor
use core::time::Duration;
use libafl_bolts::tuples::RefIndexable;
use super::{Executor, ExitKind, HasObservers, HasTimeout};
/// [`NopExecutor`] is an executor that does nothing
pub type NopExecutor = ConstantExecutor<()>;
/// Constant Executor that returns a fixed value. Mostly helpful
/// when you need it to satisfy some bounds like [`crate::fuzzer::NopFuzzer`]
#[derive(Debug)]
pub struct ConstantExecutor<OT = ()> {
exit: ExitKind,
tm: Duration,
ot: OT,
}
impl<OT> ConstantExecutor<OT> {
/// Construct a [`ConstantExecutor`]
#[must_use]
pub fn new(exit: ExitKind, tm: Duration, ot: OT) -> Self {
Self { exit, tm, ot }
}
}
impl ConstantExecutor<()> {
/// Construct a [`ConstantExecutor`] that always returns Ok
#[must_use]
pub fn ok() -> Self {
Self::new(ExitKind::Ok, Duration::default(), ())
}
/// Construct a [`ConstantExecutor`] that always returns Crash
#[must_use]
pub fn crash() -> Self {
Self::new(ExitKind::Crash, Duration::default(), ())
}
}
/// These are important to allow [`ConstantExecutor`] to be used with other components
impl<OT> HasObservers for ConstantExecutor<OT> {
type Observers = OT;
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
RefIndexable::from(&self.ot)
}
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
RefIndexable::from(&mut self.ot)
}
}
impl<OT> HasTimeout for ConstantExecutor<OT> {
fn timeout(&self) -> Duration {
self.tm
}
fn set_timeout(&mut self, timeout: Duration) {
self.tm = timeout;
}
}
impl<OT, EM, I, S, Z> Executor<EM, I, S, Z> for ConstantExecutor<OT> {
fn run_target(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<ExitKind, libafl_bolts::Error> {
Ok(self.exit)
}
}

View File

@ -0,0 +1,51 @@
//! A stage implementation that can have dynamic stage runtime
use super::{Restartable, Stage};
/// A dynamic stage implementation. This explicity uses enum so that rustc can better
/// reason about the bounds.
#[derive(Debug)]
pub enum DynamicStage<T1, T2> {
/// One stage
Stage1(T1),
/// The alernative stage
Stage2(T2),
}
impl<T1, T2, E, EM, S, Z> Stage<E, EM, S, Z> for DynamicStage<T1, T2>
where
T1: Stage<E, EM, S, Z>,
T2: Stage<E, EM, S, Z>,
{
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut S,
manager: &mut EM,
) -> Result<(), libafl_bolts::Error> {
match self {
Self::Stage1(st1) => st1.perform(fuzzer, executor, state, manager),
Self::Stage2(st2) => st2.perform(fuzzer, executor, state, manager),
}
}
}
impl<T1, T2, S> Restartable<S> for DynamicStage<T1, T2>
where
T1: Restartable<S>,
T2: Restartable<S>,
{
fn should_restart(&mut self, state: &mut S) -> Result<bool, libafl_bolts::Error> {
match self {
Self::Stage1(st1) => st1.should_restart(state),
Self::Stage2(st2) => st2.should_restart(state),
}
}
fn clear_progress(&mut self, state: &mut S) -> Result<(), libafl_bolts::Error> {
match self {
Self::Stage1(st1) => st1.clear_progress(state),
Self::Stage2(st2) => st2.clear_progress(state),
}
}
}

View File

@ -71,9 +71,11 @@ pub mod colorization;
pub mod concolic; pub mod concolic;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub mod dump; pub mod dump;
pub mod dynamic;
pub mod generalization; pub mod generalization;
pub mod generation; pub mod generation;
pub mod logics; pub mod logics;
pub mod nop;
pub mod power; pub mod power;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub mod sync; pub mod sync;

37
libafl/src/stages/nop.rs Normal file
View File

@ -0,0 +1,37 @@
//! A nop stage does nothing
use super::{Restartable, Stage};
/// A stage that does nothing
#[derive(Debug, Default)]
pub struct NopStage {}
impl NopStage {
/// Create a [`NopStage`]
#[must_use]
pub fn new() -> Self {
Self {}
}
}
impl<E, EM, S, Z> Stage<E, EM, S, Z> for NopStage {
fn perform(
&mut self,
_fuzzer: &mut Z,
_executor: &mut E,
_state: &mut S,
_manager: &mut EM,
) -> Result<(), libafl_bolts::Error> {
Ok(())
}
}
impl<S> Restartable<S> for NopStage {
fn clear_progress(&mut self, _state: &mut S) -> Result<(), libafl_bolts::Error> {
Ok(())
}
fn should_restart(&mut self, _state: &mut S) -> Result<bool, libafl_bolts::Error> {
Ok(true)
}
}