From db7ce822dc8b0ee7f72e81d39ced930a32844430 Mon Sep 17 00:00:00 2001 From: lazymio Date: Thu, 3 Apr 2025 23:25:11 +0800 Subject: [PATCH] QoL Types and Changes (#3124) * Nop executor * Qol types * no stage * A new() for NopStage * clippy * clippy again --------- Co-authored-by: Dongjia "toka" Zhang --- libafl/src/executors/mod.rs | 1 + libafl/src/executors/nop.rs | 75 ++++++++++++++++++++++++++++++++++++ libafl/src/stages/dynamic.rs | 51 ++++++++++++++++++++++++ libafl/src/stages/mod.rs | 2 + libafl/src/stages/nop.rs | 37 ++++++++++++++++++ 5 files changed, 166 insertions(+) create mode 100644 libafl/src/executors/nop.rs create mode 100644 libafl/src/stages/dynamic.rs create mode 100644 libafl/src/stages/nop.rs diff --git a/libafl/src/executors/mod.rs b/libafl/src/executors/mod.rs index 2e5754908c..3754e5c156 100644 --- a/libafl/src/executors/mod.rs +++ b/libafl/src/executors/mod.rs @@ -28,6 +28,7 @@ pub mod differential; #[cfg(all(feature = "std", feature = "fork", unix))] pub mod forkserver; pub mod inprocess; +pub mod nop; /// SAND() implementation pub mod sand; diff --git a/libafl/src/executors/nop.rs b/libafl/src/executors/nop.rs new file mode 100644 index 0000000000..208f7f5929 --- /dev/null +++ b/libafl/src/executors/nop.rs @@ -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 { + exit: ExitKind, + tm: Duration, + ot: OT, +} + +impl ConstantExecutor { + /// 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 HasObservers for ConstantExecutor { + 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 HasTimeout for ConstantExecutor { + fn timeout(&self) -> Duration { + self.tm + } + + fn set_timeout(&mut self, timeout: Duration) { + self.tm = timeout; + } +} + +impl Executor for ConstantExecutor { + fn run_target( + &mut self, + _fuzzer: &mut Z, + _state: &mut S, + _mgr: &mut EM, + _input: &I, + ) -> Result { + Ok(self.exit) + } +} diff --git a/libafl/src/stages/dynamic.rs b/libafl/src/stages/dynamic.rs new file mode 100644 index 0000000000..9e08864844 --- /dev/null +++ b/libafl/src/stages/dynamic.rs @@ -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 { + /// One stage + Stage1(T1), + /// The alernative stage + Stage2(T2), +} + +impl Stage for DynamicStage +where + T1: Stage, + T2: Stage, +{ + 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 Restartable for DynamicStage +where + T1: Restartable, + T2: Restartable, +{ + fn should_restart(&mut self, state: &mut S) -> Result { + 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), + } + } +} diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index dbddebc8d5..e57c3c76d8 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -71,9 +71,11 @@ pub mod colorization; pub mod concolic; #[cfg(feature = "std")] pub mod dump; +pub mod dynamic; pub mod generalization; pub mod generation; pub mod logics; +pub mod nop; pub mod power; #[cfg(feature = "std")] pub mod sync; diff --git a/libafl/src/stages/nop.rs b/libafl/src/stages/nop.rs new file mode 100644 index 0000000000..3f2e21a021 --- /dev/null +++ b/libafl/src/stages/nop.rs @@ -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 Stage for NopStage { + fn perform( + &mut self, + _fuzzer: &mut Z, + _executor: &mut E, + _state: &mut S, + _manager: &mut EM, + ) -> Result<(), libafl_bolts::Error> { + Ok(()) + } +} + +impl Restartable for NopStage { + fn clear_progress(&mut self, _state: &mut S) -> Result<(), libafl_bolts::Error> { + Ok(()) + } + + fn should_restart(&mut self, _state: &mut S) -> Result { + Ok(true) + } +}