From 3446ad974c39f8e3db0d8c1d7defc02cdb6853ac Mon Sep 17 00:00:00 2001 From: "Dongjia \"toka\" Zhang" Date: Thu, 12 Dec 2024 16:50:17 +0100 Subject: [PATCH] No Use* from stages (#2745) * no from stage * fixer * doc fix * how was this working???? * more fixes * delete more * rq * cargo-fuzz * m * aa --- fuzzers/baby/tutorial/src/lib.rs | 2 +- .../fuzzbench_fork_qemu/src/fuzzer.rs | 2 +- .../binary_only/fuzzbench_qemu/src/fuzzer.rs | 2 +- .../binary_only/qemu_launcher/src/instance.rs | 13 +- .../fuzzbench_forkserver/src/main.rs | 2 +- .../fuzzbench_forkserver_cmplog/src/main.rs | 5 +- fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs | 6 +- .../src/stages/mutational_stage.rs | 57 +-- fuzzers/inprocess/dynamic_analysis/src/lib.rs | 2 +- fuzzers/inprocess/fuzzbench/src/lib.rs | 2 +- fuzzers/inprocess/fuzzbench_ctx/src/lib.rs | 2 +- fuzzers/inprocess/fuzzbench_text/src/lib.rs | 4 +- fuzzers/inprocess/libfuzzer_libpng/src/lib.rs | 2 +- .../libfuzzer_libpng_cmin/src/lib.rs | 2 +- .../libfuzzer_libpng_tcp_manager/src/lib.rs | 2 +- .../libfuzzer_windows_asan/src/lib.rs | 2 +- libafl/Cargo.toml | 1 + libafl/src/fuzzer/mod.rs | 2 +- libafl/src/stages/afl_stats.rs | 81 ++-- libafl/src/stages/calibrate.rs | 51 ++- libafl/src/stages/colorization.rs | 71 ++-- libafl/src/stages/concolic.rs | 79 ++-- libafl/src/stages/dump.rs | 73 ++-- libafl/src/stages/generalization.rs | 77 ++-- libafl/src/stages/generation.rs | 30 +- libafl/src/stages/logics.rs | 132 ++---- libafl/src/stages/mod.rs | 279 ++----------- libafl/src/stages/mutational.rs | 382 +++++++++--------- libafl/src/stages/power.rs | 161 +++++--- libafl/src/stages/push/mod.rs | 280 +++++++------ libafl/src/stages/push/mutational.rs | 193 ++++++--- libafl/src/stages/stats.rs | 181 --------- libafl/src/stages/sync.rs | 86 ++-- libafl/src/stages/time_tracker.rs | 31 +- libafl/src/stages/tmin.rs | 304 +++++++------- libafl/src/stages/tracing.rs | 132 +++--- libafl/src/stages/tuneable.rs | 243 ++++++----- libafl/src/stages/unicode.rs | 22 +- libafl/src/stages/verify_timeouts.rs | 32 +- libafl_libfuzzer/runtime/src/lib.rs | 6 +- .../src/cmps/stages/aflpptracing.rs | 55 +-- 41 files changed, 1316 insertions(+), 1775 deletions(-) delete mode 100644 libafl/src/stages/stats.rs diff --git a/fuzzers/baby/tutorial/src/lib.rs b/fuzzers/baby/tutorial/src/lib.rs index 9801ee7d76..3e44abff34 100644 --- a/fuzzers/baby/tutorial/src/lib.rs +++ b/fuzzers/baby/tutorial/src/lib.rs @@ -132,7 +132,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // Setup a lain mutator with a mutational stage let mutator = LainMutator::new(); - let power: StdPowerMutationalStage<_, _, PacketData, _, _> = + let power: StdPowerMutationalStage<_, _, PacketData, _, _, _> = StdPowerMutationalStage::new(mutator); let mut stages = tuple_list!(calibration, power); diff --git a/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs b/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs index 838f8d8df5..bce4a5c3cc 100644 --- a/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs +++ b/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs @@ -314,7 +314,7 @@ fn fuzz( 5, )?; - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus diff --git a/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs b/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs index a26a588bb4..fe82f757ff 100644 --- a/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs +++ b/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs @@ -317,7 +317,7 @@ fn fuzz( 5, )?; - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus diff --git a/fuzzers/binary_only/qemu_launcher/src/instance.rs b/fuzzers/binary_only/qemu_launcher/src/instance.rs index 268aa75f88..5693c8ae2b 100644 --- a/fuzzers/binary_only/qemu_launcher/src/instance.rs +++ b/fuzzers/binary_only/qemu_launcher/src/instance.rs @@ -1,5 +1,5 @@ use core::fmt::Debug; -use std::{fs, marker::PhantomData, ops::Range, process, time::Duration}; +use std::{fs, marker::PhantomData, ops::Range, path::PathBuf, process}; #[cfg(feature = "simplemgr")] use libafl::events::SimpleEventManager; @@ -23,8 +23,8 @@ use libafl::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler, }, stages::{ - calibrate::CalibrationStage, power::StdPowerMutationalStage, IfStage, ShadowTracingStage, - StagesTuple, StatsStage, StdMutationalStage, + calibrate::CalibrationStage, power::StdPowerMutationalStage, AflStatsStage, IfStage, + ShadowTracingStage, StagesTuple, StdMutationalStage, }, state::{HasCorpus, StdState, UsesState}, Error, HasMetadata, NopFuzzer, @@ -137,7 +137,10 @@ impl Instance<'_, M> { let stats_stage = IfStage::new( |_, _, _, _| Ok(self.options.tui), - tuple_list!(StatsStage::new(Duration::from_secs(5))), + tuple_list!(AflStatsStage::builder() + .map_observer(&edges_observer) + .stats_file(PathBuf::from("stats.txt")) + .build()?), ); // Feedback to rate the interestingness of an input @@ -274,7 +277,7 @@ impl Instance<'_, M> { 5, )?; - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); // The order of the stages matter! diff --git a/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs b/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs index 3690978ede..9bead73df2 100644 --- a/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs +++ b/fuzzers/forkserver/fuzzbench_forkserver/src/main.rs @@ -298,7 +298,7 @@ fn fuzz( 5, )?; - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus diff --git a/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs b/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs index 9fab692177..4480972337 100644 --- a/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs +++ b/fuzzers/forkserver/fuzzbench_forkserver_cmplog/src/main.rs @@ -300,7 +300,7 @@ fn fuzz( 5, )?; - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus @@ -371,7 +371,8 @@ fn fuzz( let tracing = AFLppCmplogTracingStage::new(cmplog_executor, cmplog_ref); // Setup a randomic Input2State stage - let rq = MultiMutationalStage::new(AFLppRedQueen::with_cmplog_options(true, true)); + let rq: MultiMutationalStage<_, _, BytesInput, _, _, _> = + MultiMutationalStage::new(AFLppRedQueen::with_cmplog_options(true, true)); let cb = |_fuzzer: &mut _, _executor: &mut _, diff --git a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs index c985a81b0f..24f4178083 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs @@ -266,7 +266,7 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, { SupportedMutationalStages::StdMutational(StdMutationalStage::new(mutation), PhantomData) } else { SupportedMutationalStages::PowerMutational( - StdPowerMutationalStage::new(mutation), + StdPowerMutationalStage::<_, _, BytesInput, _, _, _>::new(mutation), PhantomData, ) }; @@ -487,7 +487,9 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, { let tracing = AFLppCmplogTracingStage::new(cmplog_executor, cmplog_ref); // Create a randomic Input2State stage - let rq = MultiMutationalStage::new(AFLppRedQueen::with_cmplog_options(true, true)); + let rq = MultiMutationalStage::<_, _, BytesInput, _, _, _>::new( + AFLppRedQueen::with_cmplog_options(true, true), + ); // Create an IfStage and wrap the CmpLog stages in it. // We run cmplog on the second fuzz run of the testcase. diff --git a/fuzzers/forkserver/libafl-fuzz/src/stages/mutational_stage.rs b/fuzzers/forkserver/libafl-fuzz/src/stages/mutational_stage.rs index 546d2de1a6..efde3a29cb 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/stages/mutational_stage.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/stages/mutational_stage.rs @@ -1,37 +1,25 @@ use std::{borrow::Cow, marker::PhantomData}; use libafl::{ - corpus::Corpus, - inputs::Input, - mutators::Mutator, - stages::{mutational::MutatedTransform, MutationalStage, Stage}, - state::{HasCorpus, HasRand, State, UsesState}, - Error, Evaluator, HasNamedMetadata, + stages::{MutationalStage, Stage}, + Error, }; use libafl_bolts::Named; #[derive(Debug)] -pub enum SupportedMutationalStages { - StdMutational(SM, PhantomData<(S, I, M, EM, Z, E)>), - PowerMutational(P, PhantomData<(S, I, M, EM, Z, E)>), +pub enum SupportedMutationalStages { + StdMutational(SM, PhantomData

), + PowerMutational(P, PhantomData), } -impl MutationalStage - for SupportedMutationalStages +impl MutationalStage for SupportedMutationalStages where - E: UsesState, - EM: UsesState, - M: Mutator, - Z: Evaluator, - I: MutatedTransform + Clone + Input, - SM: MutationalStage, - P: MutationalStage, - S: State + HasRand + HasCorpus + HasNamedMetadata, - <::State as HasCorpus>::Corpus: Corpus, //delete me + SM: MutationalStage, + P: MutationalStage, { + type Mutator = SM::Mutator; /// The mutator, added to this stage - #[inline] - fn mutator(&self) -> &M { + fn mutator(&self) -> &Self::Mutator { match self { Self::StdMutational(m, _) => m.mutator(), Self::PowerMutational(p, _) => p.mutator(), @@ -40,7 +28,7 @@ where /// The list of mutators, added to this stage (as mutable ref) #[inline] - fn mutator_mut(&mut self) -> &mut M { + fn mutator_mut(&mut self) -> &mut Self::Mutator { match self { Self::StdMutational(m, _) => m.mutator_mut(), Self::PowerMutational(p, _) => p.mutator_mut(), @@ -56,14 +44,7 @@ where } } -impl UsesState for SupportedMutationalStages -where - S: State + HasRand, -{ - type State = S; -} - -impl Named for SupportedMutationalStages +impl Named for SupportedMutationalStages where SM: Named, P: Named, @@ -76,18 +57,10 @@ where } } -impl Stage - for SupportedMutationalStages +impl Stage for SupportedMutationalStages where - E: UsesState, - EM: UsesState, - M: Mutator, - Z: Evaluator, - I: MutatedTransform + Clone + Input, - SM: MutationalStage, - P: MutationalStage, - S: State + HasRand + HasCorpus + HasNamedMetadata, - <::State as HasCorpus>::Corpus: Corpus, //delete me + SM: Stage, + P: Stage, { #[inline] #[allow(clippy::let_and_return)] diff --git a/fuzzers/inprocess/dynamic_analysis/src/lib.rs b/fuzzers/inprocess/dynamic_analysis/src/lib.rs index 3a4d445d7a..616bb8960e 100644 --- a/fuzzers/inprocess/dynamic_analysis/src/lib.rs +++ b/fuzzers/inprocess/dynamic_analysis/src/lib.rs @@ -314,7 +314,7 @@ fn fuzz( 5, )?; - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus diff --git a/fuzzers/inprocess/fuzzbench/src/lib.rs b/fuzzers/inprocess/fuzzbench/src/lib.rs index 710148e9cc..99b6e94b79 100644 --- a/fuzzers/inprocess/fuzzbench/src/lib.rs +++ b/fuzzers/inprocess/fuzzbench/src/lib.rs @@ -307,7 +307,7 @@ fn fuzz( 5, )?; - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus diff --git a/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs b/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs index 5d96df01a0..1fc485c250 100644 --- a/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs +++ b/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs @@ -317,7 +317,7 @@ fn fuzz( 5, )?; - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus diff --git a/fuzzers/inprocess/fuzzbench_text/src/lib.rs b/fuzzers/inprocess/fuzzbench_text/src/lib.rs index 1218689df9..f717c19491 100644 --- a/fuzzers/inprocess/fuzzbench_text/src/lib.rs +++ b/fuzzers/inprocess/fuzzbench_text/src/lib.rs @@ -374,7 +374,7 @@ fn fuzz_binary( 5, )?; - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus @@ -589,7 +589,7 @@ fn fuzz_text( 5, )?; - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); let grimoire_mutator = StdScheduledMutator::with_max_stack_pow( diff --git a/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs index 9718674d32..e783ed5116 100644 --- a/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs @@ -143,7 +143,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); let mut stages = tuple_list!(calibration, power); diff --git a/fuzzers/inprocess/libfuzzer_libpng_cmin/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng_cmin/src/lib.rs index 823b04d79d..5a456892bc 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_cmin/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng_cmin/src/lib.rs @@ -140,7 +140,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); let mut stages = tuple_list!(calibration, power); diff --git a/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs index e2b23d599e..033d6814cf 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs @@ -141,7 +141,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); let mut stages = tuple_list!(calibration, power); diff --git a/fuzzers/inprocess/libfuzzer_windows_asan/src/lib.rs b/fuzzers/inprocess/libfuzzer_windows_asan/src/lib.rs index 3ae7f82b15..89b50d70ab 100644 --- a/fuzzers/inprocess/libfuzzer_windows_asan/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_windows_asan/src/lib.rs @@ -110,7 +110,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - let power: StdPowerMutationalStage<_, _, BytesInput, _, _> = + let power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(mutator); let mut stages = tuple_list!(calibration, power); diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 2592a2c7c1..d21cc90264 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -28,6 +28,7 @@ rustc-args = ["--cfg", "docsrs"] [features] default = [ + "introspection", "std", "derive", "llmp_compression", diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index bd82146662..8a074282cb 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -27,7 +27,7 @@ use crate::{ }; /// Send a monitor update all 15 (or more) seconds -const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15); +pub(crate) const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15); /// Holds a scheduler pub trait HasScheduler: UsesState diff --git a/libafl/src/stages/afl_stats.rs b/libafl/src/stages/afl_stats.rs index 7f37241fc3..6aba14ee18 100644 --- a/libafl/src/stages/afl_stats.rs +++ b/libafl/src/stages/afl_stats.rs @@ -26,11 +26,12 @@ use crate::{ corpus::{Corpus, HasCurrentCorpusId, SchedulerTestcaseMetadata, Testcase}, events::EventFirer, executors::HasObservers, + inputs::UsesInput, mutators::Tokens, observers::MapObserver, schedulers::{minimizer::IsFavoredMetadata, HasQueueCycles}, stages::{calibrate::UnstableEntriesMetadata, Stage}, - state::{HasCorpus, HasExecutions, HasImported, HasStartTime, Stoppable, UsesState}, + state::{HasCorpus, HasExecutions, HasImported, HasStartTime, Stoppable}, std::string::ToString, Error, HasMetadata, HasNamedMetadata, HasScheduler, }; @@ -73,7 +74,7 @@ libafl_bolts::impl_serdeany!(FuzzTime); /// The [`AflStatsStage`] is a Stage that calculates and writes /// AFL++'s `fuzzer_stats` and `plot_data` information. #[derive(Debug, Clone)] -pub struct AflStatsStage { +pub struct AflStatsStage { map_observer_handle: Handle, stats_file_path: PathBuf, plot_file_path: Option, @@ -112,7 +113,7 @@ pub struct AflStatsStage { autotokens_enabled: bool, /// The core we are bound to core_id: CoreId, - phantom_data: PhantomData<(O, E, EM, Z)>, + phantom_data: PhantomData<(O, E, EM, S, Z)>, } /// AFL++'s `fuzzer_stats` @@ -234,39 +235,31 @@ pub struct AFLPlotData<'a> { edges_found: &'a u64, } -impl UsesState for AflStatsStage +impl Stage for AflStatsStage where - E: UsesState, - EM: EventFirer, - Z: UsesState, -{ - type State = E::State; -} - -impl Stage for AflStatsStage -where - E: UsesState + HasObservers, - EM: EventFirer, - Z: UsesState + HasScheduler, - E::State: HasImported + E: HasObservers, + EM: EventFirer, + Z: HasScheduler, + S: HasImported + HasCorpus + HasMetadata + HasStartTime + HasExecutions + HasNamedMetadata - + Stoppable, + + Stoppable + + HasCurrentCorpusId + + UsesInput, E::Observers: MatchNameRef, O: MapObserver, C: AsRef + Named, ::Scheduler: HasQueueCycles, - <::State as HasCorpus>::Corpus: Corpus, { #[allow(clippy::too_many_lines)] fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut E::State, + state: &mut S, _manager: &mut EM, ) -> Result<(), Error> { let Some(corpus_idx) = state.current_corpus_id()? else { @@ -413,27 +406,26 @@ where Ok(()) } - fn should_restart(&mut self, _state: &mut Self::State) -> Result { + fn should_restart(&mut self, _state: &mut S) -> Result { Ok(true) } - fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> { Ok(()) } } -impl AflStatsStage +impl AflStatsStage where - E: UsesState + HasObservers, - EM: EventFirer, - Z: UsesState, - E::State: HasImported + HasCorpus + HasMetadata + HasExecutions, + E: HasObservers, + EM: EventFirer, + S: HasImported + HasCorpus + HasMetadata + HasExecutions, C: AsRef + Named, O: MapObserver, { /// Builder for `AflStatsStage` #[must_use] - pub fn builder() -> AflStatsStageBuilder { + pub fn builder() -> AflStatsStageBuilder { AflStatsStageBuilder::new() } @@ -459,13 +451,13 @@ where Ok(()) } - fn maybe_update_is_favored_size(&mut self, testcase: &Testcase) { + fn maybe_update_is_favored_size(&mut self, testcase: &Testcase<::Input>) { if testcase.has_metadata::() { self.is_favored_size += 1; } } - fn maybe_update_slowest_exec(&mut self, testcase: &Testcase) { + fn maybe_update_slowest_exec(&mut self, testcase: &Testcase<::Input>) { if let Some(exec_time) = testcase.exec_time() { if exec_time > &self.slowest_exec { self.slowest_exec = *exec_time; @@ -477,7 +469,7 @@ where self.has_fuzzed_size += 1; } - fn maybe_update_max_depth(&mut self, testcase: &Testcase) { + fn maybe_update_max_depth(&mut self, testcase: &Testcase<::Input>) { if let Ok(metadata) = testcase.metadata::() { if metadata.depth() > self.max_depth { self.max_depth = metadata.depth(); @@ -490,7 +482,11 @@ where } #[cfg(feature = "track_hit_feedbacks")] - fn maybe_update_last_crash(&mut self, testcase: &Testcase, state: &E::State) { + fn maybe_update_last_crash( + &mut self, + testcase: &Testcase<::Input>, + state: &S, + ) { #[cfg(feature = "track_hit_feedbacks")] if testcase .hit_objectives() @@ -502,7 +498,11 @@ where } #[cfg(feature = "track_hit_feedbacks")] - fn maybe_update_last_hang(&mut self, testcase: &Testcase, state: &E::State) { + fn maybe_update_last_hang( + &mut self, + testcase: &Testcase<::Input>, + state: &S, + ) { if testcase .hit_objectives() .contains(&Cow::Borrowed(TIMEOUT_FEEDBACK_NAME)) @@ -624,7 +624,7 @@ pub fn get_run_cmdline() -> Cow<'static, str> { /// The Builder for `AflStatsStage` #[derive(Debug)] -pub struct AflStatsStageBuilder { +pub struct AflStatsStageBuilder { stats_file_path: Option, plot_file_path: Option, core_id: Option, @@ -636,15 +636,14 @@ pub struct AflStatsStageBuilder { banner: String, version: String, target_mode: String, - phantom_data: PhantomData<(O, E, EM, Z)>, + phantom_data: PhantomData<(O, E, EM, S, Z)>, } -impl AflStatsStageBuilder +impl AflStatsStageBuilder where - E: UsesState + HasObservers, - EM: EventFirer, - Z: UsesState, - E::State: HasImported + HasCorpus + HasMetadata + HasExecutions, + E: HasObservers, + EM: EventFirer, + S: HasImported + HasCorpus + HasMetadata + HasExecutions, C: AsRef + Named, O: MapObserver, { @@ -758,7 +757,7 @@ where /// Cannot create the plot file (if provided) /// No `MapObserver` supplied to the builder /// No `stats_file_path` provieded - pub fn build(self) -> Result, Error> { + pub fn build(self) -> Result, Error> { if self.stats_file_path.is_none() { return Err(Error::illegal_argument("Must set `stats_file_path`")); } diff --git a/libafl/src/stages/calibrate.rs b/libafl/src/stages/calibrate.rs index c138758e16..2d2cc09bd2 100644 --- a/libafl/src/stages/calibrate.rs +++ b/libafl/src/stages/calibrate.rs @@ -13,17 +13,17 @@ use num_traits::Bounded; use serde::{Deserialize, Serialize}; use crate::{ - corpus::{Corpus, SchedulerTestcaseMetadata}, + corpus::{Corpus, HasCurrentCorpusId, SchedulerTestcaseMetadata}, events::{Event, EventFirer, LogSeverity}, executors::{Executor, ExitKind, HasObservers}, feedbacks::{map::MapFeedbackMetadata, HasObserverHandle}, fuzzer::Evaluator, - inputs::UsesInput, + inputs::{Input, UsesInput}, monitors::{AggregatorOps, UserStats, UserStatsValue}, observers::{MapObserver, ObserversTuple}, schedulers::powersched::SchedulerMetadata, stages::{RetryCountRestartHelper, Stage}, - state::{HasCorpus, HasCurrentTestcase, HasExecutions, UsesState}, + state::{HasCorpus, HasCurrentTestcase, HasExecutions}, Error, HasMetadata, HasNamedMetadata, }; @@ -73,38 +73,37 @@ impl Default for UnstableEntriesMetadata { pub const CALIBRATION_STAGE_NAME: &str = "calibration"; /// The calibration stage will measure the average exec time and the target's stability for this input. #[derive(Clone, Debug)] -pub struct CalibrationStage { +pub struct CalibrationStage { map_observer_handle: Handle, map_name: Cow<'static, str>, name: Cow<'static, str>, stage_max: usize, /// If we should track stability track_stability: bool, - phantom: PhantomData<(E, O, OT)>, + phantom: PhantomData<(E, O, OT, S)>, } const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1 const CAL_STAGE_MAX: usize = 8; // AFL++'s CAL_CYCLES + 1 -impl UsesState for CalibrationStage +impl Stage for CalibrationStage where - E: UsesState, -{ - type State = E::State; -} - -impl Stage for CalibrationStage -where - E: Executor + HasObservers, - EM: EventFirer, + E: Executor + HasObservers, + EM: EventFirer, O: MapObserver, C: AsRef, for<'de> ::Entry: Serialize + Deserialize<'de> + 'static + Default + Debug + Bounded, - OT: ObserversTuple, - E::State: HasCorpus + HasMetadata + HasNamedMetadata + HasExecutions + HasCurrentTestcase, - Z: Evaluator, - <::State as HasCorpus>::Corpus: Corpus, //delete me + OT: ObserversTuple<::Input, S>, + S: HasCorpus + + HasMetadata + + HasNamedMetadata + + HasExecutions + + HasCurrentTestcase + + HasCurrentCorpusId + + UsesInput::Input>, + Z: Evaluator, + ::Input: Input, { #[inline] #[allow( @@ -116,7 +115,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, mgr: &mut EM, ) -> Result<(), Error> { // Run this stage only once for each corpus entry and only if we haven't already inspected it @@ -368,7 +367,7 @@ where Ok(()) } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { // Calibration stage disallow restarts // If a testcase that causes crash/timeout in the queue, we need to remove it from the queue immediately. RetryCountRestartHelper::no_retry(state, &self.name) @@ -377,19 +376,19 @@ where // remove this guy from corpus queue } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { // TODO: Make sure this is the correct way / there may be a better way? RetryCountRestartHelper::clear_progress(state, &self.name) } } -impl CalibrationStage +impl CalibrationStage where O: MapObserver, for<'it> O: AsIter<'it, Item = O::Entry>, C: AsRef, - OT: ObserversTuple<::Input, ::State>, - E: UsesState, + OT: ObserversTuple<::Input, S>, + S: HasCorpus, { /// Create a new [`CalibrationStage`]. #[must_use] @@ -422,7 +421,7 @@ where } } -impl Named for CalibrationStage { +impl Named for CalibrationStage { fn name(&self) -> &Cow<'static, str> { &self.name } diff --git a/libafl/src/stages/colorization.rs b/libafl/src/stages/colorization.rs index a5ba2b9bc7..91023844fc 100644 --- a/libafl/src/stages/colorization.rs +++ b/libafl/src/stages/colorization.rs @@ -14,7 +14,7 @@ use libafl_bolts::{ use serde::{Deserialize, Serialize}; use crate::{ - corpus::Corpus, + corpus::{Corpus, HasCurrentCorpusId}, events::EventFirer, executors::{Executor, HasObservers}, inputs::{HasMutatorBytes, UsesInput}, @@ -62,21 +62,14 @@ impl Ord for Earlier { pub const COLORIZATION_STAGE_NAME: &str = "colorization"; /// The mutational stage using power schedules #[derive(Clone, Debug)] -pub struct ColorizationStage { +pub struct ColorizationStage { map_observer_handle: Handle, name: Cow<'static, str>, #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, EM, O, E, Z)>, + phantom: PhantomData<(E, EM, O, E, S, Z)>, } -impl UsesState for ColorizationStage -where - E: UsesState, -{ - type State = E::State; -} - -impl Named for ColorizationStage +impl Named for ColorizationStage where E: UsesState, { @@ -85,17 +78,21 @@ where } } -impl Stage for ColorizationStage +impl Stage for ColorizationStage where - EM: UsesState + EventFirer, - E: HasObservers + Executor, - E::State: HasCorpus + HasMetadata + HasRand + HasNamedMetadata, - E::Observers: ObserversTuple<::Input, ::State>, - E::Input: HasMutatorBytes, + EM: EventFirer, + E: HasObservers + Executor, + S: HasCorpus + + HasMetadata + + HasRand + + HasNamedMetadata + + HasCurrentCorpusId + + UsesInput::Input>, + E::Observers: ObserversTuple<::Input, S>, + ::Input: HasMutatorBytes + Clone, O: MapObserver, C: AsRef + Named, - Z: UsesState, - <::State as HasCorpus>::Corpus: Corpus, //delete me + Z: UsesState, { #[inline] #[allow(clippy::let_and_return)] @@ -103,7 +100,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, // don't need the *main* executor for tracing - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { // Run with the mutated input @@ -112,14 +109,14 @@ where Ok(()) } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { // This is a deterministic stage // Once it failed, then don't retry, // It will just fail again RetryCountRestartHelper::no_retry(state, &self.name) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { RetryCountRestartHelper::clear_progress(state, &self.name) } } @@ -163,27 +160,31 @@ impl TaintMetadata { libafl_bolts::impl_serdeany!(TaintMetadata); -impl ColorizationStage +impl ColorizationStage where - EM: UsesState::State> + EventFirer, + EM: EventFirer, O: MapObserver, C: AsRef + Named, - E: HasObservers + Executor, - E::Observers: ObserversTuple<::Input, ::State>, - ::State: HasCorpus + HasMetadata + HasRand, - E::Input: HasMutatorBytes, - Z: UsesState::State>, - <::State as HasCorpus>::Corpus: Corpus, //delete me + E: HasObservers + Executor, + E::Observers: ObserversTuple<::Input, S>, + S: HasCorpus + + HasMetadata + + HasRand + + HasCurrentCorpusId + + HasCurrentTestcase + + UsesInput::Input>, + ::Input: HasMutatorBytes + Clone, + Z: UsesState, { #[inline] #[allow(clippy::let_and_return)] fn colorize( fuzzer: &mut Z, executor: &mut E, - state: &mut ::State, + state: &mut S, manager: &mut EM, observer_handle: &Handle, - ) -> Result { + ) -> Result<::Input, Error> { let mut input = state.current_input_cloned()?; // The backup of the input let backup = input.clone(); @@ -322,9 +323,9 @@ where fn get_raw_map_hash_run( fuzzer: &mut Z, executor: &mut E, - state: &mut ::State, + state: &mut S, manager: &mut EM, - input: &E::Input, + input: &::Input, observer_handle: &Handle, ) -> Result { executor.observers_mut().pre_exec_all(state, input)?; @@ -348,7 +349,7 @@ where /// Replace bytes with random values but following certain rules #[allow(clippy::needless_range_loop)] - fn type_replace(bytes: &mut [u8], state: &mut ::State) { + fn type_replace(bytes: &mut [u8], state: &mut S) { let len = bytes.len(); for idx in 0..len { let c = match bytes[idx] { diff --git a/libafl/src/stages/concolic.rs b/libafl/src/stages/concolic.rs index ccb8a4a36f..b6261a0125 100644 --- a/libafl/src/stages/concolic.rs +++ b/libafl/src/stages/concolic.rs @@ -14,14 +14,13 @@ use libafl_bolts::{ #[cfg(all(feature = "concolic_mutation", feature = "introspection"))] use crate::monitors::PerfFeature; -#[cfg(all(feature = "introspection", feature = "concolic_mutation"))] -use crate::state::HasClientPerfMonitor; use crate::{ - corpus::Corpus, + corpus::{Corpus, HasCurrentCorpusId}, executors::{Executor, HasObservers}, + inputs::UsesInput, observers::{concolic::ConcolicObserver, ObserversTuple}, stages::{RetryCountRestartHelper, Stage, TracingStage}, - state::{HasCorpus, HasCurrentTestcase, HasExecutions, UsesState}, + state::{HasCorpus, HasCurrentTestcase, HasExecutions, MaybeHasClientPerfMonitor, UsesState}, Error, HasMetadata, HasNamedMetadata, }; #[cfg(feature = "concolic_mutation")] @@ -29,51 +28,46 @@ use crate::{ inputs::HasMutatorBytes, mark_feature_time, observers::concolic::{ConcolicMetadata, SymExpr, SymExprRef}, - start_timer, - state::State, - Evaluator, + start_timer, Evaluator, }; /// Wraps a [`TracingStage`] to add concolic observing. #[derive(Clone, Debug)] -pub struct ConcolicTracingStage<'a, EM, TE, Z> { +pub struct ConcolicTracingStage<'a, EM, TE, S, Z> { name: Cow<'static, str>, - inner: TracingStage, + inner: TracingStage, observer_handle: Handle>, } -impl UsesState for ConcolicTracingStage<'_, EM, TE, Z> -where - TE: UsesState, -{ - type State = TE::State; -} - /// The name for concolic tracer pub const CONCOLIC_TRACING_STAGE_NAME: &str = "concolictracing"; -impl Named for ConcolicTracingStage<'_, EM, TE, Z> { +impl Named for ConcolicTracingStage<'_, EM, TE, S, Z> { fn name(&self) -> &Cow<'static, str> { &self.name } } -impl Stage for ConcolicTracingStage<'_, EM, TE, Z> +impl Stage for ConcolicTracingStage<'_, EM, TE, S, Z> where - E: UsesState, - EM: UsesState, - TE: Executor + HasObservers, - TE::Observers: ObserversTuple::State>, - TE::State: HasExecutions + HasCorpus + HasNamedMetadata + HasCurrentTestcase, - Z: UsesState, - <::State as HasCorpus>::Corpus: Corpus, //delete me + TE: Executor + HasObservers, + TE::Observers: ObserversTuple<::Input, S>, + S: HasExecutions + + HasCorpus + + HasNamedMetadata + + HasCurrentTestcase + + HasCurrentCorpusId + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + EM: UsesState, + Z: UsesState, { #[inline] fn perform( &mut self, fuzzer: &mut Z, _executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { self.inner.trace(fuzzer, state, manager)?; @@ -87,23 +81,23 @@ where Ok(()) } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { // This is a deterministic stage // Once it failed, then don't retry, // It will just fail again RetryCountRestartHelper::no_retry(state, &self.name) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { RetryCountRestartHelper::clear_progress(state, &self.name) } } -impl<'a, EM, TE, Z> ConcolicTracingStage<'a, EM, TE, Z> { +impl<'a, EM, TE, S, Z> ConcolicTracingStage<'a, EM, TE, S, Z> { /// Creates a new default tracing stage using the given [`Executor`], observing traces from a /// [`ConcolicObserver`] with the given name. pub fn new( - inner: TracingStage, + inner: TracingStage, observer_handle: Handle>, ) -> Self { let observer_name = observer_handle.name().clone(); @@ -392,22 +386,25 @@ impl Named for SimpleConcolicMutationalStage { } #[cfg(feature = "concolic_mutation")] -impl Stage for SimpleConcolicMutationalStage +impl Stage for SimpleConcolicMutationalStage where - E: UsesState, - EM: UsesState, - Z: Evaluator, - Z::Input: HasMutatorBytes, - Z::State: - State + HasExecutions + HasCorpus + HasMetadata + HasNamedMetadata + HasCurrentTestcase, - <::State as HasCorpus>::Corpus: Corpus, //delete me + Z: Evaluator, + ::Input: HasMutatorBytes + Clone, + S: HasExecutions + + HasCorpus + + HasMetadata + + HasNamedMetadata + + HasCurrentTestcase + + MaybeHasClientPerfMonitor + + HasCurrentCorpusId + + UsesInput::Input>, { #[inline] fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { { @@ -437,7 +434,7 @@ where } #[inline] - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { // This is a deterministic stage // Once it failed, then don't retry, // It will just fail again @@ -445,7 +442,7 @@ where } #[inline] - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { RetryCountRestartHelper::clear_progress(state, &self.name) } } diff --git a/libafl/src/stages/dump.rs b/libafl/src/stages/dump.rs index ee80fa6062..ca9f133cba 100644 --- a/libafl/src/stages/dump.rs +++ b/libafl/src/stages/dump.rs @@ -16,7 +16,7 @@ use crate::{ corpus::{Corpus, CorpusId, Testcase}, inputs::Input, stages::Stage, - state::{HasCorpus, HasRand, HasSolutions, UsesState}, + state::{HasCorpus, HasRand, HasSolutions}, Error, HasMetadata, }; @@ -35,65 +35,53 @@ impl_serdeany!(DumpToDiskMetadata); /// The [`DumpToDiskStage`] is a stage that dumps the corpus and the solutions to disk #[derive(Debug)] -pub struct DumpToDiskStage { +pub struct DumpToDiskStage { solutions_dir: PathBuf, corpus_dir: PathBuf, to_bytes: CB1, generate_filename: CB2, - phantom: PhantomData<(EM, Z)>, + phantom: PhantomData<(EM, S, Z)>, } -impl UsesState for DumpToDiskStage +impl Stage for DumpToDiskStage where - EM: UsesState, -{ - type State = EM::State; -} - -impl Stage for DumpToDiskStage -where - CB1: FnMut(&Testcase, &Self::State) -> Vec, - CB2: FnMut(&Testcase, &CorpusId) -> P, + CB1: FnMut(&Testcase<::Input>, &S) -> Vec, + CB2: FnMut(&Testcase<::Input>, &CorpusId) -> P, + S: HasCorpus + HasSolutions + HasRand + HasMetadata, + S::Solutions: Corpus::Input>, P: AsRef, - EM: UsesState, - E: UsesState, - Z: UsesState, - EM::State: HasCorpus + HasSolutions + HasRand + HasMetadata, - <::State as HasCorpus>::Corpus: Corpus, //delete me - <::State as HasSolutions>::Solutions: Corpus, //delete me { #[inline] fn perform( &mut self, _fuzzer: &mut Z, _executor: &mut E, - state: &mut Self::State, + state: &mut S, _manager: &mut EM, ) -> Result<(), Error> { self.dump_state_to_disk(state) } #[inline] - fn should_restart(&mut self, _state: &mut Self::State) -> Result { + fn should_restart(&mut self, _state: &mut S) -> Result { // Not executing the target, so restart safety is not needed Ok(true) } #[inline] - fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> { // Not executing the target, so restart safety is not needed Ok(()) } } /// Implementation for `DumpToDiskStage` with a default `generate_filename` function. -impl DumpToDiskStage, &CorpusId) -> String, EM, Z> +impl + DumpToDiskStage::Input>, &CorpusId) -> String, EM, S, Z> where - EM: UsesState, - Z: UsesState, - ::State: HasCorpus + HasSolutions + HasRand + HasMetadata, - <::State as HasCorpus>::Corpus: Corpus, - <::State as HasSolutions>::Solutions: Corpus, + S: HasCorpus + HasSolutions + HasRand + HasMetadata, + S::Solutions: Corpus::Input>, + ::Input: Input, { /// Create a new [`DumpToDiskStage`] with a default `generate_filename` function. pub fn new(to_bytes: CB1, corpus_dir: A, solutions_dir: B) -> Result @@ -111,7 +99,10 @@ where /// Default `generate_filename` function. #[allow(clippy::trivially_copy_pass_by_ref)] - fn generate_filename(testcase: &Testcase, id: &CorpusId) -> String { + fn generate_filename( + testcase: &Testcase<::Input>, + id: &CorpusId, + ) -> String { [ Some(id.0.to_string()), testcase.filename().clone(), @@ -128,13 +119,10 @@ where } } -impl DumpToDiskStage +impl DumpToDiskStage where - EM: UsesState, - Z: UsesState, - ::State: HasCorpus + HasSolutions + HasRand + HasMetadata, - <::State as HasCorpus>::Corpus: Corpus, - <::State as HasSolutions>::Solutions: Corpus, + S: HasCorpus + HasMetadata + HasSolutions, + S::Solutions: Corpus::Input>, { /// Create a new [`DumpToDiskStage`] with a custom `generate_filename` function. pub fn new_with_custom_filenames( @@ -175,19 +163,10 @@ where } #[inline] - fn dump_state_to_disk>( - &mut self, - state: &mut ::State, - ) -> Result<(), Error> + fn dump_state_to_disk>(&mut self, state: &mut S) -> Result<(), Error> where - CB1: FnMut( - &Testcase<<<::State as HasCorpus>::Corpus as Corpus>::Input>, - &::State, - ) -> Vec, - CB2: FnMut( - &Testcase<<<::State as HasCorpus>::Corpus as Corpus>::Input>, - &CorpusId, - ) -> P, + CB1: FnMut(&Testcase<::Input>, &S) -> Vec, + CB2: FnMut(&Testcase<::Input>, &CorpusId) -> P, { let (mut corpus_id, mut solutions_id) = if let Some(meta) = state.metadata_map().get::() { diff --git a/libafl/src/stages/generalization.rs b/libafl/src/stages/generalization.rs index 6b2d54d897..1ae2bd28c7 100644 --- a/libafl/src/stages/generalization.rs +++ b/libafl/src/stages/generalization.rs @@ -11,6 +11,8 @@ use libafl_bolts::{ AsSlice, Named, }; +#[cfg(feature = "introspection")] +use crate::monitors::PerfFeature; use crate::{ corpus::{Corpus, HasCurrentCorpusId}, executors::{Executor, HasObservers}, @@ -21,11 +23,9 @@ use crate::{ require_novelties_tracking, stages::{RetryCountRestartHelper, Stage}, start_timer, - state::{HasCorpus, HasExecutions, UsesState}, + state::{HasCorpus, HasExecutions, MaybeHasClientPerfMonitor, UsesState}, Error, HasMetadata, HasNamedMetadata, }; -#[cfg(feature = "introspection")] -use crate::{monitors::PerfFeature, state::HasClientPerfMonitor}; const MAX_GENERALIZED_LEN: usize = 8192; @@ -48,37 +48,35 @@ pub static GENERALIZATION_STAGE_NAME: &str = "generalization"; /// A stage that runs a tracer executor #[derive(Clone, Debug)] -pub struct GeneralizationStage { +pub struct GeneralizationStage { name: Cow<'static, str>, map_observer_handle: Handle, #[allow(clippy::type_complexity)] - phantom: PhantomData<(EM, O, OT, Z)>, + phantom: PhantomData<(EM, O, OT, S, Z)>, } -impl Named for GeneralizationStage { +impl Named for GeneralizationStage { fn name(&self) -> &Cow<'static, str> { &self.name } } -impl UsesState for GeneralizationStage -where - EM: UsesState, -{ - type State = EM::State; -} - -impl Stage for GeneralizationStage +impl Stage for GeneralizationStage where O: MapObserver, C: CanTrack + AsRef + Named, - E: Executor + HasObservers, - E::Observers: ObserversTuple::State>, - EM::State: - UsesInput + HasExecutions + HasMetadata + HasCorpus + HasNamedMetadata, - EM: UsesState, - <::State as HasCorpus>::Corpus: Corpus, //delete me - Z: UsesState, + E: Executor + HasObservers, + E::Observers: ObserversTuple, + S: HasExecutions + + HasMetadata + + HasCorpus + + HasNamedMetadata + + HasCurrentCorpusId + + MaybeHasClientPerfMonitor + + UsesInput, + S::Corpus: Corpus, + EM: UsesState, + Z: UsesState, { #[inline] #[allow(clippy::too_many_lines)] @@ -86,7 +84,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { let Some(corpus_id) = state.current_corpus_id()? else { @@ -331,26 +329,30 @@ where } #[inline] - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { // TODO: We need to be able to resume better if something crashes or times out RetryCountRestartHelper::should_restart(state, &self.name, 3) } #[inline] - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { // TODO: We need to be able to resume better if something crashes or times out RetryCountRestartHelper::clear_progress(state, &self.name) } } -impl GeneralizationStage +impl GeneralizationStage where - EM: UsesState, O: MapObserver, C: CanTrack + AsRef + Named, - ::State: - UsesInput + HasExecutions + HasMetadata + HasCorpus, - OT: ObserversTuple::State>, + S: HasExecutions + + HasMetadata + + HasCorpus + + MaybeHasClientPerfMonitor + + UsesInput, + OT: ObserversTuple, + EM: UsesState, + Z: UsesState, { /// Create a new [`GeneralizationStage`]. #[must_use] @@ -370,15 +372,14 @@ where &self, fuzzer: &mut Z, executor: &mut E, - state: &mut ::State, + state: &mut S, manager: &mut EM, novelties: &[usize], input: &BytesInput, ) -> Result where - E: Executor::State> + HasObservers, - E::Observers: ObserversTuple::State>, - Z: UsesState, + E: Executor + HasObservers, + E::Observers: ObserversTuple, { start_timer!(state); executor.observers_mut().pre_exec_all(state, input)?; @@ -411,7 +412,7 @@ where &self, fuzzer: &mut Z, executor: &mut E, - state: &mut ::State, + state: &mut S, manager: &mut EM, payload: &mut Vec>, novelties: &[usize], @@ -419,8 +420,7 @@ where split_char: u8, ) -> Result<(), Error> where - E: Executor::State> + HasObservers, - Z: UsesState, + E: Executor + HasObservers, { let mut start = 0; while start < payload.len() { @@ -450,7 +450,7 @@ where &self, fuzzer: &mut Z, executor: &mut E, - state: &mut ::State, + state: &mut S, manager: &mut EM, payload: &mut Vec>, novelties: &[usize], @@ -458,8 +458,7 @@ where closing_char: u8, ) -> Result<(), Error> where - E: Executor::State> + HasObservers, - Z: UsesState, + E: Executor + HasObservers, { let mut index = 0; while index < payload.len() { diff --git a/libafl/src/stages/generation.rs b/libafl/src/stages/generation.rs index a2fb61916f..7067d0ea62 100644 --- a/libafl/src/stages/generation.rs +++ b/libafl/src/stages/generation.rs @@ -7,10 +7,11 @@ use core::marker::PhantomData; use crate::{ + corpus::Corpus, generators::Generator, inputs::UsesInput, stages::Stage, - state::{HasCorpus, HasRand, UsesState}, + state::{HasCorpus, HasRand}, Error, Evaluator, }; @@ -19,36 +20,27 @@ use crate::{ /// /// This stage can be used to construct black-box (e.g., grammar-based) fuzzers. #[derive(Debug)] -pub struct GenStage(G, PhantomData); +pub struct GenStage(G, PhantomData<(S, Z)>); -impl GenStage { +impl GenStage { /// Create a new [`GenStage`]. pub fn new(g: G) -> Self { Self(g, PhantomData) } } -impl UsesState for GenStage +impl Stage for GenStage where - Z: UsesState, -{ - type State = Z::State; -} - -impl Stage for GenStage -where - E: UsesState, - EM: UsesState, - Z: Evaluator, - Self::State: HasCorpus + HasRand, - G: Generator<<::State as UsesInput>::Input, Self::State>, + Z: Evaluator, + S: HasCorpus + HasRand + UsesInput::Input>, + G: Generator<::Input, S>, { #[inline] fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { let input = self.0.generate(state)?; @@ -56,13 +48,13 @@ where Ok(()) } - fn should_restart(&mut self, _state: &mut Self::State) -> Result { + fn should_restart(&mut self, _state: &mut S) -> Result { // It's a random generation stage // so you can restart for whatever times you want Ok(true) } - fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> { Ok(()) } } diff --git a/libafl/src/stages/logics.rs b/libafl/src/stages/logics.rs index c05b818774..5a3497a14c 100644 --- a/libafl/src/stages/logics.rs +++ b/libafl/src/stages/logics.rs @@ -3,8 +3,7 @@ use core::marker::PhantomData; use crate::{ - stages::{HasCurrentStageId, HasNestedStageStatus, Stage, StageId, StagesTuple}, - state::UsesState, + stages::{HasNestedStageStatus, Stage, StageId, StagesTuple}, Error, }; @@ -32,33 +31,23 @@ impl NestedStageRetryCountRestartHelper { #[derive(Debug)] /// Perform the stage while the closure evaluates to true -pub struct WhileStage { +pub struct WhileStage { closure: CB, stages: ST, - phantom: PhantomData<(E, EM, Z)>, + phantom: PhantomData<(E, EM, S, Z)>, } -impl UsesState for WhileStage +impl Stage for WhileStage where - E: UsesState, -{ - type State = E::State; -} - -impl Stage for WhileStage -where - CB: FnMut(&mut Z, &mut E, &mut Self::State, &mut EM) -> Result, - E: UsesState, - EM: UsesState, - ST: StagesTuple, - Z: UsesState, - Self::State: HasNestedStageStatus, + CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result, + ST: StagesTuple, + S: HasNestedStageStatus, { fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { while state.current_stage_id()?.is_some() @@ -70,19 +59,18 @@ where Ok(()) } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { NestedStageRetryCountRestartHelper::should_restart(state, self) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { NestedStageRetryCountRestartHelper::clear_progress(state, self) } } -impl WhileStage +impl WhileStage where - CB: FnMut(&mut Z, &mut E, &mut ::State, &mut EM) -> Result, - E: UsesState, + CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result, { /// Constructor pub fn new(closure: CB, stages: ST) -> Self { @@ -97,33 +85,23 @@ where /// A conditionally enabled stage. /// If the closure returns true, the wrapped stage will be executed, else it will be skipped. #[derive(Debug)] -pub struct IfStage { +pub struct IfStage { closure: CB, if_stages: ST, - phantom: PhantomData<(E, EM, Z)>, + phantom: PhantomData<(E, EM, S, Z)>, } -impl UsesState for IfStage +impl Stage for IfStage where - E: UsesState, -{ - type State = E::State; -} - -impl Stage for IfStage -where - CB: FnMut(&mut Z, &mut E, &mut Self::State, &mut EM) -> Result, - E: UsesState, - EM: UsesState, - ST: StagesTuple, - Z: UsesState, - Self::State: HasNestedStageStatus, + CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result, + ST: StagesTuple, + S: HasNestedStageStatus, { fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { if state.current_stage_id()?.is_some() || (self.closure)(fuzzer, executor, state, manager)? @@ -134,19 +112,18 @@ where Ok(()) } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { NestedStageRetryCountRestartHelper::should_restart(state, self) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { NestedStageRetryCountRestartHelper::clear_progress(state, self) } } -impl IfStage +impl IfStage where - CB: FnMut(&mut Z, &mut E, &mut ::State, &mut EM) -> Result, - E: UsesState, + CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result, { /// Constructor for this conditionally enabled stage. /// If the closure returns true, the wrapped stage will be executed, else it will be skipped. @@ -161,35 +138,25 @@ where /// Perform the stage if closure evaluates to true #[derive(Debug)] -pub struct IfElseStage { +pub struct IfElseStage { closure: CB, if_stages: ST1, else_stages: ST2, - phantom: PhantomData<(E, EM, Z)>, + phantom: PhantomData<(E, EM, S, Z)>, } -impl UsesState for IfElseStage +impl Stage for IfElseStage where - E: UsesState, -{ - type State = E::State; -} - -impl Stage for IfElseStage -where - CB: FnMut(&mut Z, &mut E, &mut Self::State, &mut EM) -> Result, - E: UsesState, - EM: UsesState, - ST1: StagesTuple, - ST2: StagesTuple, - Z: UsesState, - Self::State: HasNestedStageStatus, + CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result, + ST1: StagesTuple, + ST2: StagesTuple, + S: HasNestedStageStatus, { fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { let current = state.current_stage_id()?; @@ -219,19 +186,18 @@ where Ok(()) } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { NestedStageRetryCountRestartHelper::should_restart(state, self) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { NestedStageRetryCountRestartHelper::clear_progress(state, self) } } -impl IfElseStage +impl IfElseStage where - CB: FnMut(&mut Z, &mut E, &mut ::State, &mut EM) -> Result, - E: UsesState, + CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result, { /// Constructor pub fn new(closure: CB, if_stages: ST1, else_stages: ST2) -> Self { @@ -246,31 +212,21 @@ where /// A stage wrapper where the stages do not need to be initialized, but can be [`None`]. #[derive(Debug)] -pub struct OptionalStage { +pub struct OptionalStage { stages: Option, - phantom: PhantomData<(E, EM, Z)>, + phantom: PhantomData<(E, EM, S, Z)>, } -impl UsesState for OptionalStage +impl Stage for OptionalStage where - E: UsesState, -{ - type State = E::State; -} - -impl Stage for OptionalStage -where - E: UsesState, - EM: UsesState, - ST: StagesTuple, - Z: UsesState, - Self::State: HasNestedStageStatus, + ST: StagesTuple, + S: HasNestedStageStatus, { fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { if let Some(stages) = &mut self.stages { @@ -280,16 +236,16 @@ where } } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { NestedStageRetryCountRestartHelper::should_restart(state, self) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { NestedStageRetryCountRestartHelper::clear_progress(state, self) } } -impl OptionalStage { +impl OptionalStage { /// Constructor for this conditionally enabled stage. #[must_use] pub fn new(stages: Option) -> Self { diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index 5dcad0aaca..3e66848e9b 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -33,14 +33,11 @@ pub use logics::*; pub use mutational::{MutationalStage, StdMutationalStage}; pub use power::{PowerMutationalStage, StdPowerMutationalStage}; use serde::{Deserialize, Serialize}; -pub use stats::StatsStage; #[cfg(feature = "std")] pub use sync::*; #[cfg(feature = "std")] pub use time_tracker::TimeTrackingStageWrapper; -pub use tmin::{ - MapEqualityFactory, MapEqualityFeedback, StdTMinMutationalStage, TMinMutationalStage, -}; +pub use tmin::{MapEqualityFactory, MapEqualityFeedback, StdTMinMutationalStage}; pub use tracing::{ShadowTracingStage, TracingStage}; pub use tuneable::*; use tuple_list::NonEmptyTuple; @@ -51,15 +48,9 @@ pub use verify_timeouts::{TimeoutsToVerify, VerifyTimeoutsStage}; use crate::{ corpus::{CorpusId, HasCurrentCorpusId}, - events::{EventFirer, EventProcessor, EventRestarter, HasEventManagerId, ProgressReporter}, - executors::{Executor, HasObservers}, - inputs::UsesInput, - observers::ObserversTuple, - schedulers::Scheduler, - stages::push::PushStage, - state::{HasCorpus, HasExecutions, HasLastReportTime, HasRand, State, Stoppable, UsesState}, - Error, EvaluatorObservers, ExecutesInput, ExecutionProcessor, HasMetadata, HasNamedMetadata, - HasScheduler, + events::EventProcessor, + state::{HasExecutions, State, Stoppable}, + Error, HasNamedMetadata, }; /// Mutational stage is the normal fuzzing stage. @@ -79,7 +70,6 @@ pub mod generalization; pub mod generation; pub mod logics; pub mod power; -pub mod stats; #[cfg(feature = "std")] pub mod sync; #[cfg(feature = "std")] @@ -93,21 +83,16 @@ pub mod verify_timeouts; /// A stage is one step in the fuzzing process. /// Multiple stages will be scheduled one by one for each input. -pub trait Stage: UsesState -where - E: UsesState, - EM: UsesState, - Z: UsesState, -{ +pub trait Stage { /// This method will be called before every call to [`Stage::perform`]. /// Initialize the restart tracking for this stage, _if it is not yet initialized_. /// On restart, this will be called again. /// As long as [`Stage::clear_progress`], all subsequent calls happen on restart. /// Returns `true`, if the stage's [`Stage::perform`] method should run, else `false`. - fn should_restart(&mut self, state: &mut Self::State) -> Result; + fn should_restart(&mut self, state: &mut S) -> Result; /// Clear the current status tracking of the associated stage - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error>; + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error>; /// Run the stage. /// @@ -119,7 +104,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error>; @@ -128,7 +113,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { if self.should_restart(state)? { @@ -139,13 +124,7 @@ where } /// A tuple holding all `Stages` used for fuzzing. -pub trait StagesTuple -where - E: UsesState, - EM: UsesState, - Z: UsesState, - S: UsesInput + HasCurrentStageId, -{ +pub trait StagesTuple { /// Performs all `Stages` in this tuple. fn perform_all( &mut self, @@ -158,10 +137,7 @@ where impl StagesTuple for () where - E: UsesState, - EM: UsesState, - Z: UsesState, - S: UsesInput + HasCurrentStageId, + S: HasCurrentStageId, { fn perform_all( &mut self, @@ -180,14 +156,12 @@ where } } -impl StagesTuple for (Head, Tail) +impl StagesTuple for (Head, Tail) where - Head: Stage, - Tail: StagesTuple + HasConstLen, - E: UsesState, - EM: UsesState + EventProcessor, - Z: UsesState, - Head::State: HasCurrentStageId, + Head: Stage, + Tail: StagesTuple + HasConstLen, + S: HasCurrentStageId + Stoppable, + EM: EventProcessor, { /// Performs all stages in the tuple, /// Checks after every stage if state wants to stop @@ -196,7 +170,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Head::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { match state.current_stage_id()? { @@ -239,66 +213,45 @@ where } } -impl - IntoVec>> for (Head, Tail) +impl IntoVec>> for (Head, Tail) where - Head: Stage + 'static, - Tail: StagesTuple - + HasConstLen - + IntoVec>>, - E: UsesState, - EM: UsesState, - Z: UsesState, - Head::State: HasCurrentStageId, + Head: Stage + 'static, + Tail: StagesTuple + HasConstLen + IntoVec>>, + S: HasCurrentStageId, { - fn into_vec_reversed( - self, - ) -> Vec>> { + fn into_vec_reversed(self) -> Vec>> { let (head, tail) = self.uncons(); let mut ret = tail.0.into_vec_reversed(); ret.push(Box::new(head)); ret } - fn into_vec(self) -> Vec>> { + fn into_vec(self) -> Vec>> { let mut ret = self.into_vec_reversed(); ret.reverse(); ret } } -impl IntoVec>> - for (Tail,) +impl IntoVec>> for (Tail,) where - Tail: UsesState + IntoVec>>, - Z: UsesState, - EM: UsesState, - E: UsesState, + Tail: IntoVec>>, { - fn into_vec(self) -> Vec>> { + fn into_vec(self) -> Vec>> { self.0.into_vec() } } -impl IntoVec>> - for Vec>> -where - Z: UsesState, - EM: UsesState, - E: UsesState, -{ - fn into_vec(self) -> Vec>> { +impl IntoVec>> for Vec>> { + fn into_vec(self) -> Vec>> { self } } -impl StagesTuple - for Vec>> +impl StagesTuple for Vec>> where - E: UsesState, - EM: UsesState + EventProcessor, - Z: UsesState, - S: UsesInput + HasCurrentStageId + State, + EM: EventProcessor, + S: HasCurrentStageId + State, { /// Performs all stages in the `Vec` /// Checks after every stage if state wants to stop @@ -333,46 +286,36 @@ pub struct ClosureStage { phantom: PhantomData<(E, EM, Z)>, } -impl UsesState for ClosureStage -where - E: UsesState, -{ - type State = E::State; -} - impl Named for ClosureStage { fn name(&self) -> &Cow<'static, str> { &self.name } } -impl Stage for ClosureStage +impl Stage for ClosureStage where - CB: FnMut(&mut Z, &mut E, &mut Self::State, &mut EM) -> Result<(), Error>, - E: UsesState, - EM: UsesState, - Z: UsesState, - Self::State: HasNamedMetadata, + CB: FnMut(&mut Z, &mut E, &mut S, &mut EM) -> Result<(), Error>, + S: HasNamedMetadata + HasCurrentCorpusId, { fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut E::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { (self.closure)(fuzzer, executor, state, manager) } #[inline] - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { // There's no restart safety in the content of the closure. // don't restart RetryCountRestartHelper::no_retry(state, &self.name) } #[inline] - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { RetryCountRestartHelper::clear_progress(state, &self.name) } } @@ -396,132 +339,6 @@ impl ClosureStage { } } -/// Allows us to use a [`push::PushStage`] as a normal [`Stage`] -#[allow(clippy::type_complexity)] -#[derive(Debug)] -pub struct PushStageAdapter { - name: Cow<'static, str>, - push_stage: PS, - phantom: PhantomData<(CS, EM, OT, Z)>, -} - -impl PushStageAdapter { - /// Create a new [`PushStageAdapter`], wrapping the given [`PushStage`] - /// to be used as a normal [`Stage`] - #[must_use] - pub fn new(push_stage: PS) -> Self { - // unsafe but impossible that you create two threads both instantiating this instance - let stage_id = unsafe { - let ret = PUSH_STAGE_ADAPTER_ID; - PUSH_STAGE_ADAPTER_ID += 1; - ret - }; - Self { - name: Cow::Owned( - PUSH_STAGE_ADAPTER_NAME.to_owned() + ":" + stage_id.to_string().as_str(), - ), - push_stage, - phantom: PhantomData, - } - } -} -/// The unique counter for this stage -static mut PUSH_STAGE_ADAPTER_ID: usize = 0; -/// The name for push stage adapter -pub static PUSH_STAGE_ADAPTER_NAME: &str = "pushstageadapter"; - -impl UsesState for PushStageAdapter -where - Z: UsesState, -{ - type State = Z::State; -} - -impl Named for PushStageAdapter { - #[must_use] - fn name(&self) -> &Cow<'static, str> { - &self.name - } -} - -impl Stage for PushStageAdapter -where - CS: Scheduler, - Self::State: HasExecutions - + HasRand - + HasCorpus - + HasLastReportTime - + HasCurrentCorpusId - + HasNamedMetadata - + HasMetadata, - E: Executor::State> + HasObservers, - EM: EventFirer - + EventRestarter - + HasEventManagerId - + ProgressReporter, - OT: ObserversTuple, - PS: PushStage, - Z: ExecutesInput - + ExecutionProcessor - + EvaluatorObservers - + HasScheduler, -{ - fn perform( - &mut self, - fuzzer: &mut Z, - executor: &mut E, - state: &mut Z::State, - event_mgr: &mut EM, - ) -> Result<(), Error> { - let push_stage = &mut self.push_stage; - - let Some(corpus_id) = state.current_corpus_id()? else { - return Err(Error::illegal_state( - "state is not currently processing a corpus index", - )); - }; - - push_stage.set_current_corpus_id(corpus_id); - - push_stage.init(fuzzer, state, event_mgr, &mut *executor.observers_mut())?; - - loop { - let input = - match push_stage.pre_exec(fuzzer, state, event_mgr, &mut *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, - &mut *executor.observers_mut(), - input, - exit_kind, - )?; - } - - self.push_stage - .deinit(fuzzer, state, event_mgr, &mut *executor.observers_mut()) - } - - #[inline] - fn should_restart(&mut self, state: &mut Self::State) -> Result { - // TODO: Proper restart handling - call post_exec at the right time, etc... - RetryCountRestartHelper::no_retry(state, &self.name) - } - - #[inline] - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { - RetryCountRestartHelper::clear_progress(state, &self.name) - } -} - /// Progress which permits a fixed amount of resumes per round of fuzzing. If this amount is ever /// exceeded, the input will no longer be executed by this stage. #[derive(Clone, Deserialize, Serialize, Debug)] @@ -722,7 +539,7 @@ mod test { corpus::{Corpus, HasCurrentCorpusId, Testcase}, inputs::NopInput, stages::{RetryCountRestartHelper, Stage}, - state::{HasCorpus, State, StdState, UsesState}, + state::{HasCorpus, StdState}, HasMetadata, }; @@ -771,35 +588,25 @@ mod test { } } - impl UsesState for ResumeSucceededStage + impl Stage for ResumeSucceededStage where - S: State, - { - type State = S; - } - - impl Stage for ResumeSucceededStage - where - E: UsesState, - EM: UsesState, - Z: UsesState, - Z::State: HasMetadata, + S: HasMetadata, { fn perform( &mut self, _fuzzer: &mut Z, _executor: &mut E, - _state: &mut Self::State, + _state: &mut S, _manager: &mut EM, ) -> Result<(), Error> { Ok(()) } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { TestProgress::should_restart(state, self) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { TestProgress::clear_progress(state, self) } } diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index 1f05631ea8..1ac574a489 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -9,20 +9,20 @@ use core::{marker::PhantomData, num::NonZeroUsize}; use libafl_bolts::{rands::Rand, Named}; +#[cfg(feature = "introspection")] +use crate::monitors::PerfFeature; use crate::{ - corpus::{Corpus, CorpusId, Testcase}, + corpus::{Corpus, CorpusId, HasCurrentCorpusId, Testcase}, fuzzer::Evaluator, - inputs::Input, + inputs::{Input, UsesInput}, mark_feature_time, mutators::{MultiMutator, MutationResult, Mutator}, nonzero, stages::{RetryCountRestartHelper, Stage}, start_timer, - state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, UsesState}, + state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, MaybeHasClientPerfMonitor}, Error, HasMetadata, HasNamedMetadata, }; -#[cfg(feature = "introspection")] -use crate::{monitors::PerfFeature, state::HasClientPerfMonitor}; // TODO multi mutators stage @@ -81,24 +81,170 @@ where /// A Mutational stage is the stage in a fuzzing run that mutates inputs. /// Mutational stages will usually have a range of mutations that are /// being applied to the input one by one, between executions. -pub trait MutationalStage: Stage -where - E: UsesState, - M: Mutator, - EM: UsesState, - Z: Evaluator, - Self::State: HasCorpus + HasCurrentTestcase, - I: MutatedTransform + Clone, - <::State as HasCorpus>::Corpus: Corpus, -{ +pub trait MutationalStage { + /// The mutator of this stage + type Mutator; + /// The mutator registered for this stage - fn mutator(&self) -> &M; + fn mutator(&self) -> &Self::Mutator; /// The mutator registered for this stage (mutable) - fn mutator_mut(&mut self) -> &mut M; + fn mutator_mut(&mut self) -> &mut Self::Mutator; /// Gets the number of iterations this mutator should run for. - fn iterations(&self, state: &mut Self::State) -> Result; + fn iterations(&self, state: &mut S) -> Result; +} + +/// Default value, how many iterations each stage gets, as an upper bound. +/// It may randomly continue earlier. +pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128; + +/// The default mutational stage +#[derive(Clone, Debug)] +pub struct StdMutationalStage { + /// The name + name: Cow<'static, str>, + /// The mutator(s) to use + mutator: M, + /// The maximum amount of iterations we should do each round + max_iterations: NonZeroUsize, + #[allow(clippy::type_complexity)] + phantom: PhantomData<(E, EM, I, S, Z)>, +} + +impl MutationalStage for StdMutationalStage +where + S: HasRand, +{ + type Mutator = M; + + /// The mutator, added to this stage + #[inline] + fn mutator(&self) -> &Self::Mutator { + &self.mutator + } + + /// The list of mutators, added to this stage (as mutable ref) + #[inline] + fn mutator_mut(&mut self) -> &mut Self::Mutator { + &mut self.mutator + } + + /// Gets the number of iterations as a random number + fn iterations(&self, state: &mut S) -> Result { + Ok(1 + state.rand_mut().below(self.max_iterations)) + } +} + +/// The unique id for mutational stage +static mut MUTATIONAL_STAGE_ID: usize = 0; +/// The name for mutational stage +pub static MUTATIONAL_STAGE_NAME: &str = "mutational"; + +impl Named for StdMutationalStage { + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +impl Stage for StdMutationalStage +where + M: Mutator, + Z: Evaluator, + S: HasCorpus + + HasRand + + HasMetadata + + HasExecutions + + HasNamedMetadata + + HasCurrentCorpusId + + MaybeHasClientPerfMonitor + + UsesInput, + I: MutatedTransform<::Input, S> + Clone, + ::Input: Input, + S::Corpus: Corpus, +{ + #[inline] + #[allow(clippy::let_and_return)] + fn perform( + &mut self, + fuzzer: &mut Z, + executor: &mut E, + state: &mut S, + manager: &mut EM, + ) -> Result<(), Error> { + let ret = self.perform_mutational(fuzzer, executor, state, manager); + + #[cfg(feature = "introspection")] + state.introspection_monitor_mut().finish_stage(); + + ret + } + + fn should_restart(&mut self, state: &mut S) -> Result { + RetryCountRestartHelper::should_restart(state, &self.name, 3) + } + + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { + RetryCountRestartHelper::clear_progress(state, &self.name) + } +} + +impl StdMutationalStage::Input, M, S, Z> +where + M: Mutator<::Input, S>, + Z: Evaluator, + S: HasCorpus + HasRand + HasCurrentCorpusId + UsesInput + MaybeHasClientPerfMonitor, + ::Input: Input + Clone, + S::Corpus: Corpus, +{ + /// Creates a new default mutational stage + pub fn new(mutator: M) -> Self { + // Safe to unwrap: DEFAULT_MUTATIONAL_MAX_ITERATIONS is never 0. + Self::transforming_with_max_iterations(mutator, nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS)) + } + + /// Creates a new mutational stage with the given max iterations + #[inline] + pub fn with_max_iterations(mutator: M, max_iterations: NonZeroUsize) -> Self { + Self::transforming_with_max_iterations(mutator, max_iterations) + } +} + +impl StdMutationalStage +where + M: Mutator, + Z: Evaluator, + S: HasCorpus + HasRand + HasCurrentTestcase + MaybeHasClientPerfMonitor + UsesInput, + I: MutatedTransform<::Input, S> + Clone, + ::Input: Input, + S::Corpus: Corpus, +{ + /// Creates a new transforming mutational stage with the default max iterations + pub fn transforming(mutator: M) -> Self { + // Safe to unwrap: DEFAULT_MUTATIONAL_MAX_ITERATIONS is never 0. + Self::transforming_with_max_iterations(mutator, nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS)) + } + + /// Creates a new transforming mutational stage with the given max iterations + /// + /// # Errors + /// Will return [`Error::IllegalArgument`] for `max_iterations` of 0. + #[inline] + pub fn transforming_with_max_iterations(mutator: M, max_iterations: NonZeroUsize) -> Self { + let stage_id = unsafe { + let ret = MUTATIONAL_STAGE_ID; + MUTATIONAL_STAGE_ID += 1; + ret + }; + let name = + Cow::Owned(MUTATIONAL_STAGE_NAME.to_owned() + ":" + stage_id.to_string().as_str()); + Self { + name, + mutator, + max_iterations, + phantom: PhantomData, + } + } /// Runs this (mutational) stage for the given testcase #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... @@ -106,7 +252,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { start_timer!(state); @@ -150,170 +296,13 @@ where Ok(()) } } - -/// Default value, how many iterations each stage gets, as an upper bound. -/// It may randomly continue earlier. -pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128; - -/// The default mutational stage -#[derive(Clone, Debug)] -pub struct StdMutationalStage { - /// The name - name: Cow<'static, str>, - /// The mutator(s) to use - mutator: M, - /// The maximum amount of iterations we should do each round - max_iterations: NonZeroUsize, - #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, EM, I, Z)>, -} - -impl MutationalStage for StdMutationalStage -where - E: UsesState, - EM: UsesState, - M: Mutator, - Z: Evaluator, - Z::State: HasCorpus + HasRand + HasExecutions + HasMetadata + HasNamedMetadata, - I: MutatedTransform + Clone, - <::State as HasCorpus>::Corpus: Corpus, //delete me -{ - /// The mutator, added to this stage - #[inline] - fn mutator(&self) -> &M { - &self.mutator - } - - /// The list of mutators, added to this stage (as mutable ref) - #[inline] - fn mutator_mut(&mut self) -> &mut M { - &mut self.mutator - } - - /// Gets the number of iterations as a random number - fn iterations(&self, state: &mut Self::State) -> Result { - Ok(1 + state.rand_mut().below(self.max_iterations)) - } -} - -/// The unique id for mutational stage -static mut MUTATIONAL_STAGE_ID: usize = 0; -/// The name for mutational stage -pub static MUTATIONAL_STAGE_NAME: &str = "mutational"; - -impl UsesState for StdMutationalStage -where - Z: UsesState, -{ - type State = Z::State; -} - -impl Named for StdMutationalStage { - fn name(&self) -> &Cow<'static, str> { - &self.name - } -} - -impl Stage for StdMutationalStage -where - E: UsesState, - EM: UsesState, - M: Mutator, - Z: Evaluator, - Z::State: HasCorpus + HasRand + HasMetadata + HasExecutions + HasNamedMetadata, - I: MutatedTransform + Clone, - <::State as HasCorpus>::Corpus: Corpus, //delete me -{ - #[inline] - #[allow(clippy::let_and_return)] - fn perform( - &mut self, - fuzzer: &mut Z, - executor: &mut E, - state: &mut Self::State, - manager: &mut EM, - ) -> Result<(), Error> { - let ret = self.perform_mutational(fuzzer, executor, state, manager); - - #[cfg(feature = "introspection")] - state.introspection_monitor_mut().finish_stage(); - - ret - } - - fn should_restart(&mut self, state: &mut Self::State) -> Result { - RetryCountRestartHelper::should_restart(state, &self.name, 3) - } - - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { - RetryCountRestartHelper::clear_progress(state, &self.name) - } -} - -impl StdMutationalStage -where - E: UsesState::State>, - EM: UsesState::State>, - M: Mutator::State>, - Z: Evaluator, - ::State: HasCorpus + HasRand, -{ - /// Creates a new default mutational stage - pub fn new(mutator: M) -> Self { - // Safe to unwrap: DEFAULT_MUTATIONAL_MAX_ITERATIONS is never 0. - Self::transforming_with_max_iterations(mutator, nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS)) - } - - /// Creates a new mutational stage with the given max iterations - #[inline] - pub fn with_max_iterations(mutator: M, max_iterations: NonZeroUsize) -> Self { - Self::transforming_with_max_iterations(mutator, max_iterations) - } -} - -impl StdMutationalStage -where - E: UsesState::State>, - EM: UsesState::State>, - M: Mutator::State>, - Z: Evaluator, - ::State: HasCorpus + HasRand, -{ - /// Creates a new transforming mutational stage with the default max iterations - pub fn transforming(mutator: M) -> Self { - // Safe to unwrap: DEFAULT_MUTATIONAL_MAX_ITERATIONS is never 0. - Self::transforming_with_max_iterations(mutator, nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS)) - } - - /// Creates a new transforming mutational stage with the given max iterations - /// - /// # Errors - /// Will return [`Error::IllegalArgument`] for `max_iterations` of 0. - #[inline] - pub fn transforming_with_max_iterations(mutator: M, max_iterations: NonZeroUsize) -> Self { - let stage_id = unsafe { - let ret = MUTATIONAL_STAGE_ID; - MUTATIONAL_STAGE_ID += 1; - ret - }; - let name = - Cow::Owned(MUTATIONAL_STAGE_NAME.to_owned() + ":" + stage_id.to_string().as_str()); - Self { - name, - mutator, - max_iterations, - phantom: PhantomData, - } - } -} - /// A mutational stage that operates on multiple inputs, as returned by [`MultiMutator::multi_mutate`]. #[derive(Clone, Debug)] -pub struct MultiMutationalStage { +pub struct MultiMutationalStage { name: Cow<'static, str>, mutator: M, #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, EM, I, Z)>, + phantom: PhantomData<(E, EM, I, S, Z)>, } /// The unique id for multi mutational stage @@ -321,37 +310,29 @@ static mut MULTI_MUTATIONAL_STAGE_ID: usize = 0; /// The name for multi mutational stage pub static MULTI_MUTATIONAL_STAGE_NAME: &str = "multimutational"; -impl UsesState for MultiMutationalStage -where - Z: UsesState, -{ - type State = Z::State; -} - -impl Named for MultiMutationalStage { +impl Named for MultiMutationalStage { fn name(&self) -> &Cow<'static, str> { &self.name } } -impl Stage for MultiMutationalStage +impl Stage for MultiMutationalStage where - E: UsesState, - EM: UsesState, - M: MultiMutator, - Z: Evaluator, - Z::State: HasCorpus + HasRand + HasNamedMetadata + HasCurrentTestcase, - I: MutatedTransform + Clone, - <::State as HasCorpus>::Corpus: Corpus, //delete me + M: MultiMutator, + Z: Evaluator, + S: HasCorpus + HasRand + HasNamedMetadata + HasCurrentTestcase + HasCurrentCorpusId + UsesInput, + I: MutatedTransform<::Input, S> + Clone, + ::Input: Input, + S::Corpus: Corpus, { #[inline] - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { // Make sure we don't get stuck crashing on a single testcase RetryCountRestartHelper::should_restart(state, &self.name, 3) } #[inline] - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { RetryCountRestartHelper::clear_progress(state, &self.name) } @@ -362,7 +343,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { let mut testcase = state.current_testcase_mut()?; @@ -386,17 +367,14 @@ where } } -impl MultiMutationalStage -where - Z: UsesState, -{ +impl MultiMutationalStage { /// Creates a new [`MultiMutationalStage`] pub fn new(mutator: M) -> Self { Self::transforming(mutator) } } -impl MultiMutationalStage { +impl MultiMutationalStage { /// Creates a new transforming mutational stage pub fn transforming(mutator: M) -> Self { // unsafe but impossible that you create two threads both instantiating this instance diff --git a/libafl/src/stages/power.rs b/libafl/src/stages/power.rs index 83083a692e..adcf982ca8 100644 --- a/libafl/src/stages/power.rs +++ b/libafl/src/stages/power.rs @@ -8,15 +8,24 @@ use core::{fmt::Debug, marker::PhantomData}; use libafl_bolts::Named; +#[cfg(feature = "introspection")] +use crate::monitors::PerfFeature; use crate::{ - corpus::Corpus, + corpus::{Corpus, HasCurrentCorpusId}, executors::{Executor, HasObservers}, fuzzer::Evaluator, - inputs::Input, - mutators::Mutator, + inputs::{Input, UsesInput}, + mark_feature_time, + mutators::{MutationResult, Mutator}, schedulers::{testcase_score::CorpusPowerTestcaseScore, TestcaseScore}, - stages::{mutational::MutatedTransform, MutationalStage, RetryCountRestartHelper, Stage}, - state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, UsesState}, + stages::{ + mutational::{MutatedTransform, MutatedTransformPost}, + MutationalStage, RetryCountRestartHelper, Stage, + }, + start_timer, + state::{ + HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, MaybeHasClientPerfMonitor, UsesState, + }, Error, HasMetadata, HasNamedMetadata, }; @@ -26,55 +35,41 @@ static mut POWER_MUTATIONAL_STAGE_ID: usize = 0; pub const POWER_MUTATIONAL_STAGE_NAME: &str = "power"; /// The mutational stage using power schedules #[derive(Clone, Debug)] -pub struct PowerMutationalStage { +pub struct PowerMutationalStage { name: Cow<'static, str>, /// The mutators we use mutator: M, #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, F, EM, I, Z)>, + phantom: PhantomData<(E, F, EM, I, S, Z)>, } -impl UsesState for PowerMutationalStage -where - E: UsesState, -{ - type State = E::State; -} - -impl Named for PowerMutationalStage { +impl Named for PowerMutationalStage { fn name(&self) -> &Cow<'static, str> { &self.name } } -impl MutationalStage for PowerMutationalStage +impl MutationalStage for PowerMutationalStage where - E: Executor + HasObservers, - EM: UsesState, - F: TestcaseScore, - I: Input, - M: Mutator, - E::State: - HasCorpus + HasMetadata + HasRand + HasExecutions + HasNamedMetadata + HasCurrentTestcase, - Z: Evaluator, - I: MutatedTransform + Clone, - <::State as HasCorpus>::Corpus: Corpus, //delete me + S: HasCurrentTestcase, + F: TestcaseScore, { + type Mutator = M; /// The mutator, added to this stage #[inline] - fn mutator(&self) -> &M { + fn mutator(&self) -> &Self::Mutator { &self.mutator } /// The list of mutators, added to this stage (as mutable ref) #[inline] - fn mutator_mut(&mut self) -> &mut M { + fn mutator_mut(&mut self) -> &mut Self::Mutator { &mut self.mutator } /// Gets the number of iterations as a random number #[allow(clippy::cast_sign_loss)] - fn iterations(&self, state: &mut Self::State) -> Result { + fn iterations(&self, state: &mut S) -> Result { // Update handicap let mut testcase = state.current_testcase_mut()?; let score = F::compute(state, &mut testcase)? as usize; @@ -83,17 +78,24 @@ where } } -impl Stage for PowerMutationalStage +impl Stage for PowerMutationalStage where - E: Executor + HasObservers, - EM: UsesState, - F: TestcaseScore, - M: Mutator, - E::State: - HasCorpus + HasMetadata + HasRand + HasExecutions + HasNamedMetadata + HasCurrentTestcase, - Z: Evaluator, - I: MutatedTransform + Clone + Input, - <::State as HasCorpus>::Corpus: Corpus, //delete me + E: Executor + HasObservers, + EM: UsesState, + F: TestcaseScore, + M: Mutator, + S: HasCorpus + + HasMetadata + + HasRand + + HasExecutions + + HasNamedMetadata + + HasCurrentTestcase + + HasCurrentCorpusId + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + Z: Evaluator, + I: MutatedTransform<::Input, S> + Clone + Input, + ::Input: Input, { #[inline] #[allow(clippy::let_and_return)] @@ -101,32 +103,39 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { let ret = self.perform_mutational(fuzzer, executor, state, manager); ret } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { // Make sure we don't get stuck crashing on a single testcase RetryCountRestartHelper::should_restart(state, &self.name, 3) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { RetryCountRestartHelper::clear_progress(state, &self.name) } } -impl PowerMutationalStage +impl PowerMutationalStage where - E: Executor + HasObservers, - EM: UsesState::State>, - F: TestcaseScore<::State>, + E: Executor + HasObservers, + EM: UsesState, + F: TestcaseScore, I: Input, - M: Mutator::State>, - ::State: HasCorpus + HasMetadata + HasRand, - Z: Evaluator::State>, + M: Mutator, + S: HasCorpus + + HasMetadata + + HasRand + + HasCurrentTestcase + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + I: MutatedTransform<::Input, S> + Clone + Input, + Z: Evaluator, + ::Input: Input, { /// Creates a new [`PowerMutationalStage`] pub fn new(mutator: M) -> Self { @@ -144,8 +153,58 @@ where phantom: PhantomData, } } + + /// Runs this (mutational) stage for the given testcase + #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... + fn perform_mutational( + &mut self, + fuzzer: &mut Z, + executor: &mut E, + state: &mut S, + manager: &mut EM, + ) -> Result<(), Error> { + start_timer!(state); + + // Here saturating_sub is needed as self.iterations() might be actually smaller than the previous value before reset. + /* + let num = self + .iterations(state)? + .saturating_sub(self.execs_since_progress_start(state)?); + */ + let num = self.iterations(state)?; + let mut testcase = state.current_testcase_mut()?; + + let Ok(input) = I::try_transform_from(&mut testcase, state) else { + return Ok(()); + }; + drop(testcase); + mark_feature_time!(state, PerfFeature::GetInputFromCorpus); + + for _ in 0..num { + let mut input = input.clone(); + + start_timer!(state); + let mutated = self.mutator_mut().mutate(state, &mut input)?; + mark_feature_time!(state, PerfFeature::Mutate); + + if mutated == MutationResult::Skipped { + continue; + } + + // Time is measured directly the `evaluate_input` function + let (untransformed, post) = input.try_transform_into(state)?; + let (_, corpus_id) = fuzzer.evaluate_input(state, executor, manager, untransformed)?; + + start_timer!(state); + self.mutator_mut().post_exec(state, corpus_id)?; + post.post_exec(state, corpus_id)?; + mark_feature_time!(state, PerfFeature::MutatePostExec); + } + + Ok(()) + } } /// The standard powerscheduling stage -pub type StdPowerMutationalStage = - PowerMutationalStage; +pub type StdPowerMutationalStage = + PowerMutationalStage; diff --git a/libafl/src/stages/push/mod.rs b/libafl/src/stages/push/mod.rs index a8304962e1..cbbb456eff 100644 --- a/libafl/src/stages/push/mod.rs +++ b/libafl/src/stages/push/mod.rs @@ -8,62 +8,51 @@ /// Mutational stage is the normal fuzzing stage. pub mod mutational; -use alloc::rc::Rc; +use alloc::{ + borrow::{Cow, ToOwned}, + rc::Rc, + string::ToString, +}; use core::{ cell::{Cell, RefCell}, marker::PhantomData, - time::Duration, }; +use libafl_bolts::Named; pub use mutational::StdMutationalPushStage; use crate::{ - corpus::CorpusId, + common::HasNamedMetadata, + corpus::{Corpus, CorpusId, HasCurrentCorpusId}, events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter}, - executors::ExitKind, + executors::{Executor, ExitKind, HasObservers}, inputs::UsesInput, observers::ObserversTuple, schedulers::Scheduler, + stages::{RetryCountRestartHelper, Stage}, state::{HasCorpus, HasExecutions, HasLastReportTime, HasRand}, - Error, EvaluatorObservers, ExecutionProcessor, HasMetadata, HasScheduler, + Error, EvaluatorObservers, ExecutesInput, ExecutionProcessor, HasMetadata, HasScheduler, }; -/// Send a monitor update all 15 (or more) seconds -const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15); - // The shared state for all [`PushStage`]s /// Should be stored inside a `[Rc>`] #[derive(Clone, Debug)] -pub struct PushStageSharedState -where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - OT: ObserversTuple, - Z::State: HasRand + HasCorpus, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, -{ +pub struct PushStageSharedState { /// The [`crate::state::State`] - pub state: Z::State, + pub state: S, /// The [`crate::fuzzer::Fuzzer`] instance pub fuzzer: Z, /// The [`crate::events::EventManager`] pub event_mgr: EM, /// The [`crate::observers::ObserversTuple`] pub observers: OT, - phantom: PhantomData<(CS, Z)>, + phantom: PhantomData, } -impl PushStageSharedState -where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - OT: ObserversTuple, - Z::State: HasRand + HasCorpus, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, -{ +impl PushStageSharedState { /// Create a new `PushStageSharedState` that can be used by all [`PushStage`]s #[must_use] - pub fn new(fuzzer: Z, state: Z::State, observers: OT, event_mgr: EM) -> Self { + pub fn new(fuzzer: Z, state: S, observers: OT, event_mgr: EM) -> Self { Self { state, fuzzer, @@ -76,20 +65,13 @@ where /// Helper class for the [`PushStage`] trait, taking care of borrowing the shared state #[derive(Clone, Debug)] -pub struct PushStageHelper -where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - OT: ObserversTuple, - Z::State: HasRand + HasCorpus, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, -{ +pub struct PushStageHelper { /// If this stage has already been initalized. /// This gets reset to `false` after one iteration of the stage is done. pub initialized: bool, /// The shared state, keeping track of the corpus and the fuzzer #[allow(clippy::type_complexity)] - pub shared_state: Rc>>>, + pub shared_state: Rc>>>, /// If the last iteration failed pub errored: bool, @@ -97,32 +79,22 @@ where pub current_corpus_id: Option, /// The input we just ran - pub current_input: Option<::Input>, // Todo: Get rid of copy + pub current_input: Option, // Todo: Get rid of copy - #[allow(clippy::type_complexity)] - phantom: PhantomData<(CS, EM, OT, Z)>, exit_kind: Rc>>, } -impl PushStageHelper -where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - OT: ObserversTuple, - Z::State: HasRand + HasCorpus, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, -{ +impl PushStageHelper { /// Create a new [`PushStageHelper`] #[must_use] #[allow(clippy::type_complexity)] pub fn new( - shared_state: Rc>>>, + shared_state: Rc>>>, exit_kind_ref: Rc>>, ) -> Self { Self { shared_state, initialized: false, - phantom: PhantomData, exit_kind: exit_kind_ref, errored: false, current_input: None, @@ -132,14 +104,14 @@ where /// Sets the shared state for this helper (and all other helpers owning the same [`RefCell`]) #[inline] - pub fn set_shared_state(&mut self, shared_state: PushStageSharedState) { + pub fn set_shared_state(&mut self, shared_state: PushStageSharedState) { (*self.shared_state.borrow_mut()).replace(shared_state); } /// Takes the shared state from this helper, replacing it with `None` #[inline] #[allow(clippy::type_complexity)] - pub fn take_shared_state(&mut self) -> Option> { + pub fn take_shared_state(&mut self) -> Option> { let shared_state_ref = &mut (*self.shared_state).borrow_mut(); shared_state_ref.take() } @@ -158,7 +130,7 @@ where } /// Resets this state after a full stage iter. - fn end_of_iter(&mut self, shared_state: PushStageSharedState, errored: bool) { + fn end_of_iter(&mut self, shared_state: PushStageSharedState, errored: bool) { self.set_shared_state(shared_state); self.errored = errored; self.current_corpus_id = None; @@ -171,18 +143,11 @@ where /// A push stage is a generator that returns a single testcase for each call. /// It's an iterator so we can chain it. /// After it has finished once, we will call it agan for the next fuzzer round. -pub trait PushStage: Iterator -where - CS: Scheduler, - Z::State: HasRand + HasExecutions + HasMetadata + HasCorpus + HasLastReportTime, - EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, - OT: ObserversTuple, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, -{ +pub trait PushStage { /// Gets the [`PushStageHelper`] - fn push_stage_helper(&self) -> &PushStageHelper; + fn push_stage_helper(&self) -> &PushStageHelper; /// Gets the [`PushStageHelper`] (mutable) - fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper; + fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper; /// Set the current corpus index this stage works on fn set_current_corpus_id(&mut self, corpus_id: CorpusId) { @@ -196,7 +161,7 @@ where fn init( &mut self, _fuzzer: &mut Z, - _state: &mut Z::State, + _state: &mut S, _event_mgr: &mut EM, _observers: &mut OT, ) -> Result<(), Error> { @@ -209,20 +174,20 @@ where fn pre_exec( &mut self, _fuzzer: &mut Z, - _state: &mut Z::State, + _state: &mut S, _event_mgr: &mut EM, _observers: &mut OT, - ) -> Option::Input, Error>>; + ) -> Option>; /// Called after the execution of a testcase finished. #[inline] fn post_exec( &mut self, _fuzzer: &mut Z, - _state: &mut Z::State, + _state: &mut S, _event_mgr: &mut EM, _observers: &mut OT, - _input: ::Input, + _input: I, _exit_kind: ExitKind, ) -> Result<(), Error> { Ok(()) @@ -233,80 +198,127 @@ where fn deinit( &mut self, _fuzzer: &mut Z, - _state: &mut Z::State, + _state: &mut S, _event_mgr: &mut EM, _observers: &mut OT, ) -> Result<(), Error> { Ok(()) } +} - /// This is the default implementation for `next` for this stage - fn next_std(&mut self) -> Option::Input, Error>> { - let mut shared_state = { - let shared_state_ref = &mut (*self.push_stage_helper_mut().shared_state).borrow_mut(); - shared_state_ref.take().unwrap() +/// Allows us to use a [`PushStage`] as a normal [`Stage`] +#[allow(clippy::type_complexity)] +#[derive(Debug)] +pub struct PushStageAdapter { + name: Cow<'static, str>, + push_stage: PS, + phantom: PhantomData<(CS, EM, OT, Z)>, +} + +impl PushStageAdapter { + /// Create a new [`PushStageAdapter`], wrapping the given [`PushStage`] + /// to be used as a normal [`Stage`] + #[must_use] + pub fn new(push_stage: PS) -> Self { + // unsafe but impossible that you create two threads both instantiating this instance + let stage_id = unsafe { + let ret = PUSH_STAGE_ADAPTER_ID; + PUSH_STAGE_ADAPTER_ID += 1; + ret }; - - let step_success = if self.push_stage_helper().initialized { - // We already ran once - - let last_input = self.push_stage_helper_mut().current_input.take().unwrap(); - - self.post_exec( - &mut shared_state.fuzzer, - &mut shared_state.state, - &mut shared_state.event_mgr, - &mut shared_state.observers, - last_input, - self.push_stage_helper().exit_kind().unwrap(), - ) - } else { - self.init( - &mut shared_state.fuzzer, - &mut shared_state.state, - &mut shared_state.event_mgr, - &mut shared_state.observers, - ) - }; - if let Err(err) = step_success { - self.push_stage_helper_mut().end_of_iter(shared_state, true); - return Some(Err(err)); + Self { + name: Cow::Owned( + PUSH_STAGE_ADAPTER_NAME.to_owned() + ":" + stage_id.to_string().as_str(), + ), + push_stage, + phantom: PhantomData, } - - //for i in 0..num { - let ret = self.pre_exec( - &mut shared_state.fuzzer, - &mut shared_state.state, - &mut shared_state.event_mgr, - &mut shared_state.observers, - ); - if ret.is_none() { - // We're done. - drop(self.push_stage_helper_mut().current_input.take()); - self.push_stage_helper_mut().initialized = false; - - if let Err(err) = self.deinit( - &mut shared_state.fuzzer, - &mut shared_state.state, - &mut shared_state.event_mgr, - &mut shared_state.observers, - ) { - self.push_stage_helper_mut().end_of_iter(shared_state, true); - return Some(Err(err)); - }; - - if let Err(err) = shared_state - .event_mgr - .maybe_report_progress(&mut shared_state.state, STATS_TIMEOUT_DEFAULT) - { - self.push_stage_helper_mut().end_of_iter(shared_state, true); - return Some(Err(err)); - }; - } else { - self.push_stage_helper_mut().reset_exit_kind(); - } - self.push_stage_helper_mut() - .end_of_iter(shared_state, false); - ret + } +} +/// The unique counter for this stage +static mut PUSH_STAGE_ADAPTER_ID: usize = 0; +/// The name for push stage adapter +pub static PUSH_STAGE_ADAPTER_NAME: &str = "pushstageadapter"; + +impl Named for PushStageAdapter { + #[must_use] + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +impl Stage for PushStageAdapter +where + CS: Scheduler<::Input, S>, + S: HasExecutions + + HasRand + + HasCorpus + + HasLastReportTime + + HasCurrentCorpusId + + HasNamedMetadata + + HasMetadata + + UsesInput::Input>, + E: Executor + HasObservers, + EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, + OT: ObserversTuple<::Input, S>, + PS: PushStage::Input, OT, S, Z>, + Z: ExecutesInput + + ExecutionProcessor + + EvaluatorObservers + + HasScheduler, +{ + fn perform( + &mut self, + fuzzer: &mut Z, + executor: &mut E, + state: &mut S, + event_mgr: &mut EM, + ) -> Result<(), Error> { + let push_stage = &mut self.push_stage; + + let Some(corpus_id) = state.current_corpus_id()? else { + return Err(Error::illegal_state( + "state is not currently processing a corpus index", + )); + }; + + push_stage.set_current_corpus_id(corpus_id); + + push_stage.init(fuzzer, state, event_mgr, &mut *executor.observers_mut())?; + + loop { + let input = + match push_stage.pre_exec(fuzzer, state, event_mgr, &mut *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, + &mut *executor.observers_mut(), + input, + exit_kind, + )?; + } + + self.push_stage + .deinit(fuzzer, state, event_mgr, &mut *executor.observers_mut()) + } + + #[inline] + fn should_restart(&mut self, state: &mut S) -> Result { + // TODO: Proper restart handling - call post_exec at the right time, etc... + RetryCountRestartHelper::no_retry(state, &self.name) + } + + #[inline] + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { + RetryCountRestartHelper::clear_progress(state, &self.name) } } diff --git a/libafl/src/stages/push/mutational.rs b/libafl/src/stages/push/mutational.rs index 73d73703de..d3d35f8b50 100644 --- a/libafl/src/stages/push/mutational.rs +++ b/libafl/src/stages/push/mutational.rs @@ -11,22 +11,23 @@ use libafl_bolts::rands::Rand; use serde::Serialize; use super::{PushStage, PushStageHelper, PushStageSharedState}; +#[cfg(feature = "introspection")] +use crate::monitors::PerfFeature; use crate::{ corpus::{Corpus, CorpusId}, - events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter}, + events::{EventFirer, ProgressReporter}, executors::ExitKind, - inputs::UsesInput, + fuzzer::STATS_TIMEOUT_DEFAULT, + inputs::{Input, UsesInput}, mark_feature_time, mutators::Mutator, nonzero, observers::ObserversTuple, schedulers::Scheduler, start_timer, - state::{HasCorpus, HasExecutions, HasLastReportTime, HasRand, UsesState}, - Error, EvaluatorObservers, ExecutionProcessor, HasMetadata, HasScheduler, + state::{HasCorpus, HasExecutions, HasLastReportTime, HasRand, MaybeHasClientPerfMonitor}, + Error, ExecutionProcessor, HasMetadata, HasScheduler, }; -#[cfg(feature = "introspection")] -use crate::{monitors::PerfFeature, state::HasClientPerfMonitor}; /// The default maximum number of mutations to perform per input. pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128; @@ -42,14 +43,10 @@ pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128; /// /// The default mutational push stage #[derive(Clone, Debug)] -pub struct StdMutationalPushStage +pub struct StdMutationalPushStage where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - M: Mutator, - OT: ObserversTuple + Serialize, - Z::State: HasRand + HasCorpus + Clone + Debug, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + S: HasCorpus, + ::Input: Clone + Debug, { current_corpus_id: Option, testcases_to_do: usize, @@ -57,21 +54,17 @@ where mutator: M, - psh: PushStageHelper, + psh: PushStageHelper::Input, OT, S, Z>, } -impl StdMutationalPushStage +impl StdMutationalPushStage where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - M: Mutator, - OT: ObserversTuple + Serialize, - Z::State: HasCorpus + HasRand + Clone + Debug, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + S: HasCorpus + HasRand, + ::Input: Clone + Debug, { /// Gets the number of iterations as a random number #[allow(clippy::unused_self, clippy::unnecessary_wraps)] // TODO: we should put this function into a trait later - fn iterations(&self, state: &mut Z::State, _corpus_id: CorpusId) -> Result { + fn iterations(&self, state: &mut S, _corpus_id: CorpusId) -> Result { Ok(1 + state .rand_mut() .below(nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS))) @@ -83,23 +76,28 @@ where } } -impl PushStage for StdMutationalPushStage +impl PushStage::Input, OT, S, Z> + for StdMutationalPushStage where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, - M: Mutator, - OT: ObserversTuple + Serialize, - Z::State: HasCorpus + HasRand + HasExecutions + HasLastReportTime + HasMetadata + Clone + Debug, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, - <::State as HasCorpus>::Corpus: Corpus, //delete me + EM: EventFirer, + Z: HasScheduler + ExecutionProcessor, + S: HasCorpus + + UsesInput::Input> + + HasRand + + MaybeHasClientPerfMonitor, + M: Mutator<::Input, S>, + OT: ObserversTuple<::Input, S> + Serialize, + ::Input: Input + Clone, { #[inline] - fn push_stage_helper(&self) -> &PushStageHelper { + fn push_stage_helper(&self) -> &PushStageHelper::Input, OT, S, Z> { &self.psh } #[inline] - fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper { + fn push_stage_helper_mut( + &mut self, + ) -> &mut PushStageHelper::Input, OT, S, Z> { &mut self.psh } @@ -107,7 +105,7 @@ where fn init( &mut self, fuzzer: &mut Z, - state: &mut Z::State, + state: &mut S, _event_mgr: &mut EM, _observers: &mut OT, ) -> Result<(), Error> { @@ -126,10 +124,10 @@ where fn pre_exec( &mut self, _fuzzer: &mut Z, - state: &mut Z::State, + state: &mut S, _event_mgr: &mut EM, _observers: &mut OT, - ) -> Option::Input, Error>> { + ) -> Option::Input, Error>> { if self.testcases_done >= self.testcases_to_do { // finished with this cicle. return None; @@ -161,10 +159,10 @@ where fn post_exec( &mut self, fuzzer: &mut Z, - state: &mut Z::State, + state: &mut S, event_mgr: &mut EM, observers: &mut OT, - last_input: ::Input, + last_input: ::Input, exit_kind: ExitKind, ) -> Result<(), Error> { // todo: is_interesting, etc. @@ -183,7 +181,7 @@ where fn deinit( &mut self, _fuzzer: &mut Z, - _state: &mut Z::State, + _state: &mut S, _event_mgr: &mut EM, _observers: &mut OT, ) -> Result<(), Error> { @@ -192,38 +190,51 @@ where } } -impl Iterator for StdMutationalPushStage +impl Iterator for StdMutationalPushStage where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, - M: Mutator, - OT: ObserversTuple + Serialize, - Z::State: HasCorpus + HasRand + HasExecutions + HasMetadata + HasLastReportTime + Clone + Debug, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, - <::State as HasCorpus>::Corpus: Corpus, //delete me + EM: ProgressReporter, + S: HasCorpus + + HasMetadata + + HasExecutions + + HasLastReportTime + + HasRand + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + OT: ObserversTuple<::Input, S> + Serialize, + M: Mutator<::Input, S>, + ::Input: Clone + Debug + Input, + Z: HasScheduler + ExecutionProcessor, { - type Item = Result<::Input, Error>; + type Item = Result<::Input, Error>; - fn next(&mut self) -> Option::Input, Error>> { + fn next(&mut self) -> Option::Input, Error>> { self.next_std() } } -impl StdMutationalPushStage +impl StdMutationalPushStage where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - M: Mutator, - OT: ObserversTuple + Serialize, - Z::State: HasCorpus + HasRand + Clone + Debug, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + EM: ProgressReporter, + S: HasCorpus + + HasMetadata + + HasExecutions + + HasLastReportTime + + HasRand + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + OT: ObserversTuple<::Input, S> + Serialize, + M: Mutator<::Input, S>, + ::Input: Clone + Debug + Input, + Z: HasScheduler + ExecutionProcessor, { /// Creates a new default mutational stage #[must_use] #[allow(clippy::type_complexity)] pub fn new( mutator: M, - shared_state: Rc>>>, + shared_state: Rc< + RefCell::Input, OT, S, Z>>>, + >, exit_kind: Rc>>, ) -> Self { Self { @@ -234,4 +245,74 @@ where testcases_done: 0, } } + + /// This is the implementation for `next` for this stage + pub fn next_std(&mut self) -> Option::Input, Error>> { + let mut shared_state = { + let shared_state_ref = &mut (*self.push_stage_helper_mut().shared_state).borrow_mut(); + shared_state_ref.take().unwrap() + }; + + let step_success = if self.push_stage_helper().initialized { + // We already ran once + + let last_input = self.push_stage_helper_mut().current_input.take().unwrap(); + + self.post_exec( + &mut shared_state.fuzzer, + &mut shared_state.state, + &mut shared_state.event_mgr, + &mut shared_state.observers, + last_input, + self.push_stage_helper().exit_kind().unwrap(), + ) + } else { + self.init( + &mut shared_state.fuzzer, + &mut shared_state.state, + &mut shared_state.event_mgr, + &mut shared_state.observers, + ) + }; + if let Err(err) = step_success { + self.push_stage_helper_mut().end_of_iter(shared_state, true); + return Some(Err(err)); + } + + //for i in 0..num { + let ret = self.pre_exec( + &mut shared_state.fuzzer, + &mut shared_state.state, + &mut shared_state.event_mgr, + &mut shared_state.observers, + ); + if ret.is_none() { + // We're done. + drop(self.push_stage_helper_mut().current_input.take()); + self.push_stage_helper_mut().initialized = false; + + if let Err(err) = self.deinit( + &mut shared_state.fuzzer, + &mut shared_state.state, + &mut shared_state.event_mgr, + &mut shared_state.observers, + ) { + self.push_stage_helper_mut().end_of_iter(shared_state, true); + return Some(Err(err)); + }; + + if let Err(err) = shared_state + .event_mgr + .maybe_report_progress(&mut shared_state.state, STATS_TIMEOUT_DEFAULT) + { + self.push_stage_helper_mut().end_of_iter(shared_state, true); + return Some(Err(err)); + }; + } else { + self.push_stage_helper_mut().reset_exit_kind(); + } + self.push_stage_helper_mut() + .end_of_iter(shared_state, false); + ret + } } diff --git a/libafl/src/stages/stats.rs b/libafl/src/stages/stats.rs deleted file mode 100644 index 6be3de2fd7..0000000000 --- a/libafl/src/stages/stats.rs +++ /dev/null @@ -1,181 +0,0 @@ -//! Stage to compute/report minimal AFL-like stats - -#[cfg(feature = "std")] -use alloc::{borrow::Cow, string::ToString}; -use core::{marker::PhantomData, time::Duration}; - -use libafl_bolts::current_time; -#[cfg(feature = "std")] -use serde_json::json; - -use crate::{ - corpus::{Corpus, HasCurrentCorpusId}, - events::EventFirer, - schedulers::minimizer::IsFavoredMetadata, - stages::Stage, - state::{HasCorpus, HasImported, UsesState}, - Error, HasMetadata, -}; -#[cfg(feature = "std")] -use crate::{ - events::Event, - monitors::{AggregatorOps, UserStats, UserStatsValue}, -}; - -/// The [`StatsStage`] is a simple stage that computes and reports some stats. -#[derive(Debug, Clone)] -pub struct StatsStage { - // the number of testcases that have been fuzzed - has_fuzzed_size: usize, - // the number of "favored" testcases - is_favored_size: usize, - // the number of testcases found by itself - own_finds_size: usize, - // the number of testcases imported by other fuzzers - imported_size: usize, - // the last time that we report all stats - last_report_time: Duration, - // the interval that we report all stats - stats_report_interval: Duration, - - phantom: PhantomData<(E, EM, Z)>, -} - -impl UsesState for StatsStage -where - E: UsesState, -{ - type State = E::State; -} - -impl Stage for StatsStage -where - E: UsesState, - EM: EventFirer, - Z: UsesState, - Self::State: HasImported + HasCorpus + HasMetadata, -{ - fn perform( - &mut self, - _fuzzer: &mut Z, - _executor: &mut E, - state: &mut Self::State, - _manager: &mut EM, - ) -> Result<(), Error> { - self.update_and_report_afl_stats(state, _manager) - } - - #[inline] - fn should_restart(&mut self, _state: &mut Self::State) -> Result { - // Not running the target so we wont't crash/timeout and, hence, don't need to restore anything - Ok(true) - } - - #[inline] - fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> { - // Not running the target so we wont't crash/timeout and, hence, don't need to restore anything - Ok(()) - } -} - -impl StatsStage { - fn update_and_report_afl_stats( - &mut self, - state: &mut ::State, - _manager: &mut EM, - ) -> Result<(), Error> - where - E: UsesState, - EM: EventFirer, - ::State: HasCorpus + HasImported, - { - let Some(corpus_id) = state.current_corpus_id()? else { - return Err(Error::illegal_state( - "state is not currently processing a corpus index", - )); - }; - - // Report your stats every `STATS_REPORT_INTERVAL` - // compute pending, pending_favored, imported, own_finds - { - let testcase = state.corpus().get(corpus_id)?.borrow(); - if testcase.scheduled_count() == 0 { - self.has_fuzzed_size += 1; - if testcase.has_metadata::() { - self.is_favored_size += 1; - } - } else { - return Ok(()); - } - } - - let corpus_size = state.corpus().count(); - let pending_size = corpus_size - self.has_fuzzed_size; - let pend_favored_size = corpus_size - self.is_favored_size; - self.imported_size = *state.imported(); - self.own_finds_size = corpus_size - self.imported_size; - - let cur = current_time(); - - if cur.checked_sub(self.last_report_time).unwrap_or_default() > self.stats_report_interval { - #[cfg(feature = "std")] - { - let json = json!({ - "pending":pending_size, - "pend_fav":pend_favored_size, - "own_finds":self.own_finds_size, - "imported":self.imported_size, - }); - _manager.fire( - state, - Event::UpdateUserStats { - name: Cow::from("Stats"), - value: UserStats::new( - UserStatsValue::String(Cow::from(json.to_string())), - AggregatorOps::None, - ), - phantom: PhantomData, - }, - )?; - } - #[cfg(not(feature = "std"))] - log::info!( - "pending: {}, pend_favored: {}, own_finds: {}, imported: {}", - pending_size, - pend_favored_size, - self.own_finds_size, - self.imported_size - ); - self.last_report_time = cur; - } - - Ok(()) - } -} - -impl StatsStage { - /// create a new instance of the [`StatsStage`] - #[must_use] - pub fn new(interval: Duration) -> Self { - Self { - stats_report_interval: interval, - ..Default::default() - } - } -} - -impl Default for StatsStage { - /// the default instance of the [`StatsStage`] - #[must_use] - fn default() -> Self { - Self { - has_fuzzed_size: 0, - is_favored_size: 0, - own_finds_size: 0, - imported_size: 0, - last_report_time: current_time(), - stats_report_interval: Duration::from_secs(15), - phantom: PhantomData, - } - } -} diff --git a/libafl/src/stages/sync.rs b/libafl/src/stages/sync.rs index 3dbed175a2..b4cc5fcec0 100644 --- a/libafl/src/stages/sync.rs +++ b/libafl/src/stages/sync.rs @@ -10,16 +10,14 @@ use std::path::{Path, PathBuf}; use libafl_bolts::{current_time, fs::find_new_files_rec, shmem::ShMemProvider, Named}; use serde::{Deserialize, Serialize}; -#[cfg(feature = "introspection")] -use crate::state::HasClientPerfMonitor; use crate::{ - corpus::{Corpus, CorpusId}, + corpus::{Corpus, CorpusId, HasCurrentCorpusId}, events::{llmp::LlmpEventConverter, Event, EventConfig, EventFirer}, executors::{Executor, ExitKind, HasObservers}, fuzzer::{Evaluator, EvaluatorObservers, ExecutionProcessor}, inputs::{Input, InputConverter, UsesInput}, stages::{RetryCountRestartHelper, Stage}, - state::{HasCorpus, HasExecutions, HasRand, State, UsesState}, + state::{HasCorpus, HasExecutions, HasRand, MaybeHasClientPerfMonitor, State, Stoppable}, Error, HasMetadata, HasNamedMetadata, }; @@ -54,41 +52,38 @@ impl SyncFromDiskMetadata { /// A stage that loads testcases from disk to sync with other fuzzers such as AFL++ #[derive(Debug)] -pub struct SyncFromDiskStage { +pub struct SyncFromDiskStage { name: Cow<'static, str>, sync_dirs: Vec, load_callback: CB, interval: Duration, - phantom: PhantomData<(E, EM, Z)>, + phantom: PhantomData<(E, EM, S, Z)>, } -impl UsesState for SyncFromDiskStage -where - Z: UsesState, -{ - type State = Z::State; -} - -impl Named for SyncFromDiskStage { +impl Named for SyncFromDiskStage { fn name(&self) -> &Cow<'static, str> { &self.name } } -impl Stage for SyncFromDiskStage +impl Stage for SyncFromDiskStage where - CB: FnMut(&mut Z, &mut Self::State, &Path) -> Result<::Input, Error>, - E: UsesState, - EM: UsesState, - Z: Evaluator, - Self::State: HasCorpus + HasRand + HasMetadata + HasNamedMetadata, + CB: FnMut(&mut Z, &mut S, &Path) -> Result<::Input, Error>, + Z: Evaluator, + S: HasCorpus + + HasRand + + HasMetadata + + HasNamedMetadata + + UsesInput::Input> + + HasCurrentCorpusId + + MaybeHasClientPerfMonitor, { #[inline] fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { let last = state @@ -144,19 +139,19 @@ where } #[inline] - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { // TODO: Needs proper crash handling for when an imported testcase crashes // For now, Make sure we don't get stuck crashing on this testcase RetryCountRestartHelper::no_retry(state, &self.name) } #[inline] - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { RetryCountRestartHelper::clear_progress(state, &self.name) } } -impl SyncFromDiskStage { +impl SyncFromDiskStage { /// Creates a new [`SyncFromDiskStage`] #[must_use] pub fn new(sync_dirs: Vec, load_callback: CB, interval: Duration, name: &str) -> Self { @@ -174,10 +169,8 @@ impl SyncFromDiskStage { pub type SyncFromDiskFunction = fn(&mut Z, &mut S, &Path) -> Result<::Input, Error>; -impl SyncFromDiskStage, E, EM, Z> +impl SyncFromDiskStage, E, EM, S, Z> where - E: UsesState::State>, - EM: UsesState::State>, Z: Evaluator, { /// Creates a new [`SyncFromDiskStage`] invoking `Input::from_file` to load inputs @@ -234,38 +227,31 @@ where client: LlmpEventConverter, } -impl UsesState for SyncFromBrokerStage +impl Stage for SyncFromBrokerStage where - SP: ShMemProvider + 'static, - S: State, - IC: InputConverter, - ICB: InputConverter, - DI: Input, -{ - type State = S; -} - -impl Stage for SyncFromBrokerStage -where - EM: UsesState + EventFirer, - S: State + HasExecutions + HasCorpus + HasRand + HasMetadata, + EM: EventFirer, + S: HasExecutions + + HasCorpus + + HasRand + + HasMetadata + + Stoppable + + UsesInput::Input> + + State, SP: ShMemProvider, E: HasObservers + Executor, for<'a> E::Observers: Deserialize<'a>, - Z: EvaluatorObservers - + ExecutionProcessor, - IC: InputConverter, - ICB: InputConverter, + Z: EvaluatorObservers + ExecutionProcessor, + IC: InputConverter::Input, To = DI>, + ICB: InputConverter::Input>, DI: Input, - <::Corpus as Corpus>::Input: Clone, - S::Corpus: Corpus, // delete me + <::Corpus as Corpus>::Input: Input + Clone, { #[inline] fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { if self.client.can_convert() { @@ -319,13 +305,13 @@ where } #[inline] - fn should_restart(&mut self, _state: &mut Self::State) -> Result { + fn should_restart(&mut self, _state: &mut S) -> Result { // No restart handling needed - does not execute the target. Ok(true) } #[inline] - fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> { // Not needed - does not execute the target. Ok(()) } diff --git a/libafl/src/stages/time_tracker.rs b/libafl/src/stages/time_tracker.rs index ee08d0dec8..b39ae2cd49 100644 --- a/libafl/src/stages/time_tracker.rs +++ b/libafl/src/stages/time_tracker.rs @@ -3,12 +3,7 @@ use std::{marker::PhantomData, time::Duration}; use libafl_bolts::{current_time, Error}; -use crate::{ - inputs::UsesInput, - stages::Stage, - state::{State, UsesState}, - HasMetadata, -}; +use crate::{stages::Stage, HasMetadata}; /// Track an inner Stage's execution time #[derive(Debug)] pub struct TimeTrackingStageWrapper { @@ -28,27 +23,17 @@ impl TimeTrackingStageWrapper { } } -impl UsesState for TimeTrackingStageWrapper +impl Stage for TimeTrackingStageWrapper where - S: State + HasMetadata, -{ - type State = S; -} - -impl Stage for TimeTrackingStageWrapper -where - S: UsesInput + State + HasMetadata, - ST: Stage, - M: UsesState, - Z: UsesState, - E: UsesState, + S: HasMetadata, + ST: Stage, T: libafl_bolts::serdeany::SerdeAny + From, { fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut M, ) -> Result<(), Error> { let before_run = current_time(); @@ -59,11 +44,11 @@ where Ok(()) } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { self.inner.should_restart(state) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { self.inner.clear_progress(state) } @@ -71,7 +56,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut M, ) -> Result<(), Error> { self.inner diff --git a/libafl/src/stages/tmin.rs b/libafl/src/stages/tmin.rs index d77299e73f..e7d072e486 100644 --- a/libafl/src/stages/tmin.rs +++ b/libafl/src/stages/tmin.rs @@ -1,4 +1,4 @@ -//! The [`TMinMutationalStage`] is a stage which will attempt to minimize corpus entries. +//! The [`StdTMinMutationalStage`] is a stage which will attempt to minimize corpus entries. use alloc::{ borrow::{Cow, ToOwned}, @@ -15,12 +15,14 @@ use serde::Serialize; #[cfg(feature = "track_hit_feedbacks")] use crate::feedbacks::premature_last_result_err; +#[cfg(feature = "introspection")] +use crate::monitors::PerfFeature; use crate::{ corpus::{Corpus, HasCurrentCorpusId, Testcase}, events::EventFirer, executors::{ExitKind, HasObservers}, feedbacks::{Feedback, FeedbackFactory, HasObserverHandle, StateInitializer}, - inputs::UsesInput, + inputs::{Input, UsesInput}, mark_feature_time, mutators::{MutationResult, Mutator}, observers::{MapObserver, ObserversTuple}, @@ -31,44 +33,137 @@ use crate::{ }, start_timer, state::{ - HasCorpus, HasCurrentTestcase, HasExecutions, HasMaxSize, HasSolutions, State, UsesState, + HasCorpus, HasCurrentTestcase, HasExecutions, HasMaxSize, HasSolutions, + MaybeHasClientPerfMonitor, State, UsesState, }, Error, ExecutesInput, ExecutionProcessor, HasFeedback, HasMetadata, HasNamedMetadata, HasScheduler, }; -#[cfg(feature = "introspection")] -use crate::{monitors::PerfFeature, state::HasClientPerfMonitor}; -/// Mutational stage which minimizes corpus entries. -/// -/// You must provide at least one mutator that actually reduces size. -pub trait TMinMutationalStage: - Stage + FeedbackFactory + +/// The default corpus entry minimising mutational stage +#[derive(Clone, Debug)] +pub struct StdTMinMutationalStage { + /// The name + name: Cow<'static, str>, + /// The mutator(s) this stage uses + mutator: M, + /// The factory + factory: FF, + /// The runs (=iterations) we are supposed to do + runs: usize, + /// The progress helper for this stage, keeping track of resumes after timeouts/crashes + restart_helper: ExecutionCountRestartHelper, + #[allow(clippy::type_complexity)] + phantom: PhantomData<(E, EM, F, S, Z)>, +} + +impl Stage for StdTMinMutationalStage where - E: UsesState + HasObservers, - E::Observers: ObserversTuple + Serialize, - EM: UsesState + EventFirer, - F: Feedback, - Self::State: HasMaxSize + HasCorpus + HasSolutions + HasExecutions + HasCurrentTestcase, - Self::Input: MutatedTransform + Clone + Hash + HasLen, - IP: Clone + MutatedTransformPost, - M: Mutator, - Z: UsesState - + HasScheduler - + HasFeedback + Z: HasScheduler + + ExecutionProcessor + ExecutesInput - + ExecutionProcessor, - Z::Feedback: Feedback, - Z::Scheduler: RemovableScheduler, - <::State as HasCorpus>::Corpus: Corpus, + + HasFeedback, + Z::Scheduler: RemovableScheduler<::Input, S>, + E: HasObservers + UsesState, + E::Observers: ObserversTuple<::Input, S> + Serialize, + EM: EventFirer, + FF: FeedbackFactory, + F: Feedback::Input, E::Observers, S>, + S: HasMetadata + + HasExecutions + + HasSolutions + + HasCorpus + + HasMaxSize + + HasNamedMetadata + + HasCurrentCorpusId + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + Z::Feedback: Feedback::Input, E::Observers, S>, + M: Mutator<::Input, S>, + <::Corpus as Corpus>::Input: Input + Hash + HasLen, { - /// The mutator registered for this stage - fn mutator(&self) -> &M; + fn should_restart(&mut self, state: &mut S) -> Result { + self.restart_helper.should_restart(state, &self.name) + } - /// The mutator registered for this stage (mutable) - fn mutator_mut(&mut self) -> &mut M; + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { + self.restart_helper.clear_progress(state, &self.name) + } - /// Gets the number of iterations this mutator should run for. - fn iterations(&self, state: &mut Self::State) -> Result; + fn perform( + &mut self, + fuzzer: &mut Z, + executor: &mut E, + state: &mut Z::State, + manager: &mut EM, + ) -> Result<(), Error> { + self.perform_minification(fuzzer, executor, state, manager)?; + + #[cfg(feature = "introspection")] + state.introspection_monitor_mut().finish_stage(); + + Ok(()) + } +} + +impl FeedbackFactory + for StdTMinMutationalStage +where + E: HasObservers, + FF: FeedbackFactory, +{ + fn create_feedback(&self, ctx: &E::Observers) -> F { + self.factory.create_feedback(ctx) + } +} + +impl Named for StdTMinMutationalStage { + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +/// The counter for giving this stage unique id +static mut TMIN_STAGE_ID: usize = 0; +/// The name for tmin stage +pub static TMIN_STAGE_NAME: &str = "tmin"; + +impl StdTMinMutationalStage +where + Z: HasScheduler + + ExecutionProcessor + + ExecutesInput + + HasFeedback, + Z::Scheduler: RemovableScheduler<::Input, S>, + E: HasObservers + UsesState, + E::Observers: ObserversTuple<::Input, S> + Serialize, + EM: EventFirer, + FF: FeedbackFactory, + F: Feedback::Input, E::Observers, S>, + S: HasMetadata + + HasExecutions + + HasSolutions + + HasCorpus + + HasMaxSize + + HasNamedMetadata + + HasCurrentTestcase + + HasCurrentCorpusId + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + Z::Feedback: Feedback::Input, E::Observers, S>, + M: Mutator<::Input, S>, + ::Input: Hash + HasLen + Input, +{ + /// The list of mutators, added to this stage (as mutable ref) + #[inline] + fn mutator_mut(&mut self) -> &mut M { + &mut self.mutator + } + + /// Gets the number of iterations from a fixed number of runs + fn iterations(&self, _state: &mut S) -> usize { + self.runs + } /// Runs this (mutational) stage for new objectives #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... @@ -76,7 +171,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { let Some(base_corpus_id) = state.current_corpus_id()? else { @@ -88,7 +183,7 @@ where let orig_max_size = state.max_size(); // basically copy-pasted from mutational.rs let num = self - .iterations(state)? + .iterations(state) .saturating_sub(usize::try_from(self.execs_since_progress_start(state)?)?); // If num is negative, then quit. @@ -97,8 +192,10 @@ where } start_timer!(state); - let transformed = - Self::Input::try_transform_from(state.current_testcase_mut()?.borrow_mut(), state)?; + let transformed = ::Input::try_transform_from( + state.current_testcase_mut()?.borrow_mut(), + state, + )?; let mut base = state.current_input_cloned()?; // potential post operation if base is replaced by a shorter input let mut base_post = None; @@ -159,7 +256,7 @@ where if feedback.is_interesting(state, manager, &input, &*observers, &exit_kind)? { // we found a reduced corpus entry! use the smaller base base = input; - base_post = Some(post.clone()); + base_post = Some(post); // do more runs! maybe we can minify further next_i = 0; @@ -210,144 +307,13 @@ where Ok(()) } - /// Gets the number of executions this mutator already did since it got first called in this fuzz round. - fn execs_since_progress_start(&mut self, state: &mut Self::State) -> Result; -} - -/// The default corpus entry minimising mutational stage -#[derive(Clone, Debug)] -pub struct StdTMinMutationalStage { - /// The name - name: Cow<'static, str>, - /// The mutator(s) this stage uses - mutator: M, - /// The factory - factory: FF, - /// The runs (=iterations) we are supposed to do - runs: usize, - /// The progress helper for this stage, keeping track of resumes after timeouts/crashes - restart_helper: ExecutionCountRestartHelper, - #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, EM, F, IP, Z)>, -} - -impl UsesState for StdTMinMutationalStage -where - Z: UsesState, -{ - type State = Z::State; -} - -impl Stage for StdTMinMutationalStage -where - Z: HasScheduler + ExecutionProcessor + ExecutesInput + HasFeedback, - Z::Scheduler: RemovableScheduler, - E: HasObservers + UsesState, - E::Observers: ObserversTuple + Serialize, - EM: EventFirer, - FF: FeedbackFactory, - F: Feedback, - Self::Input: MutatedTransform + Clone + HasLen + Hash, - Z::State: - HasMetadata + HasExecutions + HasSolutions + HasCorpus + HasMaxSize + HasNamedMetadata, - Z::Feedback: Feedback, - M: Mutator, - IP: MutatedTransformPost + Clone, - <::State as HasCorpus>::Corpus: Corpus, // delete me -{ - fn should_restart(&mut self, state: &mut Self::State) -> Result { - self.restart_helper.should_restart(state, &self.name) - } - - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { - self.restart_helper.clear_progress(state, &self.name) - } - - fn perform( - &mut self, - fuzzer: &mut Z, - executor: &mut E, - state: &mut Z::State, - manager: &mut EM, - ) -> Result<(), Error> { - self.perform_minification(fuzzer, executor, state, manager)?; - - #[cfg(feature = "introspection")] - state.introspection_monitor_mut().finish_stage(); - - Ok(()) - } -} - -impl FeedbackFactory - for StdTMinMutationalStage -where - E: HasObservers, - FF: FeedbackFactory, -{ - fn create_feedback(&self, ctx: &E::Observers) -> F { - self.factory.create_feedback(ctx) - } -} - -impl Named for StdTMinMutationalStage { - fn name(&self) -> &Cow<'static, str> { - &self.name - } -} - -/// The counter for giving this stage unique id -static mut TMIN_STAGE_ID: usize = 0; -/// The name for tmin stage -pub static TMIN_STAGE_NAME: &str = "tmin"; - -impl TMinMutationalStage - for StdTMinMutationalStage -where - Z: HasScheduler + ExecutionProcessor + ExecutesInput + HasFeedback, - Z::Scheduler: RemovableScheduler, - E: HasObservers + UsesState, - E::Observers: ObserversTuple + Serialize, - EM: EventFirer, - FF: FeedbackFactory, - F: Feedback, - Self::Input: MutatedTransform + Clone + HasLen + Hash, - Z::State: HasMetadata - + HasExecutions - + HasSolutions - + HasCorpus - + HasMaxSize - + HasNamedMetadata - + HasCurrentTestcase, - Z::Feedback: Feedback, - M: Mutator, - IP: MutatedTransformPost + Clone, - <::State as HasCorpus>::Corpus: Corpus, // delete me -{ - /// The mutator, added to this stage - #[inline] - fn mutator(&self) -> &M { - &self.mutator - } - - /// The list of mutators, added to this stage (as mutable ref) - #[inline] - fn mutator_mut(&mut self) -> &mut M { - &mut self.mutator - } - - /// Gets the number of iterations from a fixed number of runs - fn iterations(&self, _state: &mut Self::State) -> Result { - Ok(self.runs) - } - - fn execs_since_progress_start(&mut self, state: &mut Self::State) -> Result { + fn execs_since_progress_start(&mut self, state: &mut S) -> Result { self.restart_helper .execs_since_progress_start(state, &self.name) } } -impl StdTMinMutationalStage { +impl StdTMinMutationalStage { /// Creates a new minimizing mutational stage that will minimize provided corpus entries pub fn new(mutator: M, factory: FF, runs: usize) -> Self { // unsafe but impossible that you create two threads both instantiating this instance diff --git a/libafl/src/stages/tracing.rs b/libafl/src/stages/tracing.rs index 6c7fa6406e..b0a0442b4f 100644 --- a/libafl/src/stages/tracing.rs +++ b/libafl/src/stages/tracing.rs @@ -8,54 +8,47 @@ use core::{fmt::Debug, marker::PhantomData}; use libafl_bolts::Named; +#[cfg(feature = "introspection")] +use crate::monitors::PerfFeature; use crate::{ - corpus::Corpus, + corpus::{Corpus, HasCurrentCorpusId}, executors::{Executor, HasObservers, ShadowExecutor}, + inputs::{Input, UsesInput}, mark_feature_time, observers::ObserversTuple, stages::{RetryCountRestartHelper, Stage}, start_timer, - state::{HasCorpus, HasCurrentTestcase, HasExecutions, State, UsesState}, + state::{HasCorpus, HasCurrentTestcase, HasExecutions, MaybeHasClientPerfMonitor, UsesState}, Error, HasNamedMetadata, }; -#[cfg(feature = "introspection")] -use crate::{monitors::PerfFeature, state::HasClientPerfMonitor}; /// A stage that runs a tracer executor #[derive(Clone, Debug)] -pub struct TracingStage { +pub struct TracingStage { name: Cow<'static, str>, tracer_executor: TE, #[allow(clippy::type_complexity)] - phantom: PhantomData<(EM, TE, Z)>, + phantom: PhantomData<(EM, TE, S, Z)>, } -impl UsesState for TracingStage +impl TracingStage where - TE: UsesState, -{ - type State = TE::State; -} - -impl TracingStage -where - TE: Executor + HasObservers, - TE::Observers: ObserversTuple::State>, - ::State: HasExecutions + HasCorpus + HasNamedMetadata + HasCurrentTestcase, - EM: UsesState::State>, - Z: UsesState::State>, - <::State as HasCorpus>::Corpus: Corpus, // delete me + TE: Executor + HasObservers, + TE::Observers: ObserversTuple<::Input, S>, + S: HasExecutions + + HasCorpus + + HasNamedMetadata + + HasCurrentTestcase + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + EM: UsesState, //delete me + Z: UsesState, //delete me { #[allow(rustdoc::broken_intra_doc_links)] /// Perform tracing on the given `CorpusId`. Useful for if wrapping [`TracingStage`] with your /// own stage and you need to manage [`super::NestedStageRetryCountRestartHelper`] differently /// see [`super::ConcolicTracingStage`]'s implementation as an example of usage. - pub fn trace( - &mut self, - fuzzer: &mut Z, - state: &mut ::State, - manager: &mut EM, - ) -> Result<(), Error> { + pub fn trace(&mut self, fuzzer: &mut Z, state: &mut S, manager: &mut EM) -> Result<(), Error> { start_timer!(state); let input = state.current_input_cloned()?; @@ -83,37 +76,41 @@ where } } -impl Stage for TracingStage +impl Stage for TracingStage where - E: UsesState::State>, - TE: Executor + HasObservers, - TE::Observers: ObserversTuple::State>, - ::State: HasExecutions + HasCorpus + HasNamedMetadata, - EM: UsesState::State>, - Z: UsesState::State>, - <::State as HasCorpus>::Corpus: Corpus, // delete me + TE: Executor + HasObservers, + TE::Observers: ObserversTuple<::Input, S>, + S: HasExecutions + + HasCorpus + + HasNamedMetadata + + HasCurrentCorpusId + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + EM: UsesState, + Z: UsesState, + ::Input: Input, { #[inline] fn perform( &mut self, fuzzer: &mut Z, _executor: &mut E, - state: &mut ::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { self.trace(fuzzer, state, manager) } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { RetryCountRestartHelper::no_retry(state, &self.name) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { RetryCountRestartHelper::clear_progress(state, &self.name) } } -impl Named for TracingStage { +impl Named for TracingStage { fn name(&self) -> &Cow<'static, str> { &self.name } @@ -124,7 +121,7 @@ static mut TRACING_STAGE_ID: usize = 0; /// The name for tracing stage pub static TRACING_STAGE_NAME: &str = "tracing"; -impl TracingStage { +impl TracingStage { /// Creates a new default stage pub fn new(tracer_executor: TE) -> Self { // unsafe but impossible that you create two threads both instantiating this instance @@ -154,49 +151,46 @@ impl TracingStage { /// A stage that runs the shadow executor using also the shadow observers #[derive(Clone, Debug)] -pub struct ShadowTracingStage { +pub struct ShadowTracingStage { name: Cow<'static, str>, #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, EM, SOT, Z)>, + phantom: PhantomData<(E, EM, SOT, S, Z)>, } -impl UsesState for ShadowTracingStage -where - E: UsesState, -{ - type State = E::State; -} /// The counter for giving this stage unique id static mut SHADOW_TRACING_STAGE_ID: usize = 0; /// Name for shadow tracing stage pub static SHADOW_TRACING_STAGE_NAME: &str = "shadow"; -impl Named for ShadowTracingStage -where - E: UsesState, -{ +impl Named for ShadowTracingStage { fn name(&self) -> &Cow<'static, str> { &self.name } } -impl Stage, EM, Z> for ShadowTracingStage +impl Stage, EM, S, Z> + for ShadowTracingStage where - E: Executor + HasObservers, - E::Observers: ObserversTuple, - EM: UsesState::State>, - SOT: ObserversTuple, - Z: UsesState::State>, - ::State: - State + HasExecutions + HasCorpus + HasNamedMetadata + Debug + HasCurrentTestcase, - <::State as HasCorpus>::Corpus: Corpus, // delete me + E: Executor + HasObservers, + E::Observers: ObserversTuple<::Input, S>, + SOT: ObserversTuple<::Input, S>, + S: HasExecutions + + HasCorpus + + HasNamedMetadata + + Debug + + HasCurrentTestcase + + HasCurrentCorpusId + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + EM: UsesState, + Z: UsesState, { #[inline] fn perform( &mut self, fuzzer: &mut Z, executor: &mut ShadowExecutor, - state: &mut ::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { start_timer!(state); @@ -227,22 +221,22 @@ where Ok(()) } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { RetryCountRestartHelper::no_retry(state, &self.name) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { RetryCountRestartHelper::clear_progress(state, &self.name) } } -impl ShadowTracingStage +impl ShadowTracingStage where - E: Executor + HasObservers, - ::State: State + HasExecutions + HasCorpus, - EM: UsesState::State>, - SOT: ObserversTuple, - Z: UsesState::State>, + E: Executor + HasObservers, + S: HasExecutions + HasCorpus, + SOT: ObserversTuple<::Input, S>, + EM: UsesState, + Z: UsesState, { /// Creates a new default stage pub fn new(_executor: &mut ShadowExecutor) -> Self { diff --git a/libafl/src/stages/tuneable.rs b/libafl/src/stages/tuneable.rs index b293282ae3..a5db42bb87 100644 --- a/libafl/src/stages/tuneable.rs +++ b/libafl/src/stages/tuneable.rs @@ -6,8 +6,11 @@ use core::{marker::PhantomData, time::Duration}; use libafl_bolts::{current_time, impl_serdeany, rands::Rand}; use serde::{Deserialize, Serialize}; +#[cfg(feature = "introspection")] +use crate::monitors::PerfFeature; use crate::{ corpus::Corpus, + inputs::{Input, UsesInput}, mark_feature_time, mutators::{MutationResult, Mutator}, nonzero, @@ -16,11 +19,9 @@ use crate::{ ExecutionCountRestartHelper, MutationalStage, Stage, }, start_timer, - state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, UsesState}, + state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, MaybeHasClientPerfMonitor}, Error, Evaluator, HasMetadata, HasNamedMetadata, }; -#[cfg(feature = "introspection")] -use crate::{monitors::PerfFeature, state::HasClientPerfMonitor}; #[cfg_attr( any(not(feature = "serdeany_autoreg"), miri), @@ -150,26 +151,103 @@ where /// A [`crate::stages::MutationalStage`] where the mutator iteration can be tuned at runtime #[derive(Clone, Debug)] -pub struct TuneableMutationalStage { +pub struct TuneableMutationalStage { /// The mutator we use mutator: M, /// The name of this stage name: String, /// The progress helper we use to keep track of progress across restarts restart_helper: ExecutionCountRestartHelper, - phantom: PhantomData<(E, EM, I, Z)>, + phantom: PhantomData<(E, EM, I, S, Z)>, } -impl MutationalStage for TuneableMutationalStage +impl MutationalStage for TuneableMutationalStage where - E: UsesState, - EM: UsesState, - M: Mutator, + M: Mutator, Z: Evaluator, - Z::State: - HasCorpus + HasRand + HasNamedMetadata + HasMetadata + HasExecutions + HasCurrentTestcase, - I: MutatedTransform + Clone, - <::State as HasCorpus>::Corpus: Corpus, // delete me + S: HasCorpus + HasRand + HasNamedMetadata + HasMetadata + HasExecutions + HasCurrentTestcase, + I: MutatedTransform<::Input, S> + Clone, + ::Input: Input, +{ + type Mutator = M; + /// The mutator, added to this stage + #[inline] + fn mutator(&self) -> &Self::Mutator { + &self.mutator + } + + /// The list of mutators, added to this stage (as mutable ref) + #[inline] + fn mutator_mut(&mut self) -> &mut Self::Mutator { + &mut self.mutator + } + + /// Gets the number of iterations as a random number + fn iterations(&self, state: &mut S) -> Result { + Ok( + // fall back to random + 1 + state + .rand_mut() + .below(nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS)), + ) + } +} + +impl Stage for TuneableMutationalStage +where + M: Mutator, + Z: Evaluator, + S: HasCorpus + + HasRand + + HasNamedMetadata + + HasMetadata + + HasExecutions + + HasCurrentTestcase + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + I: MutatedTransform<::Input, S> + Clone, + ::Input: Input, +{ + #[inline] + #[allow(clippy::let_and_return)] + fn perform( + &mut self, + fuzzer: &mut Z, + executor: &mut E, + state: &mut S, + manager: &mut EM, + ) -> Result<(), Error> { + let ret = self.perform_mutational(fuzzer, executor, state, manager); + + #[cfg(feature = "introspection")] + state.introspection_monitor_mut().finish_stage(); + + ret + } + + fn should_restart(&mut self, state: &mut S) -> Result { + self.restart_helper.should_restart(state, &self.name) + } + + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { + self.restart_helper.clear_progress(state, &self.name) + } +} + +impl TuneableMutationalStage +where + M: Mutator, + Z: Evaluator, + S: HasCorpus + + HasRand + + HasNamedMetadata + + HasExecutions + + HasMetadata + + HasCurrentTestcase + + MaybeHasClientPerfMonitor + + UsesInput::Input>, + I: MutatedTransform<::Input, S> + Clone, + ::Input: Input, { /// Runs this (mutational) stage for the given `testcase` /// Exactly the same functionality as [`MutationalStage::perform_mutational`], but with added timeout support. @@ -177,7 +255,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { let fuzz_time = self.seed_fuzz_time(state)?; @@ -233,105 +311,24 @@ where Ok(()) } - /// The mutator, added to this stage - #[inline] - fn mutator(&self) -> &M { - &self.mutator - } - - /// The list of mutators, added to this stage (as mutable ref) - #[inline] - fn mutator_mut(&mut self) -> &mut M { - &mut self.mutator - } - - /// Gets the number of iterations as a random number - fn iterations(&self, state: &mut Self::State) -> Result { - Ok( - // fall back to random - 1 + state - .rand_mut() - .below(nonzero!(DEFAULT_MUTATIONAL_MAX_ITERATIONS)), - ) - } -} - -impl UsesState for TuneableMutationalStage -where - Z: Evaluator, -{ - type State = Z::State; -} - -impl Stage for TuneableMutationalStage -where - E: UsesState, - EM: UsesState, - M: Mutator, - Z: Evaluator, - Z::State: - HasCorpus + HasRand + HasNamedMetadata + HasMetadata + HasExecutions + HasCurrentTestcase, - I: MutatedTransform + Clone, - <::State as HasCorpus>::Corpus: Corpus, // delete me -{ - #[inline] - #[allow(clippy::let_and_return)] - fn perform( - &mut self, - fuzzer: &mut Z, - executor: &mut E, - state: &mut Self::State, - manager: &mut EM, - ) -> Result<(), Error> { - let ret = self.perform_mutational(fuzzer, executor, state, manager); - - #[cfg(feature = "introspection")] - state.introspection_monitor_mut().finish_stage(); - - ret - } - - fn should_restart(&mut self, state: &mut Self::State) -> Result { - self.restart_helper.should_restart(state, &self.name) - } - - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { - self.restart_helper.clear_progress(state, &self.name) - } -} - -impl TuneableMutationalStage -where - E: UsesState::State>, - EM: UsesState::State>, - M: Mutator::State>, - Z: Evaluator, - ::State: - HasCorpus + HasRand + HasNamedMetadata + HasExecutions + HasMetadata + HasCurrentTestcase, - I: MutatedTransform::State> + Clone, - <::State as HasCorpus>::Corpus: Corpus, // delete me -{ - fn execs_since_progress_start( - &mut self, - state: &mut ::State, - ) -> Result { + fn execs_since_progress_start(&mut self, state: &mut S) -> Result { self.restart_helper .execs_since_progress_start(state, &self.name) } /// Creates a new default tuneable mutational stage #[must_use] - pub fn new(state: &mut ::State, mutator: M) -> Self { + pub fn new(state: &mut S, mutator: M) -> Self { Self::transforming(state, mutator, STD_TUNEABLE_MUTATIONAL_STAGE_NAME) } /// Crates a new tuneable mutational stage with the given name - pub fn with_name(state: &mut ::State, mutator: M, name: &str) -> Self { + pub fn with_name(state: &mut S, mutator: M, name: &str) -> Self { Self::transforming(state, mutator, name) } /// Set the number of iterations to be used by this [`TuneableMutationalStage`] - pub fn set_iters(&self, state: &mut S, iters: u64) -> Result<(), Error> + pub fn set_iters(&self, state: &mut S, iters: u64) -> Result<(), Error> where S: HasNamedMetadata, { @@ -339,12 +336,12 @@ where } /// Set the number of iterations to be used by the std [`TuneableMutationalStage`] - pub fn set_iters_std(state: &mut ::State, iters: u64) -> Result<(), Error> { + pub fn set_iters_std(state: &mut S, iters: u64) -> Result<(), Error> { set_iters_by_name(state, iters, STD_TUNEABLE_MUTATIONAL_STAGE_NAME) } /// Set the number of iterations to be used by the [`TuneableMutationalStage`] with the given name - pub fn set_iters_by_name(state: &mut S, iters: u64, name: &str) -> Result<(), Error> + pub fn set_iters_by_name(state: &mut S, iters: u64, name: &str) -> Result<(), Error> where S: HasNamedMetadata, { @@ -352,7 +349,7 @@ where } /// Get the set iterations for this [`TuneableMutationalStage`], if any - pub fn fixed_iters(&self, state: &S) -> Result, Error> + pub fn fixed_iters(&self, state: &S) -> Result, Error> where S: HasNamedMetadata, { @@ -360,12 +357,12 @@ where } /// Get the set iterations for the std [`TuneableMutationalStage`], if any - pub fn iters_std(state: &::State) -> Result, Error> { + pub fn iters_std(state: &S) -> Result, Error> { get_iters_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME) } /// Get the set iterations for the [`TuneableMutationalStage`] with the given name, if any - pub fn iters_by_name(state: &S, name: &str) -> Result, Error> + pub fn iters_by_name(state: &S, name: &str) -> Result, Error> where S: HasNamedMetadata, { @@ -373,7 +370,7 @@ where } /// Set the time to mutate a single input in this [`TuneableMutationalStage`] - pub fn set_seed_fuzz_time(&self, state: &mut S, fuzz_time: Duration) -> Result<(), Error> + pub fn set_seed_fuzz_time(&self, state: &mut S, fuzz_time: Duration) -> Result<(), Error> where S: HasNamedMetadata, { @@ -381,15 +378,12 @@ where } /// Set the time to mutate a single input in the std [`TuneableMutationalStage`] - pub fn set_seed_fuzz_time_std( - state: &mut ::State, - fuzz_time: Duration, - ) -> Result<(), Error> { + pub fn set_seed_fuzz_time_std(state: &mut S, fuzz_time: Duration) -> Result<(), Error> { set_seed_fuzz_time_by_name(state, fuzz_time, STD_TUNEABLE_MUTATIONAL_STAGE_NAME) } /// Set the time to mutate a single input in the [`TuneableMutationalStage`] with the given name - pub fn set_seed_fuzz_time_by_name( + pub fn set_seed_fuzz_time_by_name( state: &mut S, fuzz_time: Duration, name: &str, @@ -401,7 +395,7 @@ where } /// Set the time to mutate a single input in this [`TuneableMutationalStage`] - pub fn seed_fuzz_time(&self, state: &S) -> Result, Error> + pub fn seed_fuzz_time(&self, state: &S) -> Result, Error> where S: HasNamedMetadata, { @@ -409,19 +403,12 @@ where } /// Set the time to mutate a single input for the std [`TuneableMutationalStage`] - pub fn seed_fuzz_time_std( - &self, - state: &::State, - ) -> Result, Error> { + pub fn seed_fuzz_time_std(&self, state: &S) -> Result, Error> { get_seed_fuzz_time_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME) } /// Set the time to mutate a single input for the [`TuneableMutationalStage`] with a given name - pub fn seed_fuzz_time_by_name( - &self, - state: &S, - name: &str, - ) -> Result, Error> + pub fn seed_fuzz_time_by_name(&self, state: &S, name: &str) -> Result, Error> where S: HasNamedMetadata, { @@ -429,7 +416,7 @@ where } /// Reset this to a normal, randomized, stage with - pub fn reset(&self, state: &mut S) -> Result<(), Error> + pub fn reset(&self, state: &mut S) -> Result<(), Error> where S: HasNamedMetadata, { @@ -437,12 +424,12 @@ where } /// Reset the std stage to a normal, randomized, stage - pub fn reset_std(state: &mut ::State) -> Result<(), Error> { + pub fn reset_std(state: &mut S) -> Result<(), Error> { reset_by_name(state, STD_TUNEABLE_MUTATIONAL_STAGE_NAME) } /// Reset this to a normal, randomized, stage by name - pub fn reset_by_name(state: &mut S, name: &str) -> Result<(), Error> + pub fn reset_by_name(state: &mut S, name: &str) -> Result<(), Error> where S: HasNamedMetadata, { @@ -453,7 +440,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut ::State, + state: &mut S, manager: &mut EM, input: &I, ) -> Result<(), Error> { @@ -480,17 +467,15 @@ where } } -impl TuneableMutationalStage +impl TuneableMutationalStage where - E: UsesState::State>, - EM: UsesState::State>, M: Mutator, Z: Evaluator, - ::State: HasCorpus + HasRand + HasNamedMetadata, + S: HasCorpus + HasRand + HasNamedMetadata, { /// Creates a new transforming mutational stage #[must_use] - pub fn transforming(state: &mut ::State, mutator: M, name: &str) -> Self { + pub fn transforming(state: &mut S, mutator: M, name: &str) -> Self { let _ = state.named_metadata_or_insert_with(name, TuneableMutationalStageMetadata::default); Self { mutator, diff --git a/libafl/src/stages/unicode.rs b/libafl/src/stages/unicode.rs index dc636bce8d..873729230a 100644 --- a/libafl/src/stages/unicode.rs +++ b/libafl/src/stages/unicode.rs @@ -11,7 +11,7 @@ use crate::{ corpus::Corpus, inputs::{BytesInput, HasTargetBytes}, stages::Stage, - state::{HasCorpus, HasCurrentTestcase, State, UsesState}, + state::{HasCorpus, HasCurrentTestcase}, HasMetadata, }; @@ -109,39 +109,29 @@ impl UnicodeIdentificationStage { } } -impl UsesState for UnicodeIdentificationStage +impl Stage for UnicodeIdentificationStage where - S: State, -{ - type State = S; -} - -impl Stage for UnicodeIdentificationStage -where - S: HasCorpus + State + HasCurrentTestcase, + S: HasCorpus + HasCurrentTestcase, S::Corpus: Corpus, - E: UsesState, - EM: UsesState, - Z: UsesState, { fn perform( &mut self, _fuzzer: &mut Z, _executor: &mut E, - state: &mut Self::State, + state: &mut S, _manager: &mut EM, ) -> Result<(), Error> { UnicodeIdentificationStage::identify_unicode_in_current_testcase(state) } #[inline] - fn should_restart(&mut self, _state: &mut Self::State) -> Result { + fn should_restart(&mut self, _state: &mut S) -> Result { // Stage does not run the target. No reset helper needed. Ok(true) } #[inline] - fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> { // Stage does not run the target. No reset helper needed. Ok(()) } diff --git a/libafl/src/stages/verify_timeouts.rs b/libafl/src/stages/verify_timeouts.rs index 19749083c0..b6755dadff 100644 --- a/libafl/src/stages/verify_timeouts.rs +++ b/libafl/src/stages/verify_timeouts.rs @@ -15,7 +15,7 @@ use crate::{ inputs::{BytesInput, UsesInput}, observers::ObserversTuple, stages::Stage, - state::{HasCorpus, State, UsesState}, + state::{HasCorpus, UsesState}, Evaluator, HasMetadata, }; @@ -43,13 +43,6 @@ impl VerifyTimeoutsStage { } } -impl UsesState for VerifyTimeoutsStage -where - S: State, -{ - type State = S; -} - /// Timeouts that `VerifyTimeoutsStage` will read from #[derive(Default, Serialize, Deserialize, Clone, Debug)] #[serde(bound = "I: for<'a> Deserialize<'a> + Serialize")] @@ -88,21 +81,20 @@ impl TimeoutsToVerify { } } -impl Stage for VerifyTimeoutsStage +impl Stage for VerifyTimeoutsStage where - E::Observers: ObserversTuple<::Input, ::State>, + E::Observers: ObserversTuple<::Input, S>, E: Executor + HasObservers + HasTimeout, EM: UsesState, - Z: UsesState + Evaluator, - S: HasCorpus + State + HasMetadata, - Self::Input: Debug + Serialize + DeserializeOwned + Default + 'static + Clone, - <::State as HasCorpus>::Corpus: Corpus, //delete me + Z: Evaluator, + S: HasCorpus + HasMetadata + UsesInput::Input>, + ::Input: Debug + Serialize + DeserializeOwned + Default + 'static + Clone, { fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut Self::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { let mut timeouts = state @@ -118,15 +110,17 @@ where } executor.set_timeout(self.original_timeout); *self.capture_timeouts.borrow_mut() = true; - let res = state.metadata_mut::>().unwrap(); - *res = TimeoutsToVerify::::new(); + let res = state + .metadata_mut::::Input>>() + .unwrap(); + *res = TimeoutsToVerify::<::Input>::new(); Ok(()) } - fn should_restart(&mut self, _state: &mut Self::State) -> Result { + fn should_restart(&mut self, _state: &mut S) -> Result { Ok(true) } - fn clear_progress(&mut self, _state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> { Ok(()) } } diff --git a/libafl_libfuzzer/runtime/src/lib.rs b/libafl_libfuzzer/runtime/src/lib.rs index 8e48992a24..36096e05df 100644 --- a/libafl_libfuzzer/runtime/src/lib.rs +++ b/libafl_libfuzzer/runtime/src/lib.rs @@ -356,7 +356,7 @@ macro_rules! fuzz_with { // TODO configure with mutation stacking options from libfuzzer let std_mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - let std_power: StdPowerMutationalStage<_, _, BytesInput, _, _> = StdPowerMutationalStage::new(std_mutator); + let std_power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(std_mutator); let std_power = IfStage::new(|_, _, _, _| Ok(mutator_status.std_mutational.into()), (std_power, ())); // for custom mutator and crossover, each have access to the LLVMFuzzerMutate -- but it appears @@ -378,7 +378,7 @@ macro_rules! fuzz_with { // Safe to unwrap: stack pow is not 0. let std_mutator_no_mutate = StdScheduledMutator::with_max_stack_pow(havoc_crossover(),3); - let cm_power: StdPowerMutationalStage<_, _, BytesInput, _, _> = StdPowerMutationalStage::new(custom_mutator); + let cm_power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(custom_mutator); let cm_power = IfStage::new(|_, _, _, _| Ok(mutator_status.custom_mutation.into()), (cm_power, ())); let cm_std_power = StdMutationalStage::new(std_mutator_no_mutate); let cm_std_power = @@ -398,7 +398,7 @@ macro_rules! fuzz_with { let cc_power = StdMutationalStage::new(custom_crossover); let cc_power = IfStage::new(|_, _, _, _| Ok(mutator_status.custom_crossover.into()), (cc_power, ())); - let cc_std_power: StdPowerMutationalStage<_, _, BytesInput, _, _> = StdPowerMutationalStage::new(std_mutator_no_crossover); + let cc_std_power: StdPowerMutationalStage<_, _, BytesInput, _, _, _> = StdPowerMutationalStage::new(std_mutator_no_crossover); let cc_std_power = IfStage::new(|_, _, _, _| Ok(mutator_status.std_no_crossover.into()), (cc_std_power, ())); diff --git a/libafl_targets/src/cmps/stages/aflpptracing.rs b/libafl_targets/src/cmps/stages/aflpptracing.rs index d87600d56d..6749ea7feb 100644 --- a/libafl_targets/src/cmps/stages/aflpptracing.rs +++ b/libafl_targets/src/cmps/stages/aflpptracing.rs @@ -2,12 +2,12 @@ use alloc::borrow::{Cow, ToOwned}; use core::marker::PhantomData; use libafl::{ - corpus::Corpus, + corpus::{Corpus, HasCurrentCorpusId}, executors::{Executor, HasObservers}, inputs::{BytesInput, UsesInput}, observers::ObserversTuple, stages::{colorization::TaintMetadata, RetryCountRestartHelper, Stage}, - state::{HasCorpus, HasCurrentTestcase, HasExecutions, UsesState}, + state::{HasCorpus, HasCurrentTestcase, UsesState}, Error, HasMetadata, HasNamedMetadata, }; use libafl_bolts::{ @@ -19,56 +19,42 @@ use crate::cmps::observers::AFLppCmpLogObserver; /// Trace with tainted input #[derive(Clone, Debug)] -pub struct AFLppCmplogTracingStage<'a, EM, TE, Z> -where - TE: UsesState, -{ +pub struct AFLppCmplogTracingStage<'a, EM, TE, S, Z> { name: Cow<'static, str>, tracer_executor: TE, cmplog_observer_handle: Handle>, #[allow(clippy::type_complexity)] - phantom: PhantomData<(EM, TE, Z)>, + phantom: PhantomData<(EM, TE, S, Z)>, } /// The name for aflpp tracing stage pub static AFLPP_CMPLOG_TRACING_STAGE_NAME: &str = "aflpptracing"; -impl UsesState for AFLppCmplogTracingStage<'_, EM, TE, Z> -where - TE: UsesState, -{ - type State = TE::State; -} - -impl Named for AFLppCmplogTracingStage<'_, EM, TE, Z> -where - TE: UsesState, -{ +impl Named for AFLppCmplogTracingStage<'_, EM, TE, S, Z> { fn name(&self) -> &Cow<'static, str> { &self.name } } -impl Stage for AFLppCmplogTracingStage<'_, EM, TE, Z> +impl Stage for AFLppCmplogTracingStage<'_, EM, TE, S, Z> where - E: UsesState, - TE: Executor + HasObservers, - TE::State: HasExecutions - + HasCorpus - + HasMetadata + EM: UsesState, + Z: UsesState, + TE: HasObservers + Executor, + TE::Observers: MatchNameRef + ObserversTuple, + S: HasCorpus + + HasCurrentTestcase + UsesInput + + HasMetadata + HasNamedMetadata - + HasCurrentTestcase, - TE::Observers: MatchNameRef + ObserversTuple, - EM: UsesState, - Z: UsesState, - ::Corpus: Corpus, //delete me + + HasCurrentCorpusId, + S::Corpus: Corpus, { #[inline] fn perform( &mut self, fuzzer: &mut Z, _executor: &mut E, - state: &mut TE::State, + state: &mut S, manager: &mut EM, ) -> Result<(), Error> { // First run with the un-mutated input @@ -131,22 +117,19 @@ where Ok(()) } - fn should_restart(&mut self, state: &mut Self::State) -> Result { + fn should_restart(&mut self, state: &mut S) -> Result { // Tracing stage is always deterministic // don't restart RetryCountRestartHelper::no_retry(state, &self.name) } - fn clear_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { // TODO: this may need better resumption? (Or is it always used with a forkserver?) RetryCountRestartHelper::clear_progress(state, &self.name) } } -impl<'a, EM, TE, Z> AFLppCmplogTracingStage<'a, EM, TE, Z> -where - TE: UsesState, -{ +impl<'a, EM, TE, S, Z> AFLppCmplogTracingStage<'a, EM, TE, S, Z> { /// With cmplog observer pub fn new(tracer_executor: TE, observer_handle: Handle>) -> Self { let observer_name = observer_handle.name().clone();