diff --git a/fuzzers/baby/tutorial/src/metadata.rs b/fuzzers/baby/tutorial/src/metadata.rs index 0098765ad8..0c93ebd5f7 100644 --- a/fuzzers/baby/tutorial/src/metadata.rs +++ b/fuzzers/baby/tutorial/src/metadata.rs @@ -2,12 +2,10 @@ use std::borrow::Cow; use libafl::{ corpus::{Corpus, Testcase}, - events::EventFirer, executors::ExitKind, - feedbacks::{Feedback, MapIndexesMetadata}, - observers::ObserversTuple, + feedbacks::{Feedback, MapIndexesMetadata, StateInitializer}, schedulers::{MinimizerScheduler, TestcaseScore}, - state::{HasCorpus, State}, + state::HasCorpus, Error, HasMetadata, }; use libafl_bolts::{Named, SerdeAny}; @@ -45,29 +43,24 @@ pub struct PacketLenFeedback { len: u64, } -impl Feedback for PacketLenFeedback -where - S: State, -{ +impl StateInitializer for PacketLenFeedback {} + +impl Feedback for PacketLenFeedback { #[inline] - fn is_interesting( + fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, input: &PacketData, _observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { self.len = input.length; Ok(false) } #[inline] - fn append_metadata( + fn append_metadata( &mut self, _state: &mut S, _manager: &mut EM, diff --git a/fuzzers/forkserver/libafl-fuzz/src/feedback/filepath.rs b/fuzzers/forkserver/libafl-fuzz/src/feedback/filepath.rs index e29d319f8e..cebb5b9d98 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/feedback/filepath.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/feedback/filepath.rs @@ -1,18 +1,13 @@ use std::{ borrow::Cow, - fmt::{Debug, Formatter}, - marker::PhantomData, path::{Path, PathBuf}, }; use libafl::{ - corpus::Testcase, - events::EventFirer, + corpus::{Corpus, Testcase}, executors::ExitKind, - feedbacks::{Feedback, FeedbackFactory}, - inputs::Input, - observers::ObserversTuple, - state::State, + feedbacks::{Feedback, FeedbackFactory, StateInitializer}, + state::HasCorpus, }; use libafl_bolts::{Error, Named}; use serde::{Deserialize, Serialize}; @@ -22,108 +17,68 @@ use serde::{Deserialize, Serialize}; /// Note: If used as part of the `Objective` chain, then it will only apply to testcases which are /// `Objectives`, vice versa for `Feedback`. #[derive(Serialize, Deserialize)] -pub struct CustomFilepathToTestcaseFeedback -where - I: Input, - S: State, - F: FnMut(&mut S, &mut Testcase, &Path) -> Result<(), Error>, -{ +pub struct CustomFilepathToTestcaseFeedback { /// Closure that returns the filename. func: F, /// The root output directory out_dir: PathBuf, - phantomm: PhantomData<(I, S)>, } -impl CustomFilepathToTestcaseFeedback -where - I: Input, - S: State, - F: FnMut(&mut S, &mut Testcase, &Path) -> Result<(), Error>, -{ +impl CustomFilepathToTestcaseFeedback { /// Create a new [`CustomFilepathToTestcaseFeedback`]. pub fn new(func: F, out_dir: PathBuf) -> Self { - Self { - func, - out_dir, - phantomm: PhantomData, - } + Self { func, out_dir } } } -impl FeedbackFactory, T> - for CustomFilepathToTestcaseFeedback +impl FeedbackFactory, T> + for CustomFilepathToTestcaseFeedback where - I: Input, - S: State, - F: FnMut(&mut S, &mut Testcase, &Path) -> Result<(), Error> + Clone, + F: Clone, { - fn create_feedback(&self, _ctx: &T) -> CustomFilepathToTestcaseFeedback { + fn create_feedback(&self, _ctx: &T) -> CustomFilepathToTestcaseFeedback { Self { func: self.func.clone(), - phantomm: self.phantomm, out_dir: self.out_dir.clone(), } } } -impl Named for CustomFilepathToTestcaseFeedback -where - I: Input, - S: State, - F: FnMut(&mut S, &mut Testcase, &Path) -> Result<(), Error>, -{ +impl Named for CustomFilepathToTestcaseFeedback { fn name(&self) -> &Cow<'static, str> { static NAME: Cow<'static, str> = Cow::Borrowed("CustomFilepathToTestcaseFeedback"); &NAME } } -impl Debug for CustomFilepathToTestcaseFeedback -where - I: Input, - S: State, - F: FnMut(&mut S, &mut Testcase, &Path) -> Result<(), Error>, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("CustomFilepathToTestcaseFeedback") - .finish_non_exhaustive() - } -} +impl StateInitializer for CustomFilepathToTestcaseFeedback {} -impl Feedback for CustomFilepathToTestcaseFeedback +impl Feedback::Input, OT, S> + for CustomFilepathToTestcaseFeedback where - S: State, - F: FnMut(&mut S, &mut Testcase, &Path) -> Result<(), Error>, - I: Input, + S: HasCorpus, + F: FnMut(&mut S, &mut Testcase<::Input>, &Path) -> Result<(), Error>, { #[allow(clippy::wrong_self_convention)] #[inline] - fn is_interesting( + fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &I, + _input: &::Input, _observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - { + ) -> Result { Ok(false) } - fn append_metadata( + fn append_metadata( &mut self, state: &mut S, _manager: &mut EM, _observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { + testcase: &mut Testcase<::Input>, + ) -> Result<(), Error> { (self.func)(state, testcase, &self.out_dir)?; Ok(()) } diff --git a/fuzzers/forkserver/libafl-fuzz/src/feedback/persistent_record.rs b/fuzzers/forkserver/libafl-fuzz/src/feedback/persistent_record.rs index 05c0a765ec..2943c469b2 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/feedback/persistent_record.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/feedback/persistent_record.rs @@ -1,18 +1,12 @@ -use std::{ - borrow::Cow, - collections::VecDeque, - fmt::{Debug, Formatter}, - marker::PhantomData, -}; +use std::{borrow::Cow, collections::VecDeque}; use libafl::{ corpus::{Corpus, Testcase}, - events::EventFirer, executors::ExitKind, feedbacks::{Feedback, FeedbackFactory}, inputs::Input, - observers::ObserversTuple, - state::{HasCorpus, State}, + prelude::StateInitializer, + state::HasCorpus, }; use libafl_bolts::{Error, Named}; use serde::{Deserialize, Serialize}; @@ -20,85 +14,59 @@ use serde::{Deserialize, Serialize}; /// A [`PersitentRecordFeedback`] tracks the last N inputs that the fuzzer has run. /// TODO: Kept in memory for now but should write to disk. #[derive(Serialize, Deserialize)] -pub struct PersitentRecordFeedback -where - S: State, -{ +pub struct PersitentRecordFeedback { /// Vec that tracks the last `record_size` [`Input`] record: VecDeque, record_size: usize, - phantomm: PhantomData<(I, S)>, } -impl PersitentRecordFeedback -where - I: Input, - S: State, -{ +impl PersitentRecordFeedback { /// Create a new [`PersitentRecordFeedback`]. pub fn new(record_size: usize) -> Self { Self { record_size, record: VecDeque::default(), - phantomm: PhantomData, } } } -impl FeedbackFactory, T> for PersitentRecordFeedback +impl FeedbackFactory, T> for PersitentRecordFeedback where - I: Input, - S: State, + I: Clone, { - fn create_feedback(&self, _ctx: &T) -> PersitentRecordFeedback { + fn create_feedback(&self, _ctx: &T) -> PersitentRecordFeedback { Self { record_size: self.record_size, record: self.record.clone(), - phantomm: self.phantomm, } } } -impl Named for PersitentRecordFeedback -where - I: Input, - S: State, -{ +impl Named for PersitentRecordFeedback { fn name(&self) -> &Cow<'static, str> { static NAME: Cow<'static, str> = Cow::Borrowed("PersitentRecordFeedback"); &NAME } } -impl Debug for PersitentRecordFeedback -where - I: Input, - S: State, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("PersitentRecordFeedback") - .finish_non_exhaustive() - } -} +impl StateInitializer for PersitentRecordFeedback {} -impl Feedback for PersitentRecordFeedback +impl Feedback for PersitentRecordFeedback where - S: State + HasCorpus, + S: HasCorpus, + S::Corpus: Corpus, I: Input, { #[allow(clippy::wrong_self_convention)] #[inline] - fn is_interesting( + fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, input: &I, _observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - { + ) -> Result { if self.should_run() { self.record.push_back(input.clone()); if self.record.len() == self.record_size { @@ -108,17 +76,13 @@ where Ok(false) } - fn append_metadata( + fn append_metadata( &mut self, state: &mut S, _manager: &mut EM, _observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { + testcase: &mut Testcase, + ) -> Result<(), Error> { if self.should_run() { let file_path = testcase .file_path() @@ -150,11 +114,7 @@ where } } -impl PersitentRecordFeedback -where - I: Input, - S: State, -{ +impl PersitentRecordFeedback { fn should_run(&self) -> bool { self.record_size > 0 } diff --git a/fuzzers/forkserver/libafl-fuzz/src/feedback/seed.rs b/fuzzers/forkserver/libafl-fuzz/src/feedback/seed.rs index b94a72fa44..8e2c399a19 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/feedback/seed.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/feedback/seed.rs @@ -1,8 +1,7 @@ use std::{borrow::Cow, marker::PhantomData}; use libafl::{ - corpus::Testcase, events::EventFirer, executors::ExitKind, feedbacks::Feedback, - observers::ObserversTuple, state::State, Error, + corpus::Testcase, executors::ExitKind, feedbacks::Feedback, prelude::StateInitializer, Error, }; use libafl_bolts::Named; @@ -13,57 +12,50 @@ use crate::Opt; /// then, essentially becomes benign #[allow(clippy::module_name_repetitions, clippy::struct_excessive_bools)] #[derive(Debug)] -pub struct SeedFeedback -where - A: Feedback, - S: State, -{ +pub struct SeedFeedback { /// Inner [`Feedback`] pub inner: A, ignore_timeouts: bool, ignore_seed_issues: bool, exit_on_seed_issues: bool, - phantom: PhantomData, done_loading_seeds: bool, + phantom: PhantomData, } -impl SeedFeedback -where - A: Feedback, - S: State, -{ +impl SeedFeedback { pub fn new(inner: A, opt: &Opt) -> Self { Self { inner, ignore_timeouts: opt.ignore_timeouts, ignore_seed_issues: opt.ignore_seed_issues, exit_on_seed_issues: opt.exit_on_seed_issues, - phantom: PhantomData, done_loading_seeds: false, + phantom: PhantomData, } } } -impl Feedback for SeedFeedback +impl StateInitializer for SeedFeedback where - A: Feedback, - S: State, + A: StateInitializer, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { self.inner.init_state(state)?; Ok(()) } - fn is_interesting( +} + +impl Feedback for SeedFeedback +where + A: Feedback, +{ + fn is_interesting( &mut self, state: &mut S, manager: &mut EM, - input: &S::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { if !self.done_loading_seeds { match exit_kind { ExitKind::Timeout => { @@ -93,17 +85,13 @@ where } /// Append to the testcase the generated metadata in case of a new corpus item #[inline] - fn append_metadata( + fn append_metadata( &mut self, state: &mut S, manager: &mut EM, observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { + testcase: &mut Testcase, + ) -> Result<(), Error> { self.inner .append_metadata(state, manager, observers, testcase)?; Ok(()) @@ -111,7 +99,7 @@ where /// Discard the stored metadata in case that the testcase is not added to the corpus #[inline] - fn discard_metadata(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { + fn discard_metadata(&mut self, state: &mut S, input: &I) -> Result<(), Error> { self.inner.discard_metadata(state, input)?; Ok(()) } @@ -128,11 +116,7 @@ where } } -impl Named for SeedFeedback -where - A: Feedback, - S: State, -{ +impl Named for SeedFeedback { #[inline] fn name(&self) -> &Cow<'static, str> { static NAME: Cow<'static, str> = Cow::Borrowed("SeedFeedback"); @@ -140,11 +124,7 @@ where } } -impl SeedFeedback -where - A: Feedback, - S: State, -{ +impl SeedFeedback { pub fn done_loading_seeds(&mut self) { self.done_loading_seeds = true; } diff --git a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs index 1c9e982627..4fbf277480 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs @@ -8,8 +8,8 @@ use std::{ use libafl::{ corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus}, events::{ - CentralizedEventManager, EventManagerHooksTuple, EventProcessor, - LlmpRestartingEventManager, ProgressReporter, + CentralizedEventManager, EventManagerHooksTuple, LlmpRestartingEventManager, + ProgressReporter, }, executors::forkserver::{ForkserverExecutor, ForkserverExecutorBuilder}, feedback_and, feedback_or, feedback_or_fast, @@ -530,7 +530,7 @@ pub fn run_fuzzer_with_stages( where Z: Fuzzer, E: UsesState, - EM: ProgressReporter + EventProcessor, + EM: ProgressReporter, ST: StagesTuple, ::State: HasLastReportTime + HasExecutions + HasMetadata, { diff --git a/libafl/src/events/centralized.rs b/libafl/src/events/centralized.rs index ce0dc28912..f86b048248 100644 --- a/libafl/src/events/centralized.rs +++ b/libafl/src/events/centralized.rs @@ -377,8 +377,8 @@ where S: State, Self::State: HasExecutions + HasMetadata, SP: ShMemProvider, - Z: EvaluatorObservers - + ExecutionProcessor, + Z: EvaluatorObservers + + ExecutionProcessor, { fn process( &mut self, @@ -413,8 +413,8 @@ where EMH: EventManagerHooksTuple, S: State, SP: ShMemProvider, - Z: EvaluatorObservers - + ExecutionProcessor, + Z: EvaluatorObservers + + ExecutionProcessor, { } @@ -535,8 +535,8 @@ where ObserversTuple<::Input, ::State> + Serialize, ::State: UsesInput + HasExecutions + HasMetadata, for<'a> E::Observers: Deserialize<'a>, - Z: ExecutionProcessor::State> - + EvaluatorObservers, + Z: ExecutionProcessor::State> + + EvaluatorObservers, { // TODO: Get around local event copy by moving handle_in_client let self_id = self.client.sender().id(); @@ -585,8 +585,8 @@ where ObserversTuple<::Input, ::State> + Serialize, ::State: UsesInput + HasExecutions + HasMetadata, for<'a> E::Observers: Deserialize<'a> + Serialize, - Z: ExecutionProcessor::State> - + EvaluatorObservers, + Z: ExecutionProcessor::State> + + EvaluatorObservers, { log::debug!("handle_in_main!"); @@ -641,7 +641,7 @@ where process::id(), event_name ); - fuzzer.evaluate_input_with_observers::( + fuzzer.evaluate_input_with_observers::( state, executor, self, diff --git a/libafl/src/events/llmp/mgr.rs b/libafl/src/events/llmp/mgr.rs index 8b984d8f59..155331c760 100644 --- a/libafl/src/events/llmp/mgr.rs +++ b/libafl/src/events/llmp/mgr.rs @@ -406,7 +406,9 @@ where E: Executor + HasObservers, E::Observers: ObserversTuple + Serialize, for<'a> E::Observers: Deserialize<'a>, - Z: ExecutionProcessor + EvaluatorObservers + Evaluator, + Z: ExecutionProcessor + + EvaluatorObservers + + Evaluator, { if !self.hooks.pre_exec_all(state, client_id, &event)? { return Ok(()); @@ -449,7 +451,7 @@ where { state.scalability_monitor_mut().testcase_without_observers += 1; } - fuzzer.evaluate_input_with_observers::( + fuzzer.evaluate_input_with_observers::( state, executor, self, input, false, )? }; @@ -590,7 +592,9 @@ where E: HasObservers + Executor, E::Observers: ObserversTuple + Serialize, for<'a> E::Observers: Deserialize<'a>, - Z: ExecutionProcessor + EvaluatorObservers + Evaluator, + Z: ExecutionProcessor + + EvaluatorObservers + + Evaluator, { fn process( &mut self, @@ -642,7 +646,9 @@ where EMH: EventManagerHooksTuple, S: State + HasExecutions + HasMetadata + HasLastReportTime + HasImported, SP: ShMemProvider, - Z: ExecutionProcessor + EvaluatorObservers + Evaluator, + Z: ExecutionProcessor + + EvaluatorObservers + + Evaluator, { } diff --git a/libafl/src/events/llmp/mod.rs b/libafl/src/events/llmp/mod.rs index 62447388dd..c76bfbc28d 100644 --- a/libafl/src/events/llmp/mod.rs +++ b/libafl/src/events/llmp/mod.rs @@ -296,7 +296,7 @@ where E: Executor + HasObservers, EM: UsesState + EventFirer, for<'a> E::Observers: Deserialize<'a>, - Z: ExecutionProcessor + EvaluatorObservers, + Z: ExecutionProcessor + EvaluatorObservers, { match event { Event::NewTestcase { @@ -308,7 +308,7 @@ where return Ok(()); }; - let res = fuzzer.evaluate_input_with_observers::( + let res = fuzzer.evaluate_input_with_observers::( state, executor, manager, @@ -350,7 +350,7 @@ where E: Executor + HasObservers, EM: UsesState + EventFirer, for<'a> E::Observers: Deserialize<'a>, - Z: ExecutionProcessor + EvaluatorObservers, + Z: ExecutionProcessor + EvaluatorObservers, { // TODO: Get around local event copy by moving handle_in_client let self_id = self.llmp.sender().id(); diff --git a/libafl/src/events/llmp/restarting.rs b/libafl/src/events/llmp/restarting.rs index 4e1c8dbdff..1177e270a4 100644 --- a/libafl/src/events/llmp/restarting.rs +++ b/libafl/src/events/llmp/restarting.rs @@ -210,8 +210,8 @@ where EMH: EventManagerHooksTuple, S: State + HasExecutions + HasMetadata + HasImported, SP: ShMemProvider, - Z: ExecutionProcessor - + EvaluatorObservers + Z: ExecutionProcessor, E::Observers, State = S> + + EvaluatorObservers, E::Observers> + Evaluator>, { fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result { @@ -234,8 +234,8 @@ where EMH: EventManagerHooksTuple, S: State + HasExecutions + HasMetadata + HasLastReportTime + HasImported, SP: ShMemProvider, - Z: ExecutionProcessor - + EvaluatorObservers + Z: ExecutionProcessor, E::Observers, State = S> + + EvaluatorObservers, E::Observers> + Evaluator>, { } diff --git a/libafl/src/events/tcp.rs b/libafl/src/events/tcp.rs index 2c7bc92c82..5ca70fbd5e 100644 --- a/libafl/src/events/tcp.rs +++ b/libafl/src/events/tcp.rs @@ -614,7 +614,8 @@ where E: Executor + HasObservers, E::Observers: Serialize + ObserversTuple, for<'a> E::Observers: Deserialize<'a>, - Z: ExecutionProcessor + EvaluatorObservers, + Z: ExecutionProcessor + + EvaluatorObservers, { if !self.hooks.pre_exec_all(state, client_id, &event)? { return Ok(()); @@ -645,9 +646,8 @@ where { state.scalability_monitor_mut().testcase_without_observers += 1; } - fuzzer.evaluate_input_with_observers::( - state, executor, self, input, false, - )? + fuzzer + .evaluate_input_with_observers::(state, executor, self, input, false)? }; if let Some(item) = _res.1 { *state.imported_mut() += 1; @@ -756,7 +756,8 @@ where for<'a> E::Observers: Deserialize<'a>, EMH: EventManagerHooksTuple, S: State + HasExecutions + HasMetadata + HasImported, - Z: EvaluatorObservers + ExecutionProcessor, + Z: EvaluatorObservers + + ExecutionProcessor, { fn process( &mut self, @@ -830,7 +831,8 @@ where for<'a> E::Observers: Deserialize<'a>, EMH: EventManagerHooksTuple, S: State + HasExecutions + HasMetadata + HasLastReportTime + HasImported, - Z: EvaluatorObservers + ExecutionProcessor, + Z: EvaluatorObservers + + ExecutionProcessor, { } @@ -976,7 +978,8 @@ where EMH: EventManagerHooksTuple, S: State + HasExecutions + HasMetadata + HasImported, SP: ShMemProvider + 'static, - Z: EvaluatorObservers + ExecutionProcessor, //CE: CustomEvent, + Z: EvaluatorObservers, E::Observers, State = S> + + ExecutionProcessor, E::Observers>, //CE: CustomEvent, { fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result { self.tcp_mgr.process(fuzzer, state, executor) @@ -996,7 +999,8 @@ where EMH: EventManagerHooksTuple, S: State + HasExecutions + HasMetadata + HasLastReportTime + HasImported, SP: ShMemProvider + 'static, - Z: EvaluatorObservers + ExecutionProcessor, //CE: CustomEvent, + Z: EvaluatorObservers, E::Observers, State = S> + + ExecutionProcessor, E::Observers>, //CE: CustomEvent, { } diff --git a/libafl/src/executors/hooks/inprocess.rs b/libafl/src/executors/hooks/inprocess.rs index aa2ee157e6..7240d62f76 100644 --- a/libafl/src/executors/hooks/inprocess.rs +++ b/libafl/src/executors/hooks/inprocess.rs @@ -239,7 +239,7 @@ where E: Executor + HasObservers + HasInProcessHooks, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasExecutions + HasSolutions + HasCorpus, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me @@ -282,7 +282,7 @@ where E: Executor + HasObservers + HasInProcessHooks, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: State + HasExecutions + HasSolutions + HasCorpus, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me @@ -339,7 +339,7 @@ where where E: Executor + HasObservers + HasInProcessHooks, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasExecutions + HasSolutions + HasCorpus, Z: HasObjective, { diff --git a/libafl/src/executors/hooks/unix.rs b/libafl/src/executors/hooks/unix.rs index 48a9bab85b..7d9c1030c2 100644 --- a/libafl/src/executors/hooks/unix.rs +++ b/libafl/src/executors/hooks/unix.rs @@ -80,7 +80,7 @@ pub mod unix_signal_handler { E: Executor + HasObservers, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasExecutions + HasSolutions + HasCorpus, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me @@ -130,7 +130,7 @@ pub mod unix_signal_handler { E: Executor + HasInProcessHooks + HasObservers, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasExecutions + HasSolutions + HasCorpus, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me @@ -188,7 +188,7 @@ pub mod unix_signal_handler { E: Executor + HasObservers, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasExecutions + HasSolutions + HasCorpus, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me diff --git a/libafl/src/executors/hooks/windows.rs b/libafl/src/executors/hooks/windows.rs index f4a3c176b2..95b78252b3 100644 --- a/libafl/src/executors/hooks/windows.rs +++ b/libafl/src/executors/hooks/windows.rs @@ -31,7 +31,7 @@ pub mod windows_asan_handler { where E: Executor + HasObservers, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasExecutions + HasSolutions + HasCorpus, E::Observers: ObserversTuple<::Input, E::State>, Z: HasObjective, @@ -184,7 +184,7 @@ pub mod windows_exception_handler { where E: HasObservers + Executor, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasExecutions + HasSolutions + HasCorpus, E::Observers: ObserversTuple<::Input, E::State>, Z: HasObjective, @@ -248,7 +248,7 @@ pub mod windows_exception_handler { E: HasObservers + HasInProcessHooks + Executor, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: State + HasExecutions + HasSolutions + HasCorpus, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me @@ -321,7 +321,7 @@ pub mod windows_exception_handler { E: Executor + HasObservers, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasExecutions + HasSolutions + HasCorpus, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me diff --git a/libafl/src/executors/inprocess/inner.rs b/libafl/src/executors/inprocess/inner.rs index a901c7874a..a4f4202721 100644 --- a/libafl/src/executors/inprocess/inner.rs +++ b/libafl/src/executors/inprocess/inner.rs @@ -170,7 +170,7 @@ where E: Executor + HasObservers + HasInProcessHooks, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me @@ -200,7 +200,7 @@ where E: Executor + HasObservers + HasInProcessHooks, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me @@ -233,7 +233,7 @@ where E: Executor + HasObservers + HasInProcessHooks, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me diff --git a/libafl/src/executors/inprocess/mod.rs b/libafl/src/executors/inprocess/mod.rs index 073a1f65a8..0075045dea 100644 --- a/libafl/src/executors/inprocess/mod.rs +++ b/libafl/src/executors/inprocess/mod.rs @@ -173,7 +173,7 @@ where where Self: Executor + HasObservers, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, { @@ -201,7 +201,7 @@ where where Self: Executor, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, ::Solutions: Corpus, //delete me @@ -242,7 +242,7 @@ where where Self: Executor, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, ::Solutions: Corpus, //delete me @@ -287,7 +287,7 @@ where where Self: Executor, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, { @@ -316,7 +316,7 @@ where where Self: Executor, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, ::Solutions: Corpus, //delete me @@ -353,7 +353,7 @@ where where Self: Executor, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, ::Solutions: Corpus, //delete me @@ -442,7 +442,7 @@ pub fn run_observers_and_save_state( E: Executor + HasObservers, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me @@ -505,11 +505,11 @@ where E: Executor + HasObservers, E::Observers: ObserversTuple<::Input, E::State>, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, Z: HasObjective + HasScheduler - + ExecutionProcessor, + + ExecutionProcessor, <::State as HasSolutions>::Solutions: Corpus, //delete me { let data = addr_of_mut!(GLOBAL_STATE); diff --git a/libafl/src/executors/inprocess/stateful.rs b/libafl/src/executors/inprocess/stateful.rs index 942bb36e5e..27bd145836 100644 --- a/libafl/src/executors/inprocess/stateful.rs +++ b/libafl/src/executors/inprocess/stateful.rs @@ -163,7 +163,7 @@ where where Self: Executor, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, { @@ -193,7 +193,7 @@ where where Self: Executor, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, ::Solutions: Corpus, //delete me @@ -236,7 +236,7 @@ where where Self: Executor, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, ::Solutions: Corpus, //delete me @@ -301,7 +301,7 @@ where ) -> Result where EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, { @@ -332,7 +332,7 @@ where ) -> Result where EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, ::Solutions: Corpus, //delete me @@ -371,7 +371,7 @@ where ) -> Result where EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State, Z: HasObjective, ::Solutions: Corpus, //delete me diff --git a/libafl/src/executors/inprocess_fork/mod.rs b/libafl/src/executors/inprocess_fork/mod.rs index d2f51cb1cf..834b3bdfc9 100644 --- a/libafl/src/executors/inprocess_fork/mod.rs +++ b/libafl/src/executors/inprocess_fork/mod.rs @@ -53,7 +53,7 @@ where OT: ObserversTuple, SP: ShMemProvider, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: HasSolutions, Z: HasObjective, { @@ -190,7 +190,7 @@ where OT: ObserversTuple, SP: ShMemProvider, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State + HasSolutions, Z: HasObjective, { diff --git a/libafl/src/executors/inprocess_fork/stateful.rs b/libafl/src/executors/inprocess_fork/stateful.rs index 53c04bf5b8..72d6ee0a34 100644 --- a/libafl/src/executors/inprocess_fork/stateful.rs +++ b/libafl/src/executors/inprocess_fork/stateful.rs @@ -38,7 +38,7 @@ where OT: ObserversTuple, SP: ShMemProvider, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State + HasSolutions, Z: HasObjective, { @@ -137,7 +137,7 @@ where HT: ExecutorHooksTuple, EM: EventFirer + EventRestarter, Z: HasObjective, - OF: Feedback, + OF: Feedback, { #[allow(unreachable_code)] #[inline] @@ -179,7 +179,7 @@ where SP: ShMemProvider, Z: UsesState, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: State + HasSolutions, Z: HasObjective, { diff --git a/libafl/src/feedbacks/concolic.rs b/libafl/src/feedbacks/concolic.rs index 12311994a3..5d5cda21eb 100644 --- a/libafl/src/feedbacks/concolic.rs +++ b/libafl/src/feedbacks/concolic.rs @@ -5,21 +5,17 @@ //! to be not interesting. //! Requires a [`ConcolicObserver`] to observe the concolic trace. use alloc::borrow::Cow; -use core::{fmt::Debug, marker::PhantomData}; +use core::fmt::Debug; use libafl_bolts::{ - tuples::{Handle, Handled, MatchNameRef}, + tuples::{Handle, Handled, MatchName, MatchNameRef}, Named, }; use crate::{ corpus::Testcase, - events::EventFirer, - executors::ExitKind, - feedbacks::Feedback, - inputs::UsesInput, - observers::{concolic::ConcolicObserver, ObserversTuple}, - state::State, + feedbacks::{Feedback, StateInitializer}, + observers::concolic::ConcolicObserver, Error, HasMetadata, }; @@ -29,60 +25,45 @@ use crate::{ /// to be not interesting. /// Requires a [`ConcolicObserver`] to observe the concolic trace. #[derive(Debug)] -pub struct ConcolicFeedback<'map, S> { +pub struct ConcolicFeedback<'map> { observer_handle: Handle>, - phantom: PhantomData, } -impl<'map, S> ConcolicFeedback<'map, S> { +impl<'map> ConcolicFeedback<'map> { /// Creates a concolic feedback from an observer #[allow(unused)] #[must_use] pub fn from_observer(observer: &ConcolicObserver<'map>) -> Self { Self { observer_handle: observer.handle(), - phantom: PhantomData, } } } -impl Named for ConcolicFeedback<'_, S> { +impl Named for ConcolicFeedback<'_> { fn name(&self) -> &Cow<'static, str> { self.observer_handle.name() } } -impl Feedback for ConcolicFeedback<'_, S> +impl StateInitializer for ConcolicFeedback<'_> {} + +impl Feedback for ConcolicFeedback<'_> where - S: State, + OT: MatchName, { - #[allow(clippy::wrong_self_convention)] - fn is_interesting( - &mut self, - _state: &mut S, - _manager: &mut EM, - _input: &::Input, - _observers: &OT, - _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + #[cfg(feature = "track_hit_feedbacks")] + fn last_result(&self) -> Result { Ok(false) } - fn append_metadata( + fn append_metadata( &mut self, _state: &mut S, _manager: &mut EM, observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { + testcase: &mut Testcase, + ) -> Result<(), Error> { if let Some(metadata) = observers .get(&self.observer_handle) .map(ConcolicObserver::create_metadata_from_current_map) @@ -91,17 +72,4 @@ where } Ok(()) } - - fn discard_metadata( - &mut self, - _state: &mut S, - _input: &::Input, - ) -> Result<(), Error> { - Ok(()) - } - - #[cfg(feature = "track_hit_feedbacks")] - fn last_result(&self) -> Result { - Ok(false) - } } diff --git a/libafl/src/feedbacks/custom_filename.rs b/libafl/src/feedbacks/custom_filename.rs index 5d1af8b2d0..df20ad23d4 100644 --- a/libafl/src/feedbacks/custom_filename.rs +++ b/libafl/src/feedbacks/custom_filename.rs @@ -1,135 +1,97 @@ use alloc::{borrow::Cow, string::String}; -use core::{ - fmt::{self, Debug, Formatter}, - marker::PhantomData, -}; +use core::fmt::{self, Debug, Formatter}; use libafl_bolts::Named; use serde::{Deserialize, Serialize}; use crate::{ corpus::Testcase, - events::EventFirer, - executors::ExitKind, - feedbacks::{Feedback, FeedbackFactory}, - inputs::Input, - observers::ObserversTuple, - state::State, + feedbacks::{Feedback, FeedbackFactory, StateInitializer}, Error, }; -/// A [`CustomFilenameToTestcaseFeedback`] takes a closure which returns a filename for the testcase. -/// +/// Type which can generate a custom filename for a given input/state pair +pub trait CustomFilenameGenerator { + /// Sets the name of the provided [`Testcase`] based on the state and input + fn set_name(&mut self, state: &mut S, testcase: &mut Testcase) -> Result; +} + +// maintain compatibility with old impls +impl CustomFilenameGenerator for F +where + F: FnMut(&mut S, &mut Testcase) -> Result, +{ + fn set_name(&mut self, state: &mut S, testcase: &mut Testcase) -> Result { + self(state, testcase) + } +} + +/// A [`CustomFilenameToTestcaseFeedback`] takes a [`CustomFilenameGenerator`] which returns a +/// filename for the testcase. /// Is never interesting (use with an Eager OR). +/// /// Note: Use only in conjunction with a `Corpus` type that writes to disk. /// Note: If used as part of the `Objective` chain, then it will only apply to testcases which are /// `Objectives`, vice versa for `Feedback`. #[derive(Serialize, Deserialize)] -pub struct CustomFilenameToTestcaseFeedback -where - I: Input, - S: State, - F: FnMut(&mut S, &mut Testcase) -> Result, -{ - /// Closure that returns the filename. - func: F, - phantomm: PhantomData<(I, S)>, +pub struct CustomFilenameToTestcaseFeedback { + /// Generator that returns the filename. + generator: N, } -impl CustomFilenameToTestcaseFeedback -where - I: Input, - S: State, - F: FnMut(&mut S, &mut Testcase) -> Result, -{ +impl CustomFilenameToTestcaseFeedback { /// Create a new [`CustomFilenameToTestcaseFeedback`]. - pub fn new(func: F) -> Self { + pub fn new(generator: N) -> Self { + Self { generator } + } +} + +impl FeedbackFactory, T> + for CustomFilenameToTestcaseFeedback +where + N: Clone, +{ + fn create_feedback(&self, _ctx: &T) -> CustomFilenameToTestcaseFeedback { Self { - func, - phantomm: PhantomData, + generator: self.generator.clone(), } } } -impl FeedbackFactory, T> - for CustomFilenameToTestcaseFeedback -where - I: Input, - S: State, - F: FnMut(&mut S, &mut Testcase) -> Result + Clone, -{ - fn create_feedback(&self, _ctx: &T) -> CustomFilenameToTestcaseFeedback { - Self { - func: self.func.clone(), - phantomm: self.phantomm, - } - } -} - -impl Named for CustomFilenameToTestcaseFeedback -where - I: Input, - S: State, - F: FnMut(&mut S, &mut Testcase) -> Result, -{ +impl Named for CustomFilenameToTestcaseFeedback { fn name(&self) -> &Cow<'static, str> { static NAME: Cow<'static, str> = Cow::Borrowed("CustomFilenameToTestcaseFeedback"); &NAME } } -impl Debug for CustomFilenameToTestcaseFeedback -where - I: Input, - S: State, - F: FnMut(&mut S, &mut Testcase) -> Result, -{ +impl Debug for CustomFilenameToTestcaseFeedback { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("CustomFilenameToTestcaseFeedback") .finish_non_exhaustive() } } -impl Feedback for CustomFilenameToTestcaseFeedback +impl StateInitializer for CustomFilenameToTestcaseFeedback {} + +impl Feedback for CustomFilenameToTestcaseFeedback where - S: State, - F: FnMut(&mut S, &mut Testcase) -> Result, - I: Input, + N: CustomFilenameGenerator, { - #[allow(clippy::wrong_self_convention)] - #[inline] - fn is_interesting( - &mut self, - _state: &mut S, - _manager: &mut EM, - _input: &I, - _observers: &OT, - _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - { - Ok(false) - } - - fn append_metadata( - &mut self, - state: &mut S, - _manager: &mut EM, - _observers: &OT, - testcase: &mut Testcase<::Input>, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { - *testcase.filename_mut() = Some((self.func)(state, testcase)?); - Ok(()) - } - #[cfg(feature = "track_hit_feedbacks")] #[inline] fn last_result(&self) -> Result { Ok(false) } + + fn append_metadata( + &mut self, + state: &mut S, + _manager: &mut EM, + _observers: &OT, + testcase: &mut Testcase, + ) -> Result<(), Error> { + *testcase.filename_mut() = Some(self.generator.set_name(state, testcase)?); + Ok(()) + } } diff --git a/libafl/src/feedbacks/differential.rs b/libafl/src/feedbacks/differential.rs index dcbe1a6878..54c3f6ffc7 100644 --- a/libafl/src/feedbacks/differential.rs +++ b/libafl/src/feedbacks/differential.rs @@ -2,10 +2,7 @@ //! use alloc::borrow::Cow; -use core::{ - fmt::{self, Debug, Formatter}, - marker::PhantomData, -}; +use core::fmt::{self, Debug, Formatter}; use libafl_bolts::{ tuples::{Handle, Handled, MatchName, MatchNameRef}, @@ -16,13 +13,9 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "track_hit_feedbacks")] use crate::feedbacks::premature_last_result_err; use crate::{ - events::EventFirer, executors::ExitKind, - feedbacks::{Feedback, FeedbackFactory}, - inputs::Input, - observers::{Observer, ObserversTuple}, - state::State, - Error, HasMetadata, + feedbacks::{Feedback, FeedbackFactory, StateInitializer}, + Error, }; /// The result of a differential test between two observers. @@ -51,12 +44,24 @@ impl DiffResult { } } -/// A [`DiffFeedback`] compares the content of two [`Observer`]s using the given compare function. -#[derive(Serialize, Deserialize)] -pub struct DiffFeedback +/// Compares two [`crate::observers::Observer`]s to see if the result should be denoted as equal +pub trait DiffComparator { + /// Performs the comparison between two [`crate::observers::Observer`]s + fn compare(&mut self, first: &O1, second: &O2) -> DiffResult; +} + +impl DiffComparator for F where - F: FnMut(&O1, &O2) -> DiffResult, + F: Fn(&O1, &O2) -> DiffResult, { + fn compare(&mut self, first: &O1, second: &O2) -> DiffResult { + self(first, second) + } +} + +/// A [`DiffFeedback`] compares the content of two observers using the given compare function. +#[derive(Serialize, Deserialize)] +pub struct DiffFeedback { /// This feedback's name name: Cow<'static, str>, /// The first observer to compare against @@ -66,19 +71,17 @@ where // The previous run's result of `Self::is_interesting` #[cfg(feature = "track_hit_feedbacks")] last_result: Option, - /// The function used to compare the two observers - compare_fn: F, - phantomm: PhantomData<(I, S)>, + /// The comparator used to compare the two observers + comparator: C, } -impl DiffFeedback +impl DiffFeedback where - F: FnMut(&O1, &O2) -> DiffResult, O1: Named, O2: Named, { /// Create a new [`DiffFeedback`] using two observers and a test function. - pub fn new(name: &'static str, o1: &O1, o2: &O2, compare_fn: F) -> Result { + pub fn new(name: &'static str, o1: &O1, o2: &O2, comparator: C) -> Result { let o1_ref = o1.handle(); let o2_ref = o2.handle(); if o1_ref.name() == o2_ref.name() { @@ -93,51 +96,38 @@ where name: Cow::from(name), #[cfg(feature = "track_hit_feedbacks")] last_result: None, - compare_fn, - phantomm: PhantomData, + comparator, }) } } } -impl FeedbackFactory, T> - for DiffFeedback +impl FeedbackFactory, T> for DiffFeedback where - F: FnMut(&O1, &O2) -> DiffResult + Clone, - I: Input, - O1: Observer + Named, - O2: Observer + Named, - S: HasMetadata + State, + C: Clone, { - fn create_feedback(&self, _ctx: &T) -> DiffFeedback { + fn create_feedback(&self, _ctx: &T) -> DiffFeedback { Self { name: self.name.clone(), o1_ref: self.o1_ref.clone(), o2_ref: self.o2_ref.clone(), - compare_fn: self.compare_fn.clone(), + comparator: self.comparator.clone(), #[cfg(feature = "track_hit_feedbacks")] last_result: None, - phantomm: self.phantomm, } } } -impl Named for DiffFeedback -where - F: FnMut(&O1, &O2) -> DiffResult, - O1: Named, - O2: Named, -{ +impl Named for DiffFeedback { fn name(&self) -> &Cow<'static, str> { &self.name } } -impl Debug for DiffFeedback +impl Debug for DiffFeedback where - F: FnMut(&O1, &O2) -> DiffResult, - O1: Named, - O2: Named, + O1: Debug, + O2: Debug, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("DiffFeedback") @@ -148,27 +138,22 @@ where } } -impl Feedback for DiffFeedback +impl StateInitializer for DiffFeedback {} + +impl Feedback for DiffFeedback where - F: FnMut(&O1, &O2) -> DiffResult, - I: Input, - S: HasMetadata + State, - O1: Observer, - O2: Observer, + OT: MatchName, + C: DiffComparator, { #[allow(clippy::wrong_self_convention)] - fn is_interesting( + fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, _input: &I, observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple + MatchName, - { + ) -> Result { fn err(name: &str) -> Error { Error::illegal_argument(format!("DiffFeedback: observer {name} not found")) } @@ -178,7 +163,7 @@ where let o2: &O2 = observers .get(&self.o2_ref) .ok_or_else(|| err(self.o2_ref.name()))?; - let res = (self.compare_fn)(o1, o2) == DiffResult::Diff; + let res = self.comparator.compare(o1, o2) == DiffResult::Diff; #[cfg(feature = "track_hit_feedbacks")] { self.last_result = Some(res); @@ -195,25 +180,24 @@ where #[cfg(test)] mod tests { use alloc::borrow::Cow; - use core::marker::PhantomData; use libafl_bolts::{tuples::tuple_list, Named}; use crate::{ - events::EventFirer, + events::NopEventManager, executors::ExitKind, feedbacks::{differential::DiffResult, DiffFeedback, Feedback}, inputs::BytesInput, observers::Observer, - state::{NopState, State, UsesState}, + state::NopState, }; #[derive(Debug)] - struct NopObserver { + struct DummyObserver { name: Cow<'static, str>, value: bool, } - impl NopObserver { + impl DummyObserver { fn new(name: &'static str, value: bool) -> Self { Self { name: Cow::from(name), @@ -221,72 +205,45 @@ mod tests { } } } - impl Observer for NopObserver {} - impl PartialEq for NopObserver { + impl Observer for DummyObserver {} + impl PartialEq for DummyObserver { fn eq(&self, other: &Self) -> bool { self.value == other.value } } - impl Named for NopObserver { + impl Named for DummyObserver { fn name(&self) -> &Cow<'static, str> { &self.name } } - struct NopEventFirer { - phantom: PhantomData, - } - impl UsesState for NopEventFirer - where - S: State, - { - type State = S; - } - impl EventFirer for NopEventFirer - where - S: State, - { - fn should_send(&self) -> bool { - true - } - - fn fire( - &mut self, - _state: &mut S, - _event: crate::events::Event, - ) -> Result<(), crate::Error> { - Ok(()) + fn comparator(o1: &DummyObserver, o2: &DummyObserver) -> DiffResult { + if o1 == o2 { + DiffResult::Equal + } else { + DiffResult::Diff } } fn test_diff(should_equal: bool) { - let mut nop_state = NopState::new(); + let mut nop_state: NopState = NopState::new(); - let o1 = NopObserver::new("o1", true); - let o2 = NopObserver::new("o2", should_equal); + let o1 = DummyObserver::new("o1", true); + let o2 = DummyObserver::new("o2", should_equal); - let mut diff_feedback = DiffFeedback::new("diff_feedback", &o1, &o2, |o1, o2| { - if o1 == o2 { - DiffResult::Equal - } else { - DiffResult::Diff - } - }) - .unwrap(); + let mut diff_feedback = DiffFeedback::new("diff_feedback", &o1, &o2, comparator).unwrap(); let observers = tuple_list![o1, o2]; assert_eq!( !should_equal, - diff_feedback - .is_interesting( - &mut nop_state, - &mut NopEventFirer { - phantom: PhantomData - }, - &BytesInput::new(vec![0]), - &observers, - &ExitKind::Ok - ) - .unwrap() + DiffFeedback::<_, _, _>::is_interesting( + &mut diff_feedback, + &mut nop_state, + &mut NopEventManager::>::default(), + &BytesInput::new(vec![0]), + &observers, + &ExitKind::Ok + ) + .unwrap() ); } diff --git a/libafl/src/feedbacks/list.rs b/libafl/src/feedbacks/list.rs index 93adcfc2b8..1270938a48 100644 --- a/libafl/src/feedbacks/list.rs +++ b/libafl/src/feedbacks/list.rs @@ -3,46 +3,34 @@ use core::{fmt::Debug, hash::Hash}; use hashbrown::HashSet; use libafl_bolts::{ - tuples::{Handle, Handled, MatchNameRef}, + tuples::{Handle, Handled, MatchName, MatchNameRef}, Error, HasRefCnt, Named, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ - events::EventFirer, executors::ExitKind, - feedbacks::Feedback, - observers::{ListObserver, ObserversTuple}, - state::State, + feedbacks::{Feedback, StateInitializer}, + observers::ListObserver, HasNamedMetadata, }; /// The metadata to remember past observed value #[derive(Default, Serialize, Deserialize, Clone, Debug)] -#[serde(bound = "T: DeserializeOwned")] -#[cfg_attr( - any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) -)] -pub struct ListFeedbackMetadata -where - T: Default + Copy + 'static + Serialize + Eq + Hash, -{ +#[serde(bound = "T: Eq + Hash + for<'a> Deserialize<'a> + Serialize")] +pub struct ListFeedbackMetadata { /// Contains the information of past observed set of values. pub set: HashSet, /// A refcount used to know when we can remove this metadata pub tcref: isize, } -impl ListFeedbackMetadata -where - T: Default + Copy + 'static + Serialize + Eq + Hash, -{ +impl ListFeedbackMetadata { /// The constructor #[must_use] pub fn new() -> Self { Self { - set: HashSet::::new(), + set: HashSet::new(), tcref: 0, } } @@ -54,10 +42,7 @@ where } } -impl HasRefCnt for ListFeedbackMetadata -where - T: Default + Copy + 'static + Serialize + Eq + Hash, -{ +impl HasRefCnt for ListFeedbackMetadata { fn refcnt(&self) -> isize { self.tcref } @@ -69,10 +54,7 @@ where /// Consider interesting a testcase if the list in `ListObserver` is not empty. #[derive(Clone, Debug)] -pub struct ListFeedback -where - T: Hash + Eq, -{ +pub struct ListFeedback { observer_handle: Handle>, novelty: HashSet, } @@ -82,30 +64,32 @@ libafl_bolts::impl_serdeany!( ,,,,,,,,,, ); -impl Feedback for ListFeedback +impl StateInitializer for ListFeedback where - S: State + HasNamedMetadata, + S: HasNamedMetadata, T: Debug + Serialize + Hash + Eq + DeserializeOwned + Default + Copy + 'static, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { - // eprintln!("self.name {:#?}", &self.name); state.add_named_metadata(self.name(), ListFeedbackMetadata::::default()); Ok(()) } +} + +impl Feedback for ListFeedback +where + OT: MatchName, + S: HasNamedMetadata, + T: Debug + Serialize + Hash + Eq + DeserializeOwned + Default + Copy + 'static, +{ #[allow(clippy::wrong_self_convention)] - fn is_interesting( + fn is_interesting( &mut self, state: &mut S, _manager: &mut EM, - _input: &S::Input, + _input: &I, observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { - // TODO Replace with match_name_type when stable + ) -> Result { let observer = observers.get(&self.observer_handle).unwrap(); // TODO register the list content in a testcase metadata self.novelty.clear(); @@ -122,17 +106,18 @@ where Ok(!self.novelty.is_empty()) } - fn append_metadata( + #[cfg(feature = "track_hit_feedbacks")] + fn last_result(&self) -> Result { + Ok(!self.novelty.is_empty()) + } + + fn append_metadata( &mut self, state: &mut S, _manager: &mut EM, _observers: &OT, - _testcase: &mut crate::corpus::Testcase<::Input>, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { + _testcase: &mut crate::corpus::Testcase, + ) -> Result<(), Error> { let history_set = state .named_metadata_map_mut() .get_mut::>(self.name()) @@ -143,32 +128,22 @@ where } Ok(()) } - #[cfg(feature = "track_hit_feedbacks")] - fn last_result(&self) -> Result { - Ok(!self.novelty.is_empty()) - } } -impl Named for ListFeedback -where - T: Debug + Serialize + Hash + Eq + DeserializeOwned, -{ +impl Named for ListFeedback { #[inline] fn name(&self) -> &Cow<'static, str> { self.observer_handle.name() } } -impl ListFeedback -where - T: Debug + Serialize + Hash + Eq + DeserializeOwned, -{ +impl ListFeedback { /// Creates a new [`ListFeedback`], deciding if the given [`ListObserver`] value of a run is interesting. #[must_use] pub fn new(observer: &ListObserver) -> Self { Self { observer_handle: observer.handle(), - novelty: HashSet::::new(), + novelty: HashSet::new(), } } } diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index 64518f8c57..75a4e13bcb 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -12,7 +12,7 @@ use core::{ #[rustversion::nightly] use libafl_bolts::AsSlice; use libafl_bolts::{ - tuples::{Handle, Handled, MatchNameRef}, + tuples::{Handle, Handled, MatchName, MatchNameRef}, AsIter, HasRefCnt, Named, }; use num_traits::PrimInt; @@ -24,37 +24,33 @@ use crate::{ corpus::Testcase, events::{Event, EventFirer}, executors::ExitKind, - feedbacks::{Feedback, HasObserverHandle}, + feedbacks::{Feedback, HasObserverHandle, StateInitializer}, inputs::UsesInput, monitors::{AggregatorOps, UserStats, UserStatsValue}, - observers::{CanTrack, MapObserver, Observer, ObserversTuple}, - state::State, + observers::{CanTrack, MapObserver}, Error, HasMetadata, HasNamedMetadata, }; /// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from (`HitcountsMapObserver`)[`crate::observers::HitcountsMapObserver`]. -pub type AflMapFeedback = MapFeedback; +pub type AflMapFeedback = MapFeedback; /// A [`MapFeedback`] that strives to maximize the map contents. -pub type MaxMapFeedback = MapFeedback; +pub type MaxMapFeedback = MapFeedback; /// A [`MapFeedback`] that strives to minimize the map contents. -pub type MinMapFeedback = MapFeedback; +pub type MinMapFeedback = MapFeedback; /// A [`MapFeedback`] that always returns `true` for `is_interesting`. Useful for tracing all executions. -pub type AlwaysInterestingMapFeedback = MapFeedback; +pub type AlwaysInterestingMapFeedback = MapFeedback; /// A [`MapFeedback`] that strives to maximize the map contents, /// but only, if a value is larger than `pow2` of the previous. -pub type MaxMapPow2Feedback = MapFeedback; +pub type MaxMapPow2Feedback = MapFeedback; /// A [`MapFeedback`] that strives to maximize the map contents, /// but only, if a value is either `T::one()` or `T::max_value()`. -pub type MaxMapOneOrFilledFeedback = MapFeedback; +pub type MaxMapOneOrFilledFeedback = MapFeedback; /// A `Reducer` function is used to aggregate values for the novelty search -pub trait Reducer: 'static -where - T: Default + Copy + 'static, -{ +pub trait Reducer { /// Reduce two values to one value, with the current [`Reducer`]. fn reduce(first: T, second: T) -> T; } @@ -65,7 +61,7 @@ pub struct OrReducer {} impl Reducer for OrReducer where - T: BitOr + Default + Copy + 'static + PartialOrd, + T: BitOr, { #[inline] fn reduce(history: T, new: T) -> T { @@ -79,7 +75,7 @@ pub struct AndReducer {} impl Reducer for AndReducer where - T: BitAnd + Default + Copy + 'static + PartialOrd, + T: BitAnd, { #[inline] fn reduce(history: T, new: T) -> T { @@ -91,10 +87,7 @@ where #[derive(Clone, Debug)] pub struct NopReducer {} -impl Reducer for NopReducer -where - T: Default + Copy + 'static, -{ +impl Reducer for NopReducer { #[inline] fn reduce(_history: T, new: T) -> T { new @@ -107,7 +100,7 @@ pub struct MaxReducer {} impl Reducer for MaxReducer where - T: Default + Copy + 'static + PartialOrd, + T: PartialOrd, { #[inline] fn reduce(first: T, second: T) -> T { @@ -125,7 +118,7 @@ pub struct MinReducer {} impl Reducer for MinReducer where - T: Default + Copy + 'static + PartialOrd, + T: PartialOrd, { #[inline] fn reduce(first: T, second: T) -> T { @@ -138,10 +131,7 @@ where } /// A `IsNovel` function is used to discriminate if a reduced value is considered novel. -pub trait IsNovel: 'static -where - T: Default + Copy + 'static, -{ +pub trait IsNovel { /// If a new value in the [`MapFeedback`] was found, /// this filter can decide if the result is considered novel or not. fn is_novel(old: T, new: T) -> bool; @@ -225,11 +215,8 @@ where } /// A testcase metadata holding a list of indexes of a map -#[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) -)] // for SerdeAny +#[derive(Debug, Serialize, Deserialize)] +#[allow(clippy::unsafe_derive_deserialize)] // for SerdeAny pub struct MapIndexesMetadata { /// The list of indexes. pub list: Vec, @@ -274,10 +261,7 @@ impl MapIndexesMetadata { /// A testcase metadata holding a list of indexes of a map #[derive(Debug, Serialize, Deserialize)] -#[cfg_attr( - any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) -)] // for SerdeAny +#[allow(clippy::unsafe_derive_deserialize)] // for SerdeAny pub struct MapNoveltiesMetadata { /// A `list` of novelties. pub list: Vec, @@ -312,15 +296,8 @@ impl MapNoveltiesMetadata { /// The state of [`MapFeedback`] #[derive(Default, Serialize, Deserialize, Clone, Debug)] -#[serde(bound = "T: DeserializeOwned")] -#[cfg_attr( - any(not(feature = "serdeany_autoreg"), miri), - allow(clippy::unsafe_derive_deserialize) -)] // for SerdeAny -pub struct MapFeedbackMetadata -where - T: Default + Copy + 'static + Serialize, -{ +#[allow(clippy::unsafe_derive_deserialize)] // for SerdeAny +pub struct MapFeedbackMetadata { /// Contains information about untouched entries pub history_map: Vec, /// Tells us how many non-initial entries there are in `history_map` @@ -328,7 +305,7 @@ where } libafl_bolts::impl_serdeany!( - MapFeedbackMetadata, + MapFeedbackMetadata, ,,,,,,,,,,,, ); @@ -384,7 +361,7 @@ where /// The most common AFL-like feedback type #[derive(Clone, Debug)] -pub struct MapFeedback { +pub struct MapFeedback { /// New indexes observed in the last observation novelties: Option>, /// Name identifier of this instance @@ -397,38 +374,44 @@ pub struct MapFeedback { #[cfg(feature = "track_hit_feedbacks")] last_result: Option, /// Phantom Data of Reducer - phantom: PhantomData<(C, N, O, R, T)>, + #[allow(clippy::type_complexity)] + phantom: PhantomData (N, O, R)>, } -impl Feedback for MapFeedback +impl StateInitializer for MapFeedback where - N: IsNovel, - O: MapObserver + for<'it> AsIter<'it, Item = T>, - R: Reducer, - S: State + HasNamedMetadata, - T: Default + Copy + Serialize + for<'de> Deserialize<'de> + PartialEq + Debug + 'static, - C: CanTrack + AsRef + Named, + O: MapObserver, + O::Entry: 'static + Default + Debug + DeserializeOwned + Serialize, + S: HasNamedMetadata, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { // Initialize `MapFeedbackMetadata` with an empty vector and add it to the state. // The `MapFeedbackMetadata` would be resized on-demand in `is_interesting` - state.add_named_metadata(&self.name, MapFeedbackMetadata::::default()); + state.add_named_metadata(&self.name, MapFeedbackMetadata::::default()); Ok(()) } +} +impl Feedback for MapFeedback +where + C: CanTrack + AsRef, + EM: EventFirer, + N: IsNovel, + O: MapObserver + for<'it> AsIter<'it, Item = O::Entry>, + O::Entry: 'static + Default + Debug + DeserializeOwned + Serialize, + OT: MatchName, + R: Reducer, + S: HasNamedMetadata + UsesInput, // delete me +{ #[rustversion::nightly] - default fn is_interesting( + default fn is_interesting( &mut self, state: &mut S, manager: &mut EM, - input: &S::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { let res = self.is_interesting_default(state, manager, input, observers, exit_kind); #[cfg(feature = "track_hit_feedbacks")] { @@ -438,18 +421,14 @@ where } #[rustversion::not(nightly)] - fn is_interesting( + fn is_interesting( &mut self, state: &mut S, manager: &mut EM, - input: &::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple<::Input, S>, - { + ) -> Result { let res = self.is_interesting_default(state, manager, input, observers, exit_kind); #[cfg(feature = "track_hit_feedbacks")] @@ -459,17 +438,18 @@ where Ok(res) } - fn append_metadata( + #[cfg(feature = "track_hit_feedbacks")] + fn last_result(&self) -> Result { + self.last_result.ok_or(premature_last_result_err()) + } + + fn append_metadata( &mut self, state: &mut S, manager: &mut EM, observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { + testcase: &mut Testcase, + ) -> Result<(), Error> { if let Some(novelties) = self.novelties.as_mut().map(core::mem::take) { let meta = MapNoveltiesMetadata::new(novelties); testcase.add_metadata(meta); @@ -478,7 +458,7 @@ where let initial = observer.initial(); let map_state = state .named_metadata_map_mut() - .get_mut::>(&self.name) + .get_mut::>(&self.name) .unwrap(); let len = observer.len(); if map_state.history_map.len() < len { @@ -551,35 +531,28 @@ where Ok(()) } - - #[cfg(feature = "track_hit_feedbacks")] - fn last_result(&self) -> Result { - self.last_result.ok_or(premature_last_result_err()) - } } /// Specialize for the common coverage map size, maximization of u8s #[rustversion::nightly] -impl Feedback for MapFeedback +impl Feedback for MapFeedback where + C: CanTrack + AsRef, + EM: EventFirer, O: MapObserver + for<'a> AsSlice<'a, Entry = u8> + for<'a> AsIter<'a, Item = u8>, - S: State + HasNamedMetadata, - C: CanTrack + AsRef + Observer, + OT: MatchName, + S: HasNamedMetadata + UsesInput, { #[allow(clippy::wrong_self_convention)] #[allow(clippy::needless_range_loop)] - fn is_interesting( + fn is_interesting( &mut self, state: &mut S, _manager: &mut EM, - _input: &S::Input, + _input: &I, observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { // 128 bits vectors type VectorType = core::simd::u8x16; @@ -679,18 +652,14 @@ where } } -impl Named for MapFeedback { +impl Named for MapFeedback { #[inline] fn name(&self) -> &Cow<'static, str> { &self.name } } -impl HasObserverHandle for MapFeedback -where - O: Named, - C: AsRef, -{ +impl HasObserverHandle for MapFeedback { type Observer = C; #[inline] @@ -708,14 +677,9 @@ fn create_stats_name(name: &Cow<'static, str>) -> Cow<'static, str> { } } -impl MapFeedback +impl MapFeedback where - T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, - R: Reducer, - O: MapObserver, - for<'it> O: AsIter<'it, Item = T>, - N: IsNovel, - C: CanTrack + AsRef + Named, + C: CanTrack + Named + AsRef, { /// Create new `MapFeedback` #[must_use] @@ -747,22 +711,30 @@ where phantom: PhantomData, } } +} +impl MapFeedback +where + R: Reducer, + O: MapObserver + for<'it> AsIter<'it, Item = O::Entry>, + O::Entry: 'static + Debug + Serialize + DeserializeOwned, + N: IsNovel, + C: AsRef, +{ #[allow(clippy::wrong_self_convention)] #[allow(clippy::needless_range_loop)] #[allow(clippy::trivially_copy_pass_by_ref)] - fn is_interesting_default( + fn is_interesting_default( &mut self, state: &mut S, _manager: &mut EM, - _input: &S::Input, + _input: &I, observers: &OT, _exit_kind: &ExitKind, ) -> bool where - EM: EventFirer, - OT: ObserversTuple, - S: UsesInput + HasNamedMetadata, + S: HasNamedMetadata, + OT: MatchName, { let mut interesting = false; // TODO Replace with match_name_type when stable @@ -770,7 +742,7 @@ where let map_state = state .named_metadata_map_mut() - .get_mut::>(&self.name) + .get_mut::>(&self.name) .unwrap(); let len = observer.len(); if map_state.history_map.len() < len { diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index fe5c47b6d7..4659948cff 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -7,16 +7,13 @@ use alloc::borrow::Cow; #[cfg(feature = "track_hit_feedbacks")] use alloc::vec::Vec; -use core::{ - fmt::{self, Debug, Formatter}, - marker::PhantomData, -}; +use core::{fmt::Debug, marker::PhantomData}; #[cfg(feature = "std")] pub use concolic::ConcolicFeedback; pub use differential::DiffFeedback; use libafl_bolts::{ - tuples::{Handle, Handled, MatchNameRef}, + tuples::{Handle, Handled, MatchName, MatchNameRef}, Named, }; pub use list::*; @@ -29,14 +26,7 @@ pub use new_hash_feedback::NewHashFeedback; pub use new_hash_feedback::NewHashFeedbackMetadata; use serde::{Deserialize, Serialize}; -use crate::{ - corpus::Testcase, - events::EventFirer, - executors::ExitKind, - observers::{ObserversTuple, TimeObserver}, - state::State, - Error, -}; +use crate::{corpus::Testcase, executors::ExitKind, observers::TimeObserver, Error}; #[cfg(feature = "std")] pub mod concolic; #[cfg(feature = "std")] @@ -54,49 +44,53 @@ pub mod new_hash_feedback; pub mod stdio; pub mod transferred; -/// Feedbacks evaluate the observers. -/// Basically, they reduce the information provided by an observer to a value, -/// indicating the "interestingness" of the last run. -pub trait Feedback: Named -where - S: State, -{ +#[cfg(feature = "introspection")] +use crate::state::HasClientPerfMonitor; + +/// Feedback which initializes a state. +/// +/// This trait is separate from the general [`Feedback`] definition as it would not be sufficiently +/// specified otherwise. +pub trait StateInitializer { /// Initializes the feedback state. /// This method is called after that the `State` is created. fn init_state(&mut self, _state: &mut S) -> Result<(), Error> { Ok(()) } +} +/// Feedbacks evaluate the observers. +/// Basically, they reduce the information provided by an observer to a value, +/// indicating the "interestingness" of the last run. +pub trait Feedback: StateInitializer + Named { /// `is_interesting ` return if an input is worth the addition to the corpus #[allow(clippy::wrong_self_convention)] - fn is_interesting( + fn is_interesting( &mut self, - state: &mut S, - manager: &mut EM, - input: &S::Input, - observers: &OT, - exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple; + _state: &mut S, + _manager: &mut EM, + _input: &I, + _observers: &OT, + _exit_kind: &ExitKind, + ) -> Result { + Ok(false) + } /// Returns if the result of a run is interesting and the value input should be stored in a corpus. /// It also keeps track of introspection stats. #[cfg(feature = "introspection")] #[allow(clippy::too_many_arguments)] #[allow(clippy::wrong_self_convention)] - fn is_interesting_introspection( + fn is_interesting_introspection( &mut self, state: &mut S, manager: &mut EM, - input: &S::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + S: HasClientPerfMonitor, { // Start a timer for this feedback let start_time = libafl_bolts::cpu::read_time_counter(); @@ -131,25 +125,23 @@ where } /// Append to the testcase the generated metadata in case of a new corpus item + /// + /// Precondition: `testcase` must contain an input. #[inline] #[allow(unused_variables)] - fn append_metadata( + fn append_metadata( &mut self, - state: &mut S, - manager: &mut EM, - observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { + _state: &mut S, + _manager: &mut EM, + _observers: &OT, + _testcase: &mut Testcase, + ) -> Result<(), Error> { Ok(()) } /// Discard the stored metadata in case that the testcase is not added to the corpus #[inline] - fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { + fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { Ok(()) } } @@ -165,39 +157,26 @@ pub trait HasObserverHandle { /// A combined feedback consisting of multiple [`Feedback`]s #[derive(Debug)] -pub struct CombinedFeedback -where - A: Feedback, - B: Feedback, - FL: FeedbackLogic, - S: State, -{ +pub struct CombinedFeedback { /// First [`Feedback`] pub first: A, /// Second [`Feedback`] pub second: B, name: Cow<'static, str>, - phantom: PhantomData<(S, FL)>, + phantom: PhantomData, } -impl Named for CombinedFeedback -where - A: Feedback, - B: Feedback, - FL: FeedbackLogic, - S: State, -{ +impl Named for CombinedFeedback { fn name(&self) -> &Cow<'static, str> { &self.name } } -impl CombinedFeedback +impl CombinedFeedback where - A: Feedback, - B: Feedback, - FL: FeedbackLogic, - S: State, + A: Named, + B: Named, + FL: FeedbackLogic, { /// Create a new combined feedback pub fn new(first: A, second: B) -> Self { @@ -216,42 +195,42 @@ where } } -impl Feedback for CombinedFeedback +impl StateInitializer for CombinedFeedback where - A: Feedback, - B: Feedback, - FL: FeedbackLogic, - S: State, + A: StateInitializer, + B: StateInitializer, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { self.first.init_state(state)?; self.second.init_state(state)?; Ok(()) } - #[cfg(feature = "track_hit_feedbacks")] - fn last_result(&self) -> Result { - FL::last_result(&self.first, &self.second) - } - #[cfg(feature = "track_hit_feedbacks")] - fn append_hit_feedbacks(&self, list: &mut Vec>) -> Result<(), Error> { - FL::append_hit_feedbacks(&self.first, &self.second, list) - } +} + +impl Feedback for CombinedFeedback +where + A: Feedback, + B: Feedback, + FL: FeedbackLogic, +{ #[allow(clippy::wrong_self_convention)] - fn is_interesting( + fn is_interesting( &mut self, state: &mut S, manager: &mut EM, - input: &S::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { FL::is_pair_interesting( - &mut self.first, - &mut self.second, + |state, manager, input, observers, exit_kind| { + self.first + .is_interesting(state, manager, input, observers, exit_kind) + }, + |state, manager, input, observers, exit_kind| { + self.second + .is_interesting(state, manager, input, observers, exit_kind) + }, state, manager, input, @@ -262,21 +241,26 @@ where #[cfg(feature = "introspection")] #[allow(clippy::wrong_self_convention)] - fn is_interesting_introspection( + fn is_interesting_introspection( &mut self, state: &mut S, manager: &mut EM, - input: &S::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + S: HasClientPerfMonitor, { - FL::is_pair_interesting_introspection( - &mut self.first, - &mut self.second, + FL::is_pair_interesting( + |state, manager, input, observers, exit_kind| { + self.first + .is_interesting_introspection(state, manager, input, observers, exit_kind) + }, + |state, manager, input, observers, exit_kind| { + self.second + .is_interesting_introspection(state, manager, input, observers, exit_kind) + }, state, manager, input, @@ -285,18 +269,30 @@ where ) } + #[cfg(feature = "track_hit_feedbacks")] + fn last_result(&self) -> Result { + FL::last_result(self.first.last_result(), self.second.last_result()) + } + + #[cfg(feature = "track_hit_feedbacks")] + fn append_hit_feedbacks(&self, list: &mut Vec>) -> Result<(), Error> { + FL::append_hit_feedbacks( + self.first.last_result(), + |list| self.first.append_hit_feedbacks(list), + self.second.last_result(), + |list| self.second.append_hit_feedbacks(list), + list, + ) + } + #[inline] - fn append_metadata( + fn append_metadata( &mut self, state: &mut S, manager: &mut EM, observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { + testcase: &mut Testcase, + ) -> Result<(), Error> { self.first .append_metadata(state, manager, observers, testcase)?; self.second @@ -304,21 +300,19 @@ where } #[inline] - fn discard_metadata(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { + fn discard_metadata(&mut self, state: &mut S, input: &I) -> Result<(), Error> { self.first.discard_metadata(state, input)?; self.second.discard_metadata(state, input) } } -impl FeedbackFactory, T> - for CombinedFeedback +impl FeedbackFactory, T> for CombinedFeedback where - A: Feedback + FeedbackFactory, - B: Feedback + FeedbackFactory, - FL: FeedbackLogic, - S: State, + A: FeedbackFactory + Named, + B: FeedbackFactory + Named, + FL: FeedbackLogic, { - fn create_feedback(&self, ctx: &T) -> CombinedFeedback { + fn create_feedback(&self, ctx: &T) -> CombinedFeedback { CombinedFeedback::new( self.first.create_feedback(ctx), self.second.create_feedback(ctx), @@ -327,58 +321,46 @@ where } /// Logical combination of two feedbacks -pub trait FeedbackLogic: 'static -where - A: Feedback, - B: Feedback, - S: State, -{ +pub trait FeedbackLogic { /// The name of this combination fn name() -> &'static str; - /// If the feedback pair is interesting - fn is_pair_interesting( - first: &mut A, - second: &mut B, + /// If the feedback pair is interesting. + /// + /// `first` and `second` are closures which invoke the corresponding + /// [`Feedback::is_interesting`] methods of the associated feedbacks. Implementors may choose to + /// use the closure or not, depending on eagerness logic + fn is_pair_interesting( + first: F1, + second: F2, state: &mut S, manager: &mut EM, - input: &S::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple; + F1: FnOnce(&mut S, &mut EM, &I, &OT, &ExitKind) -> Result, + F2: FnOnce(&mut S, &mut EM, &I, &OT, &ExitKind) -> Result; /// Get the result of the last `Self::is_interesting` run #[cfg(feature = "track_hit_feedbacks")] - fn last_result(first: &A, second: &B) -> Result; + fn last_result(first: Result, second: Result) -> Result; - /// Append this [`Feedback`]'s name if [`Feedback::last_result`] is true - /// If you have any nested Feedbacks, you must call this function on them if relevant. - /// See the implementations of [`CombinedFeedback`] + /// Append each [`Feedback`]'s name according to the logic implemented by this + /// [`FeedbackLogic`]. `if_first` and `if_second` are closures which invoke the corresponding + /// [`Feedback::append_hit_feedbacks`] logics of the relevant closures. #[cfg(feature = "track_hit_feedbacks")] - fn append_hit_feedbacks( - first: &A, - second: &B, + fn append_hit_feedbacks( + first_result: Result, + if_first: F1, + second_result: Result, + if_second: F2, list: &mut Vec>, - ) -> Result<(), Error>; - - /// If this pair is interesting (with introspection features enabled) - #[cfg(feature = "introspection")] - #[allow(clippy::too_many_arguments)] - fn is_pair_interesting_introspection( - first: &mut A, - second: &mut B, - state: &mut S, - manager: &mut EM, - input: &S::Input, - observers: &OT, - exit_kind: &ExitKind, - ) -> Result + ) -> Result<(), Error> where - EM: EventFirer, - OT: ObserversTuple; + F1: FnOnce(&mut Vec>) -> Result<(), Error>, + F2: FnOnce(&mut Vec>) -> Result<(), Error>; } /// Factory for feedbacks which should be sensitive to an existing context, e.g. observer(s) from a @@ -397,451 +379,321 @@ where } } /// Eager `OR` combination of two feedbacks +/// +/// When the `track_hit_feedbacks` feature is used, [`LogicEagerOr`]'s hit feedback preferences will +/// behave like [`LogicFastOr`]'s because the second feedback will not have contributed to the +/// result. When using [`crate::feedback_or`], ensure that you set the first parameter to the +/// prioritized feedback. #[derive(Debug, Clone)] -pub struct LogicEagerOr {} - +pub struct LogicEagerOr; /// Fast `OR` combination of two feedbacks #[derive(Debug, Clone)] -pub struct LogicFastOr {} +pub struct LogicFastOr; /// Eager `AND` combination of two feedbacks #[derive(Debug, Clone)] -pub struct LogicEagerAnd {} +pub struct LogicEagerAnd; /// Fast `AND` combination of two feedbacks #[derive(Debug, Clone)] -pub struct LogicFastAnd {} +pub struct LogicFastAnd; -impl FeedbackLogic for LogicEagerOr -where - A: Feedback, - B: Feedback, - S: State, -{ +impl FeedbackLogic for LogicEagerOr { fn name() -> &'static str { "Eager OR" } - fn is_pair_interesting( - first: &mut A, - second: &mut B, + fn is_pair_interesting( + first: F1, + second: F2, state: &mut S, manager: &mut EM, - input: &S::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + F1: FnOnce(&mut S, &mut EM, &I, &OT, &ExitKind) -> Result, + F2: FnOnce(&mut S, &mut EM, &I, &OT, &ExitKind) -> Result, { - let a = first.is_interesting(state, manager, input, observers, exit_kind)?; - let b = second.is_interesting(state, manager, input, observers, exit_kind)?; - Ok(a || b) + Ok(first(state, manager, input, observers, exit_kind)? + | second(state, manager, input, observers, exit_kind)?) } #[cfg(feature = "track_hit_feedbacks")] - fn last_result(first: &A, second: &B) -> Result { - Ok(first.last_result()? || second.last_result()?) + fn last_result(first: Result, second: Result) -> Result { + first.and_then(|first| second.map(|second| first | second)) } /// Note: Eager OR's hit feedbacks will behave like Fast OR /// because the second feedback will not have contributed to the result. /// Set the second feedback as the first (A, B) vs (B, A) /// to "prioritize" the result in case of Eager OR. #[cfg(feature = "track_hit_feedbacks")] - fn append_hit_feedbacks( - first: &A, - second: &B, + fn append_hit_feedbacks( + first_result: Result, + if_first: F1, + second_result: Result, + if_second: F2, list: &mut Vec>, - ) -> Result<(), Error> { - if first.last_result()? { - first.append_hit_feedbacks(list)?; - } else if second.last_result()? { - second.append_hit_feedbacks(list)?; - } - Ok(()) - } - - #[cfg(feature = "introspection")] - fn is_pair_interesting_introspection( - first: &mut A, - second: &mut B, - state: &mut S, - manager: &mut EM, - input: &S::Input, - observers: &OT, - exit_kind: &ExitKind, - ) -> Result + ) -> Result<(), Error> where - EM: EventFirer, - OT: ObserversTuple, + F1: FnOnce(&mut Vec>) -> Result<(), Error>, + F2: FnOnce(&mut Vec>) -> Result<(), Error>, { - // Execute this feedback - let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; - - let b = second.is_interesting_introspection(state, manager, input, observers, exit_kind)?; - Ok(a || b) + LogicFastOr::append_hit_feedbacks(first_result, if_first, second_result, if_second, list) } } -impl FeedbackLogic for LogicFastOr -where - A: Feedback, - B: Feedback, - S: State, -{ +impl FeedbackLogic for LogicFastOr { fn name() -> &'static str { "Fast OR" } - fn is_pair_interesting( - first: &mut A, - second: &mut B, + fn is_pair_interesting( + first: F1, + second: F2, state: &mut S, manager: &mut EM, - input: &S::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + F1: FnOnce(&mut S, &mut EM, &I, &OT, &ExitKind) -> Result, + F2: FnOnce(&mut S, &mut EM, &I, &OT, &ExitKind) -> Result, { - let a = first.is_interesting(state, manager, input, observers, exit_kind)?; + let a = first(state, manager, input, observers, exit_kind)?; if a { return Ok(true); } - second.is_interesting(state, manager, input, observers, exit_kind) + second(state, manager, input, observers, exit_kind) } #[cfg(feature = "track_hit_feedbacks")] - fn last_result(first: &A, second: &B) -> Result { - if first.last_result()? { - return Ok(true); - } - - // The second must have run if the first wasn't interesting - second.last_result() + fn last_result(first: Result, second: Result) -> Result { + first.and_then(|first| Ok(first || second?)) } + /// Note: Eager OR's hit feedbacks will behave like Fast OR + /// because the second feedback will not have contributed to the result. + /// Set the second feedback as the first (A, B) vs (B, A) + /// to "prioritize" the result in case of Eager OR. #[cfg(feature = "track_hit_feedbacks")] - fn append_hit_feedbacks( - first: &A, - second: &B, + fn append_hit_feedbacks( + first_result: Result, + if_first: F1, + second_result: Result, + if_second: F2, list: &mut Vec>, - ) -> Result<(), Error> { - if first.last_result()? { - first.append_hit_feedbacks(list)?; - } else if second.last_result()? { - second.append_hit_feedbacks(list)?; - } - Ok(()) - } - - #[cfg(feature = "introspection")] - fn is_pair_interesting_introspection( - first: &mut A, - second: &mut B, - state: &mut S, - manager: &mut EM, - input: &S::Input, - observers: &OT, - exit_kind: &ExitKind, - ) -> Result + ) -> Result<(), Error> where - EM: EventFirer, - OT: ObserversTuple, + F1: FnOnce(&mut Vec>) -> Result<(), Error>, + F2: FnOnce(&mut Vec>) -> Result<(), Error>, { - // Execute this feedback - let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; - - if a { - return Ok(true); + if first_result? { + if_first(list) + } else if second_result? { + if_second(list) + } else { + Ok(()) } - - second.is_interesting_introspection(state, manager, input, observers, exit_kind) } } -impl FeedbackLogic for LogicEagerAnd -where - A: Feedback, - B: Feedback, - S: State, -{ +impl FeedbackLogic for LogicEagerAnd { fn name() -> &'static str { "Eager AND" } - fn is_pair_interesting( - first: &mut A, - second: &mut B, + fn is_pair_interesting( + first: F1, + second: F2, state: &mut S, manager: &mut EM, - input: &S::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + F1: FnOnce(&mut S, &mut EM, &I, &OT, &ExitKind) -> Result, + F2: FnOnce(&mut S, &mut EM, &I, &OT, &ExitKind) -> Result, { - let a = first.is_interesting(state, manager, input, observers, exit_kind)?; - let b = second.is_interesting(state, manager, input, observers, exit_kind)?; - Ok(a && b) + Ok(first(state, manager, input, observers, exit_kind)? + & second(state, manager, input, observers, exit_kind)?) } #[cfg(feature = "track_hit_feedbacks")] - fn last_result(first: &A, second: &B) -> Result { - Ok(first.last_result()? && second.last_result()?) + fn last_result(first: Result, second: Result) -> Result { + Ok(first? & second?) } + #[cfg(feature = "track_hit_feedbacks")] - fn append_hit_feedbacks( - first: &A, - second: &B, + fn append_hit_feedbacks( + first_result: Result, + if_first: F1, + second_result: Result, + if_second: F2, list: &mut Vec>, - ) -> Result<(), Error> { - if first.last_result()? && second.last_result()? { - first.append_hit_feedbacks(list)?; - second.append_hit_feedbacks(list)?; + ) -> Result<(), Error> + where + F1: FnOnce(&mut Vec>) -> Result<(), Error>, + F2: FnOnce(&mut Vec>) -> Result<(), Error>, + { + if first_result? & second_result? { + if_first(list)?; + if_second(list)?; } Ok(()) } - - #[cfg(feature = "introspection")] - fn is_pair_interesting_introspection( - first: &mut A, - second: &mut B, - state: &mut S, - manager: &mut EM, - input: &S::Input, - observers: &OT, - exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { - // Execute this feedback - let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; - - let b = second.is_interesting_introspection(state, manager, input, observers, exit_kind)?; - Ok(a && b) - } } -impl FeedbackLogic for LogicFastAnd -where - A: Feedback, - B: Feedback, - S: State, -{ +impl FeedbackLogic for LogicFastAnd { fn name() -> &'static str { "Fast AND" } - fn is_pair_interesting( - first: &mut A, - second: &mut B, + fn is_pair_interesting( + first: F1, + second: F2, state: &mut S, manager: &mut EM, - input: &S::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + F1: FnOnce(&mut S, &mut EM, &I, &OT, &ExitKind) -> Result, + F2: FnOnce(&mut S, &mut EM, &I, &OT, &ExitKind) -> Result, { - let a = first.is_interesting(state, manager, input, observers, exit_kind)?; - if !a { - return Ok(false); - } - - second.is_interesting(state, manager, input, observers, exit_kind) + Ok(first(state, manager, input, observers, exit_kind)? + && second(state, manager, input, observers, exit_kind)?) } #[cfg(feature = "track_hit_feedbacks")] - fn last_result(first: &A, second: &B) -> Result { - if !first.last_result()? { - return Ok(false); - } - - // The second must have run if the first wasn't interesting - second.last_result() + fn last_result(first: Result, second: Result) -> Result { + Ok(first? && second?) } #[cfg(feature = "track_hit_feedbacks")] - fn append_hit_feedbacks( - first: &A, - second: &B, + fn append_hit_feedbacks( + first_result: Result, + if_first: F1, + second_result: Result, + if_second: F2, list: &mut Vec>, - ) -> Result<(), Error> { - if first.last_result()? { - first.append_hit_feedbacks(list)?; - } else if second.last_result()? { - second.append_hit_feedbacks(list)?; + ) -> Result<(), Error> + where + F1: FnOnce(&mut Vec>) -> Result<(), Error>, + F2: FnOnce(&mut Vec>) -> Result<(), Error>, + { + if first_result? && second_result? { + if_first(list)?; + if_second(list)?; } Ok(()) } - - #[cfg(feature = "introspection")] - fn is_pair_interesting_introspection( - first: &mut A, - second: &mut B, - state: &mut S, - manager: &mut EM, - input: &S::Input, - observers: &OT, - exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { - // Execute this feedback - let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; - - if !a { - return Ok(false); - } - - second.is_interesting_introspection(state, manager, input, observers, exit_kind) - } } /// Combine two feedbacks with an eager AND operation, /// will call all feedbacks functions even if not necessary to conclude the result -pub type EagerAndFeedback = CombinedFeedback; +pub type EagerAndFeedback = CombinedFeedback; /// Combine two feedbacks with an fast AND operation, /// might skip calling feedbacks functions if not necessary to conclude the result -pub type FastAndFeedback = CombinedFeedback; +pub type FastAndFeedback = CombinedFeedback; /// Combine two feedbacks with an eager OR operation, /// will call all feedbacks functions even if not necessary to conclude the result -pub type EagerOrFeedback = CombinedFeedback; +pub type EagerOrFeedback = CombinedFeedback; /// Combine two feedbacks with an fast OR operation - fast. /// /// This might skip calling feedbacks functions if not necessary to conclude the result. /// This means any feedback that is not first might be skipped, use caution when using with /// `TimeFeedback` -pub type FastOrFeedback = CombinedFeedback; +pub type FastOrFeedback = CombinedFeedback; /// Compose feedbacks with an `NOT` operation -#[derive(Clone)] -pub struct NotFeedback -where - A: Feedback, - S: State, -{ +#[derive(Clone, Debug)] +pub struct NotFeedback { /// The feedback to invert - pub first: A, + pub inner: A, /// The name name: Cow<'static, str>, - phantom: PhantomData, } -impl Debug for NotFeedback +impl StateInitializer for NotFeedback where - A: Feedback + Debug, - S: State, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("NotFeedback") - .field("name", &self.name) - .field("first", &self.first) - .finish() - } -} - -impl Feedback for NotFeedback -where - A: Feedback, - S: State, + A: StateInitializer, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { - self.first.init_state(state) + self.inner.init_state(state) } +} +impl Feedback for NotFeedback +where + A: Feedback, +{ #[allow(clippy::wrong_self_convention)] - fn is_interesting( + fn is_interesting( &mut self, state: &mut S, manager: &mut EM, - input: &S::Input, + input: &I, observers: &OT, exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { Ok(!self - .first + .inner .is_interesting(state, manager, input, observers, exit_kind)?) } - #[inline] - fn append_metadata( - &mut self, - state: &mut S, - manager: &mut EM, - observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { - self.first - .append_metadata(state, manager, observers, testcase) - } - - #[inline] - fn discard_metadata(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { - self.first.discard_metadata(state, input) - } - #[cfg(feature = "track_hit_feedbacks")] fn last_result(&self) -> Result { - Ok(!self.first.last_result()?) + Ok(!self.inner.last_result()?) + } + + #[inline] + fn append_metadata( + &mut self, + state: &mut S, + manager: &mut EM, + observers: &OT, + testcase: &mut Testcase, + ) -> Result<(), Error> { + self.inner + .append_metadata(state, manager, observers, testcase) + } + + #[inline] + fn discard_metadata(&mut self, state: &mut S, input: &I) -> Result<(), Error> { + self.inner.discard_metadata(state, input) } } -impl Named for NotFeedback -where - A: Feedback, - S: State, -{ +impl Named for NotFeedback { #[inline] fn name(&self) -> &Cow<'static, str> { &self.name } } -impl FeedbackFactory, T> for NotFeedback +impl FeedbackFactory, T> for NotFeedback where - A: Feedback + FeedbackFactory, - S: State, + A: Named + FeedbackFactory, { - fn create_feedback(&self, ctx: &T) -> NotFeedback { - NotFeedback::new(self.first.create_feedback(ctx)) + fn create_feedback(&self, ctx: &T) -> NotFeedback { + NotFeedback::new(self.inner.create_feedback(ctx)) } } -impl NotFeedback +impl NotFeedback where - A: Feedback, - S: State, + A: Named, { /// Creates a new [`NotFeedback`]. - pub fn new(first: A) -> Self { - let name = Cow::from(format!("Not({})", first.name())); - Self { - first, - name, - phantom: PhantomData, - } + pub fn new(inner: A) -> Self { + let name = Cow::from(format!("Not({})", inner.name())); + Self { inner, name } } } @@ -905,242 +757,149 @@ macro_rules! feedback_not { }; } +impl StateInitializer for () {} + /// Hack to use () as empty Feedback -impl Feedback for () -where - S: State, -{ - #[allow(clippy::wrong_self_convention)] - fn is_interesting( - &mut self, - _state: &mut S, - _manager: &mut EM, - _input: &S::Input, - _observers: &OT, - _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { - Ok(false) - } +impl Feedback for () { #[cfg(feature = "track_hit_feedbacks")] fn last_result(&self) -> Result { Ok(false) } } +/// Logic for measuring whether a given [`ExitKind`] is interesting as a [`Feedback`]. Use with +/// [`ExitKindFeedback`]. +pub trait ExitKindLogic { + /// The name of this kind of logic + const NAME: Cow<'static, str>; + + /// Check whether the provided [`ExitKind`] is actually interesting + fn check_exit_kind(kind: &ExitKind) -> Result; +} + +/// Logic which finds all [`ExitKind::Crash`] exits interesting +#[derive(Debug, Copy, Clone)] +pub struct CrashLogic; + +impl ExitKindLogic for CrashLogic { + const NAME: Cow<'static, str> = Cow::Borrowed("CrashFeedback"); + + fn check_exit_kind(kind: &ExitKind) -> Result { + Ok(matches!(kind, ExitKind::Crash)) + } +} + +/// Logic which finds all [`ExitKind::Timeout`] exits interesting +#[derive(Debug, Copy, Clone)] +pub struct TimeoutLogic; + +impl ExitKindLogic for TimeoutLogic { + const NAME: Cow<'static, str> = Cow::Borrowed("TimeoutFeedback"); + + fn check_exit_kind(kind: &ExitKind) -> Result { + Ok(matches!(kind, ExitKind::Timeout)) + } +} + +/// Logic which finds all [`ExitKind::Diff`] exits interesting +#[derive(Debug, Copy, Clone)] +pub struct GenericDiffLogic; + +impl ExitKindLogic for GenericDiffLogic { + const NAME: Cow<'static, str> = Cow::Borrowed("DiffExitKindFeedback"); + + fn check_exit_kind(kind: &ExitKind) -> Result { + Ok(matches!(kind, ExitKind::Diff { .. })) + } +} + +/// A generic exit type checking feedback. Use [`CrashFeedback`], [`TimeoutFeedback`], or +/// [`DiffExitKindFeedback`] directly instead. +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ExitKindFeedback { + #[cfg(feature = "track_hit_feedbacks")] + // The previous run's result of `Self::is_interesting` + last_result: Option, + name: Cow<'static, str>, + phantom: PhantomData L>, +} + +impl StateInitializer for ExitKindFeedback where L: ExitKindLogic {} + +impl Feedback for ExitKindFeedback +where + L: ExitKindLogic, +{ + #[allow(clippy::wrong_self_convention)] + fn is_interesting( + &mut self, + _state: &mut S, + _manager: &mut EM, + _input: &I, + _observers: &OT, + exit_kind: &ExitKind, + ) -> Result { + let res = L::check_exit_kind(exit_kind)?; + #[cfg(feature = "track_hit_feedbacks")] + { + self.last_result = Some(res); + } + Ok(res) + } + + #[cfg(feature = "track_hit_feedbacks")] + fn last_result(&self) -> Result { + self.last_result.ok_or(premature_last_result_err()) + } +} + +impl Named for ExitKindFeedback { + #[inline] + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +impl ExitKindFeedback +where + L: ExitKindLogic, +{ + /// Creates a new [`ExitKindFeedback`] + #[must_use] + pub fn new() -> Self { + Self { + #[cfg(feature = "track_hit_feedbacks")] + last_result: None, + name: L::NAME, + phantom: PhantomData, + } + } +} + +impl Default for ExitKindFeedback +where + L: ExitKindLogic, +{ + fn default() -> Self { + Self::new() + } +} + +impl FeedbackFactory, T> for ExitKindFeedback +where + L: ExitKindLogic, +{ + fn create_feedback(&self, _ctx: &T) -> ExitKindFeedback { + Self::new() + } +} + /// A [`CrashFeedback`] reports as interesting if the target crashed. -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct CrashFeedback { - #[cfg(feature = "track_hit_feedbacks")] - // The previous run's result of `Self::is_interesting` - last_result: Option, -} - -impl Feedback for CrashFeedback -where - S: State, -{ - #[allow(clippy::wrong_self_convention)] - fn is_interesting( - &mut self, - _state: &mut S, - _manager: &mut EM, - _input: &S::Input, - _observers: &OT, - exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { - let res = matches!(exit_kind, ExitKind::Crash); - #[cfg(feature = "track_hit_feedbacks")] - { - self.last_result = Some(res); - } - Ok(res) - } - - #[cfg(feature = "track_hit_feedbacks")] - fn last_result(&self) -> Result { - self.last_result.ok_or(premature_last_result_err()) - } -} - -impl Named for CrashFeedback { - #[inline] - fn name(&self) -> &Cow<'static, str> { - static NAME: Cow<'static, str> = Cow::Borrowed("CrashFeedback"); - &NAME - } -} - -impl CrashFeedback { - /// Creates a new [`CrashFeedback`] - #[must_use] - pub fn new() -> Self { - Self { - #[cfg(feature = "track_hit_feedbacks")] - last_result: None, - } - } -} - -impl Default for CrashFeedback { - fn default() -> Self { - Self::new() - } -} - -impl FeedbackFactory for CrashFeedback { - fn create_feedback(&self, _ctx: &T) -> CrashFeedback { - CrashFeedback::new() - } -} - +pub type CrashFeedback = ExitKindFeedback; /// A [`TimeoutFeedback`] reduces the timeout value of a run. -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct TimeoutFeedback { - #[cfg(feature = "track_hit_feedbacks")] - // The previous run's result of `Self::is_interesting` - last_result: Option, -} - -impl Feedback for TimeoutFeedback -where - S: State, -{ - #[allow(clippy::wrong_self_convention)] - fn is_interesting( - &mut self, - _state: &mut S, - _manager: &mut EM, - _input: &S::Input, - _observers: &OT, - exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { - let res = matches!(exit_kind, ExitKind::Timeout); - #[cfg(feature = "track_hit_feedbacks")] - { - self.last_result = Some(res); - } - Ok(res) - } - - #[cfg(feature = "track_hit_feedbacks")] - fn last_result(&self) -> Result { - self.last_result.ok_or(premature_last_result_err()) - } -} - -impl Named for TimeoutFeedback { - #[inline] - fn name(&self) -> &Cow<'static, str> { - static NAME: Cow<'static, str> = Cow::Borrowed("TimeoutFeedback"); - &NAME - } -} - -impl TimeoutFeedback { - /// Returns a new [`TimeoutFeedback`]. - #[must_use] - pub fn new() -> Self { - Self { - #[cfg(feature = "track_hit_feedbacks")] - last_result: None, - } - } -} - -impl Default for TimeoutFeedback { - fn default() -> Self { - Self::new() - } -} - -/// A feedback factory for timeout feedbacks -impl FeedbackFactory for TimeoutFeedback { - fn create_feedback(&self, _ctx: &T) -> TimeoutFeedback { - TimeoutFeedback::new() - } -} - -/// A [`DiffExitKindFeedback`] checks if there is a difference in the [`crate::executors::ExitKind`]s in a [`crate::executors::DiffExecutor`]. -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct DiffExitKindFeedback { - #[cfg(feature = "track_hit_feedbacks")] - // The previous run's result of `Self::is_interesting` - last_result: Option, -} - -impl Feedback for DiffExitKindFeedback -where - S: State, -{ - #[allow(clippy::wrong_self_convention)] - fn is_interesting( - &mut self, - _state: &mut S, - _manager: &mut EM, - _input: &S::Input, - _observers: &OT, - exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { - let res = matches!(exit_kind, ExitKind::Diff { .. }); - #[cfg(feature = "track_hit_feedbacks")] - { - self.last_result = Some(res); - } - Ok(res) - } - #[cfg(feature = "track_hit_feedbacks")] - fn last_result(&self) -> Result { - self.last_result.ok_or(premature_last_result_err()) - } -} - -impl Named for DiffExitKindFeedback { - #[inline] - fn name(&self) -> &Cow<'static, str> { - static NAME: Cow<'static, str> = Cow::Borrowed("DiffExitKindFeedback"); - &NAME - } -} - -impl DiffExitKindFeedback { - /// Returns a new [`DiffExitKindFeedback`]. - #[must_use] - pub fn new() -> Self { - Self { - #[cfg(feature = "track_hit_feedbacks")] - last_result: None, - } - } -} - -impl Default for DiffExitKindFeedback { - fn default() -> Self { - Self::new() - } -} - -/// A feedback factory for diff exit kind feedbacks -impl FeedbackFactory for DiffExitKindFeedback { - fn create_feedback(&self, _ctx: &T) -> DiffExitKindFeedback { - DiffExitKindFeedback::new() - } -} +pub type TimeoutFeedback = ExitKindFeedback; +/// A [`DiffExitKindFeedback`] checks if there is a difference in the [`ExitKind`]s in a [`crate::executors::DiffExecutor`]. +pub type DiffExitKindFeedback = ExitKindFeedback; /// A [`Feedback`] to track execution time. /// @@ -1151,56 +910,30 @@ impl FeedbackFactory for DiffExitKindFeedback { pub struct TimeFeedback { observer_handle: Handle, } +impl StateInitializer for TimeFeedback {} -impl Feedback for TimeFeedback +impl Feedback for TimeFeedback where - S: State, + OT: MatchName, { - #[allow(clippy::wrong_self_convention)] - fn is_interesting( - &mut self, - _state: &mut S, - _manager: &mut EM, - _input: &S::Input, - _observers: &OT, - _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { - // TODO Replace with match_name_type when stable + #[cfg(feature = "track_hit_feedbacks")] + fn last_result(&self) -> Result { Ok(false) } /// Append to the testcase the generated metadata in case of a new corpus item #[inline] - fn append_metadata( + fn append_metadata( &mut self, _state: &mut S, _manager: &mut EM, observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { + testcase: &mut Testcase, + ) -> Result<(), Error> { let observer = observers.get(&self.observer_handle).unwrap(); *testcase.exec_time_mut() = *observer.last_runtime(); Ok(()) } - - /// Discard the stored metadata in case that the testcase is not added to the corpus - #[inline] - fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { - Ok(()) - } - - #[cfg(feature = "track_hit_feedbacks")] - fn last_result(&self) -> Result { - Ok(false) - } } impl Named for TimeFeedback { @@ -1226,28 +959,23 @@ impl TimeFeedback { pub enum ConstFeedback { /// Always returns `true` True, - /// Alsways returns `false` + /// Always returns `false` False, } -impl Feedback for ConstFeedback -where - S: State, -{ +impl StateInitializer for ConstFeedback {} + +impl Feedback for ConstFeedback { #[inline] #[allow(clippy::wrong_self_convention)] - fn is_interesting( + fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &S::Input, + _input: &I, _observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { Ok((*self).into()) } diff --git a/libafl/src/feedbacks/nautilus.rs b/libafl/src/feedbacks/nautilus.rs index 467f42d3a1..88d062cad5 100644 --- a/libafl/src/feedbacks/nautilus.rs +++ b/libafl/src/feedbacks/nautilus.rs @@ -1,6 +1,6 @@ //! Nautilus grammar mutator, see use alloc::{borrow::Cow, string::String}; -use core::{fmt::Debug, marker::PhantomData}; +use core::fmt::Debug; use std::fs::create_dir_all; use libafl_bolts::Named; @@ -9,13 +9,11 @@ use serde::{Deserialize, Serialize}; use crate::{ common::nautilus::grammartec::{chunkstore::ChunkStore, context::Context}, corpus::{Corpus, Testcase}, - events::EventFirer, executors::ExitKind, - feedbacks::Feedback, + feedbacks::{Feedback, StateInitializer}, generators::NautilusContext, inputs::NautilusInput, - observers::ObserversTuple, - state::{HasCorpus, State}, + state::HasCorpus, Error, HasMetadata, }; @@ -51,66 +49,52 @@ impl NautilusChunksMetadata { } /// A nautilus feedback for grammar fuzzing -pub struct NautilusFeedback<'a, S> { +#[derive(Debug)] +pub struct NautilusFeedback<'a> { ctx: &'a Context, - phantom: PhantomData, } -impl Debug for NautilusFeedback<'_, S> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "NautilusFeedback {{}}") - } -} - -impl<'a, S> NautilusFeedback<'a, S> { +impl<'a> NautilusFeedback<'a> { /// Create a new [`NautilusFeedback`] #[must_use] pub fn new(context: &'a NautilusContext) -> Self { - Self { - ctx: &context.ctx, - phantom: PhantomData, - } + Self { ctx: &context.ctx } } } -impl<'a, S> Named for NautilusFeedback<'a, S> { +impl<'a> Named for NautilusFeedback<'a> { fn name(&self) -> &Cow<'static, str> { static NAME: Cow<'static, str> = Cow::Borrowed("NautilusFeedback"); &NAME } } -impl<'a, S> Feedback for NautilusFeedback<'a, S> +impl<'a, S> StateInitializer for NautilusFeedback<'a> {} + +impl<'a, EM, OT, S> Feedback for NautilusFeedback<'a> where - S: HasMetadata + HasCorpus + State, + S: HasMetadata + HasCorpus, S::Corpus: Corpus, { #[allow(clippy::wrong_self_convention)] - fn is_interesting( + fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, _input: &NautilusInput, _observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { Ok(false) } - fn append_metadata( + fn append_metadata( &mut self, state: &mut S, _manager: &mut EM, _observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - { + testcase: &mut Testcase, + ) -> Result<(), Error> { state.corpus().load_input_into(testcase)?; let input = testcase.input().as_ref().unwrap().clone(); let meta = state diff --git a/libafl/src/feedbacks/new_hash_feedback.rs b/libafl/src/feedbacks/new_hash_feedback.rs index 6f74a9cb3a..641ce685c7 100644 --- a/libafl/src/feedbacks/new_hash_feedback.rs +++ b/libafl/src/feedbacks/new_hash_feedback.rs @@ -1,11 +1,11 @@ //! The ``NewHashFeedback`` uses the backtrace hash and a hashset to only keep novel cases use alloc::{borrow::Cow, string::ToString}; -use std::{fmt::Debug, marker::PhantomData}; +use std::fmt::Debug; use hashbrown::HashSet; use libafl_bolts::{ - tuples::{Handle, Handled, MatchNameRef}, + tuples::{Handle, Handled, MatchName, MatchNameRef}, Named, }; use serde::{Deserialize, Serialize}; @@ -13,12 +13,9 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "track_hit_feedbacks")] use crate::feedbacks::premature_last_result_err; use crate::{ - events::EventFirer, executors::ExitKind, - feedbacks::{Feedback, HasObserverHandle}, - inputs::UsesInput, - observers::{ObserverWithHashField, ObserversTuple}, - state::State, + feedbacks::{Feedback, HasObserverHandle, StateInitializer}, + observers::ObserverWithHashField, Error, HasNamedMetadata, }; @@ -38,7 +35,7 @@ pub trait HashSetState { #[allow(clippy::unsafe_derive_deserialize)] pub struct NewHashFeedbackMetadata { /// Contains information about untouched entries - pub hash_set: HashSet, + hash_set: HashSet, } #[rustfmt::skip] @@ -64,6 +61,17 @@ impl NewHashFeedbackMetadata { self.hash_set.clear(); Ok(()) } + + /// Gets the associated [`HashSet`] being used to track hashes + #[must_use] + pub fn hash_set(&self) -> &HashSet { + &self.hash_set + } + + /// Gets the associated [`HashSet`] being used to track hashes, mutably + pub fn hash_set_mut(&mut self) -> &mut HashSet { + &mut self.hash_set + } } impl HashSetState for NewHashFeedbackMetadata { @@ -82,7 +90,7 @@ impl HashSetState for NewHashFeedbackMetadata { /// A [`NewHashFeedback`] maintains a hashset of already seen stacktraces and considers interesting unseen ones #[derive(Serialize, Deserialize, Clone, Debug)] -pub struct NewHashFeedback { +pub struct NewHashFeedback { name: Cow<'static, str>, o_ref: Handle, /// Initial capacity of hash set @@ -90,13 +98,11 @@ pub struct NewHashFeedback { #[cfg(feature = "track_hit_feedbacks")] // The previous run's result of `Self::is_interesting` last_result: Option, - phantom: PhantomData, } -impl Feedback for NewHashFeedback +impl StateInitializer for NewHashFeedback where - O: ObserverWithHashField + Named, - S: State + HasNamedMetadata, + S: HasNamedMetadata, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { state.add_named_metadata( @@ -105,20 +111,23 @@ where ); Ok(()) } +} +impl Feedback for NewHashFeedback +where + O: ObserverWithHashField, + OT: MatchName, + S: HasNamedMetadata, +{ #[allow(clippy::wrong_self_convention)] - fn is_interesting( + fn is_interesting( &mut self, state: &mut S, _manager: &mut EM, - _input: &::Input, + _input: &I, observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { let observer = observers .get(&self.o_ref) .expect("A NewHashFeedback needs a BacktraceObserver"); @@ -147,14 +156,14 @@ where } } -impl Named for NewHashFeedback { +impl Named for NewHashFeedback { #[inline] fn name(&self) -> &Cow<'static, str> { &self.name } } -impl HasObserverHandle for NewHashFeedback { +impl HasObserverHandle for NewHashFeedback { type Observer = O; #[inline] @@ -169,9 +178,9 @@ impl HasObserverHandle for NewHashFeedback { /// runs of the target, producing many different feedbacks. const DEFAULT_CAPACITY: usize = 4096; -impl NewHashFeedback +impl NewHashFeedback where - O: ObserverWithHashField + Named, + O: Named, { /// Returns a new [`NewHashFeedback`]. #[must_use] @@ -189,7 +198,6 @@ where capacity, #[cfg(feature = "track_hit_feedbacks")] last_result: None, - phantom: PhantomData, } } } diff --git a/libafl/src/feedbacks/stdio.rs b/libafl/src/feedbacks/stdio.rs index fb94c44a2d..0cc92fa139 100644 --- a/libafl/src/feedbacks/stdio.rs +++ b/libafl/src/feedbacks/stdio.rs @@ -4,18 +4,15 @@ use alloc::{borrow::Cow, string::String}; use libafl_bolts::{ impl_serdeany, - tuples::{Handle, Handled, MatchNameRef}, + tuples::{Handle, Handled, MatchName, MatchNameRef}, Named, }; use serde::{Deserialize, Serialize}; use crate::{ corpus::Testcase, - events::EventFirer, - executors::ExitKind, - feedbacks::Feedback, - observers::{ObserversTuple, StdErrObserver, StdOutObserver}, - state::State, + feedbacks::{Feedback, StateInitializer}, + observers::{StdErrObserver, StdOutObserver}, Error, HasMetadata, }; @@ -35,40 +32,26 @@ pub struct StdOutToMetadataFeedback { o_ref: Handle, } -impl Feedback for StdOutToMetadataFeedback +impl StateInitializer for StdOutToMetadataFeedback {} + +impl Feedback for StdOutToMetadataFeedback where - S: State, + OT: MatchName, { - #[allow(clippy::wrong_self_convention)] - #[inline] - fn is_interesting( - &mut self, - _state: &mut S, - _manager: &mut EM, - _input: &S::Input, - _observers: &OT, - _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + #[cfg(feature = "track_hit_feedbacks")] + fn last_result(&self) -> Result { Ok(false) } /// Append to the testcase the generated metadata in case of a new corpus item. #[inline] - fn append_metadata( + fn append_metadata( &mut self, _state: &mut S, _manager: &mut EM, observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { + testcase: &mut Testcase, + ) -> Result<(), Error> { let observer = observers .get(&self.o_ref) .ok_or(Error::illegal_state("StdOutObserver is missing"))?; @@ -84,17 +67,6 @@ where Ok(()) } - - /// Discard the stored metadata in case that the testcase is not added to the corpus. - #[inline] - fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { - Ok(()) - } - - #[cfg(feature = "track_hit_feedbacks")] - fn last_result(&self) -> Result { - Ok(false) - } } impl Named for StdOutToMetadataFeedback { @@ -130,40 +102,26 @@ pub struct StdErrToMetadataFeedback { o_ref: Handle, } -impl Feedback for StdErrToMetadataFeedback +impl StateInitializer for StdErrToMetadataFeedback {} + +impl Feedback for StdErrToMetadataFeedback where - S: State, + OT: MatchName, { - #[allow(clippy::wrong_self_convention)] - #[inline] - fn is_interesting( - &mut self, - _state: &mut S, - _manager: &mut EM, - _input: &S::Input, - _observers: &OT, - _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + #[cfg(feature = "track_hit_feedbacks")] + fn last_result(&self) -> Result { Ok(false) } /// Append to the testcase the generated metadata in case of a new corpus item. #[inline] - fn append_metadata( + fn append_metadata( &mut self, _state: &mut S, _manager: &mut EM, observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - EM: EventFirer, - { + testcase: &mut Testcase, + ) -> Result<(), Error> { let observer = observers .get(&self.o_ref) .ok_or(Error::illegal_state("StdErrObserver is missing"))?; @@ -179,16 +137,6 @@ where Ok(()) } - - /// Discard the stored metadata in case that the testcase is not added to the corpus. - #[inline] - fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { - Ok(()) - } - #[cfg(feature = "track_hit_feedbacks")] - fn last_result(&self) -> Result { - Ok(false) - } } impl Named for StdErrToMetadataFeedback { diff --git a/libafl/src/feedbacks/transferred.rs b/libafl/src/feedbacks/transferred.rs index 95a63c03b2..84f848922f 100644 --- a/libafl/src/feedbacks/transferred.rs +++ b/libafl/src/feedbacks/transferred.rs @@ -9,17 +9,18 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "track_hit_feedbacks")] use crate::feedbacks::premature_last_result_err; use crate::{ - events::EventFirer, executors::ExitKind, feedbacks::Feedback, observers::ObserversTuple, - state::State, HasMetadata, + executors::ExitKind, + feedbacks::{Feedback, StateInitializer}, + HasMetadata, }; + /// Constant name of the [`TransferringMetadata`]. pub const TRANSFERRED_FEEDBACK_NAME: Cow<'static, str> = Cow::Borrowed("transferred_feedback_internal"); /// Metadata which denotes whether we are currently transferring an input. /// -/// Implementors of -/// multi-node communication systems (like [`crate::events::LlmpEventManager`]) should wrap any +/// Implementors of multi-node communication systems (like [`crate::events::LlmpEventManager`]) should wrap any /// [`crate::EvaluatorObservers::evaluate_input_with_observers`] or /// [`crate::ExecutionProcessor::process_execution`] calls with setting this metadata to true/false /// before and after. @@ -52,27 +53,28 @@ impl Named for TransferredFeedback { } } -impl Feedback for TransferredFeedback +impl StateInitializer for TransferredFeedback where - S: HasMetadata + State, + S: HasMetadata, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { state.add_metadata(TransferringMetadata { transferring: true }); Ok(()) } +} - fn is_interesting( +impl Feedback for TransferredFeedback +where + S: HasMetadata, +{ + fn is_interesting( &mut self, state: &mut S, _manager: &mut EM, - _input: &S::Input, + _input: &I, _observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { let res = state.metadata::()?.transferring; #[cfg(feature = "track_hit_feedbacks")] { @@ -80,6 +82,7 @@ where } Ok(res) } + #[cfg(feature = "track_hit_feedbacks")] fn last_result(&self) -> Result { self.last_result.ok_or(premature_last_result_err()) diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index a31d083b85..35312dea69 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -47,7 +47,7 @@ where /// Holds an feedback pub trait HasFeedback: UsesState { /// The feedback type - type Feedback: Feedback; + type Feedback; /// The feedback fn feedback(&self) -> &Self::Feedback; @@ -59,7 +59,7 @@ pub trait HasFeedback: UsesState { /// Holds an objective feedback pub trait HasObjective: UsesState { /// The type of the [`Feedback`] used to find objectives for this fuzzer - type Objective: Feedback; + type Objective; /// The objective feedback fn objective(&self) -> &Self::Objective; @@ -69,9 +69,9 @@ pub trait HasObjective: UsesState { } /// Evaluates if an input is interesting using the feedback -pub trait ExecutionProcessor: UsesState { +pub trait ExecutionProcessor: UsesState { /// Check the outcome of the execution, find if it is worth for corpus or objectives - fn check_results( + fn check_results( &mut self, state: &mut Self::State, manager: &mut EM, @@ -85,7 +85,7 @@ pub trait ExecutionProcessor: UsesState { /// Process `ExecuteInputResult`. Add to corpus, solution or ignore #[allow(clippy::too_many_arguments)] - fn process_execution( + fn process_execution( &mut self, state: &mut Self::State, manager: &mut EM, @@ -98,7 +98,7 @@ pub trait ExecutionProcessor: UsesState { OT: ObserversTuple<::Input, Self::State>; /// serialize and send event via manager - fn serialize_and_dispatch( + fn serialize_and_dispatch( &mut self, state: &mut Self::State, manager: &mut EM, @@ -112,7 +112,7 @@ pub trait ExecutionProcessor: UsesState { OT: ObserversTuple<::Input, Self::State> + Serialize; /// send event via manager - fn dispatch_event( + fn dispatch_event( &mut self, state: &mut Self::State, manager: &mut EM, @@ -125,7 +125,7 @@ pub trait ExecutionProcessor: UsesState { EM: EventFirer; /// Evaluate if a set of observation channels has an interesting state - fn evaluate_execution( + fn evaluate_execution( &mut self, state: &mut Self::State, manager: &mut EM, @@ -140,11 +140,11 @@ pub trait ExecutionProcessor: UsesState { } /// Evaluates an input modifying the state of the fuzzer -pub trait EvaluatorObservers: UsesState + Sized { +pub trait EvaluatorObservers: UsesState + Sized { /// Runs the input and triggers observers and feedback, /// returns if is interesting an (option) the index of the new /// [`crate::corpus::Testcase`] in the [`crate::corpus::Corpus`] - fn evaluate_input_with_observers( + fn evaluate_input_with_observers( &mut self, state: &mut Self::State, executor: &mut E, @@ -336,8 +336,6 @@ where impl HasFeedback for StdFuzzer where S: State, - F: Feedback, - OF: Feedback, { type Feedback = F; @@ -353,8 +351,6 @@ where impl HasObjective for StdFuzzer where S: State, - F: Feedback, - OF: Feedback, { type Objective = OF; @@ -367,16 +363,16 @@ where } } -impl ExecutionProcessor for StdFuzzer +impl ExecutionProcessor for StdFuzzer where CS: Scheduler, - F: Feedback, - OF: Feedback, + F: Feedback, + OF: Feedback, S: HasCorpus + HasSolutions + HasExecutions + HasCorpus + HasCurrentCorpusId + State, S::Corpus: Corpus, //delete me S::Solutions: Corpus, //delete me { - fn check_results( + fn check_results( &mut self, state: &mut S, manager: &mut EM, @@ -420,7 +416,7 @@ where Ok(res) } - fn evaluate_execution( + fn evaluate_execution( &mut self, state: &mut Self::State, manager: &mut EM, @@ -441,7 +437,7 @@ where Ok((exec_res, corpus_id)) } - fn serialize_and_dispatch( + fn serialize_and_dispatch( &mut self, state: &mut Self::State, manager: &mut EM, @@ -475,7 +471,7 @@ where Ok(()) } - fn dispatch_event( + fn dispatch_event( &mut self, state: &mut Self::State, manager: &mut EM, @@ -527,7 +523,7 @@ where } /// Evaluate if a set of observation channels has an interesting state - fn process_execution( + fn process_execution( &mut self, state: &mut Self::State, manager: &mut EM, @@ -585,19 +581,19 @@ where } } -impl EvaluatorObservers for StdFuzzer +impl EvaluatorObservers for StdFuzzer where CS: Scheduler, OT: ObserversTuple + Serialize + DeserializeOwned, - F: Feedback, - OF: Feedback, + F: Feedback, + OF: Feedback, S: HasCorpus + HasSolutions + HasExecutions + State, S::Corpus: Corpus, //delete me S::Solutions: Corpus, //delete me { /// Process one input, adding to the respective corpora if needed and firing the right events #[inline] - fn evaluate_input_with_observers( + fn evaluate_input_with_observers( &mut self, state: &mut S, executor: &mut E, @@ -624,8 +620,8 @@ where E: HasObservers + Executor, E::Observers: ObserversTuple + Serialize + DeserializeOwned, EM: EventFirer, - F: Feedback, - OF: Feedback, + F: Feedback, + OF: Feedback, S: HasCorpus + HasSolutions + HasExecutions + HasLastFoundTime + State, S::Corpus: Corpus, //delete me S::Solutions: Corpus, //delete me @@ -760,8 +756,6 @@ where CS: Scheduler, E: UsesState, EM: ProgressReporter + EventProcessor, - F: Feedback, - OF: Feedback, S: HasExecutions + HasMetadata + HasCorpus @@ -837,8 +831,6 @@ where impl StdFuzzer where CS: Scheduler, - F: Feedback<::State>, - OF: Feedback<::State>, S: UsesInput + HasExecutions + HasCorpus + State, { /// Create a new `StdFuzzer` with standard behavior. @@ -901,8 +893,6 @@ where impl ExecutesInput for StdFuzzer where CS: Scheduler, - F: Feedback<::State>, - OF: Feedback<::State>, E: Executor + HasObservers, E::Observers: ObserversTuple<::Input, ::State>, EM: UsesState, diff --git a/libafl/src/observers/map/mod.rs b/libafl/src/observers/map/mod.rs index 7c8b86d876..513f18062e 100644 --- a/libafl/src/observers/map/mod.rs +++ b/libafl/src/observers/map/mod.rs @@ -48,7 +48,7 @@ pub use owned_map::*; /// ``` /// # use libafl::corpus::InMemoryCorpus; /// # use libafl::feedbacks::{Feedback, MapFeedbackMetadata}; -/// use libafl::feedbacks::MaxMapFeedback; +/// use libafl::feedbacks::{MaxMapFeedback, StateInitializer}; /// # use libafl::inputs::BytesInput; /// use libafl::observers::{StdMapObserver, CanTrack}; /// use libafl::schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}; diff --git a/libafl/src/observers/stdio.rs b/libafl/src/observers/stdio.rs index 8370cbcd83..950e38d5c7 100644 --- a/libafl/src/observers/stdio.rs +++ b/libafl/src/observers/stdio.rs @@ -27,7 +27,7 @@ use crate::{observers::Observer, Error}; /// corpus::{Corpus, InMemoryCorpus, Testcase}, /// events::{EventFirer, NopEventManager}, /// executors::{CommandExecutor, ExitKind}, -/// feedbacks::Feedback, +/// feedbacks::{Feedback, StateInitializer}, /// inputs::{BytesInput, UsesInput}, /// mutators::{MutationResult, NopMutator}, /// observers::{ObserversTuple, StdErrObserver, StdOutObserver}, @@ -53,21 +53,22 @@ use crate::{observers::Observer, Error}; /// stderr_observer: Handle, /// } /// -/// impl Feedback for ExportStdXObserver +/// impl StateInitializer for ExportStdXObserver {} +/// +/// +/// impl Feedback for ExportStdXObserver /// where -/// S: State +/// S: State, +/// OT: MatchNameRef /// { -/// fn is_interesting( +/// fn is_interesting( /// &mut self, /// _state: &mut S, /// _manager: &mut EM, -/// _input: &::Input, +/// _input: &I, /// observers: &OT, /// _exit_kind: &ExitKind, /// ) -> Result -/// where -/// EM: EventFirer, -/// OT: ObserversTuple, /// { /// unsafe { /// STDOUT = observers.get(&self.stdout_observer).unwrap().stdout.clone(); diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index 37a0b4f690..3909528332 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -447,8 +447,8 @@ where OT: ObserversTuple, PS: PushStage, Z: ExecutesInput - + ExecutionProcessor - + EvaluatorObservers + + ExecutionProcessor + + EvaluatorObservers + HasScheduler, { fn perform( diff --git a/libafl/src/stages/push/mod.rs b/libafl/src/stages/push/mod.rs index ab9aca5d71..a8304962e1 100644 --- a/libafl/src/stages/push/mod.rs +++ b/libafl/src/stages/push/mod.rs @@ -40,7 +40,7 @@ where EM: EventFirer + EventRestarter + HasEventManagerId, OT: ObserversTuple, Z::State: HasRand + HasCorpus, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// The [`crate::state::State`] pub state: Z::State, @@ -59,7 +59,7 @@ where EM: EventFirer + EventRestarter + HasEventManagerId, OT: ObserversTuple, Z::State: HasRand + HasCorpus, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// Create a new `PushStageSharedState` that can be used by all [`PushStage`]s #[must_use] @@ -82,7 +82,7 @@ where EM: EventFirer + EventRestarter + HasEventManagerId, OT: ObserversTuple, Z::State: HasRand + HasCorpus, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// If this stage has already been initalized. /// This gets reset to `false` after one iteration of the stage is done. @@ -110,7 +110,7 @@ where EM: EventFirer + EventRestarter + HasEventManagerId, OT: ObserversTuple, Z::State: HasRand + HasCorpus, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// Create a new [`PushStageHelper`] #[must_use] @@ -177,7 +177,7 @@ where Z::State: HasRand + HasExecutions + HasMetadata + HasCorpus + HasLastReportTime, EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, OT: ObserversTuple, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// Gets the [`PushStageHelper`] fn push_stage_helper(&self) -> &PushStageHelper; diff --git a/libafl/src/stages/push/mutational.rs b/libafl/src/stages/push/mutational.rs index b36b18a413..be414321bf 100644 --- a/libafl/src/stages/push/mutational.rs +++ b/libafl/src/stages/push/mutational.rs @@ -48,7 +48,7 @@ where M: Mutator, OT: ObserversTuple + Serialize, Z::State: HasRand + HasCorpus + Clone + Debug, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { current_corpus_id: Option, testcases_to_do: usize, @@ -66,7 +66,7 @@ where M: Mutator, OT: ObserversTuple + Serialize, Z::State: HasCorpus + HasRand + Clone + Debug, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// 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 @@ -87,7 +87,7 @@ where M: Mutator, OT: ObserversTuple + Serialize, Z::State: HasCorpus + HasRand + HasExecutions + HasLastReportTime + HasMetadata + Clone + Debug, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, <::State as HasCorpus>::Corpus: Corpus, //delete me { #[inline] @@ -196,7 +196,7 @@ where M: Mutator, OT: ObserversTuple + Serialize, Z::State: HasCorpus + HasRand + HasExecutions + HasMetadata + HasLastReportTime + Clone + Debug, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, <::State as HasCorpus>::Corpus: Corpus, //delete me { type Item = Result<::Input, Error>; @@ -213,7 +213,7 @@ where M: Mutator, OT: ObserversTuple + Serialize, Z::State: HasCorpus + HasRand + Clone + Debug, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// Creates a new default mutational stage #[must_use] diff --git a/libafl/src/stages/sync.rs b/libafl/src/stages/sync.rs index b3f2641538..b9878c679c 100644 --- a/libafl/src/stages/sync.rs +++ b/libafl/src/stages/sync.rs @@ -253,7 +253,8 @@ where SP: ShMemProvider, E: HasObservers + Executor, for<'a> E::Observers: Deserialize<'a>, - Z: EvaluatorObservers + ExecutionProcessor, + Z: EvaluatorObservers + + ExecutionProcessor, IC: InputConverter, ICB: InputConverter, DI: Input, diff --git a/libafl/src/stages/tmin.rs b/libafl/src/stages/tmin.rs index a650f15445..0396de92b4 100644 --- a/libafl/src/stages/tmin.rs +++ b/libafl/src/stages/tmin.rs @@ -8,7 +8,7 @@ use core::{borrow::BorrowMut, fmt::Debug, hash::Hash, marker::PhantomData}; use ahash::RandomState; use libafl_bolts::{ - tuples::{Handle, Handled, MatchNameRef}, + tuples::{Handle, Handled, MatchName, MatchNameRef}, HasLen, Named, }; use serde::Serialize; @@ -19,7 +19,7 @@ use crate::{ corpus::{Corpus, HasCurrentCorpusId, Testcase}, events::EventFirer, executors::{ExitKind, HasObservers}, - feedbacks::{Feedback, FeedbackFactory, HasObserverHandle}, + feedbacks::{Feedback, FeedbackFactory, HasObserverHandle, StateInitializer}, inputs::UsesInput, mark_feature_time, mutators::{MutationResult, Mutator}, @@ -47,7 +47,7 @@ where E: UsesState + HasObservers, E::Observers: ObserversTuple + Serialize, EM: UsesState + EventFirer, - F: Feedback, + F: Feedback, Self::State: HasMaxSize + HasCorpus + HasSolutions + HasExecutions + HasCurrentTestcase, Self::Input: MutatedTransform + Clone + Hash + HasLen, IP: Clone + MutatedTransformPost, @@ -56,7 +56,8 @@ where + HasScheduler + HasFeedback + ExecutesInput - + ExecutionProcessor, + + ExecutionProcessor, + Z::Feedback: Feedback, Z::Scheduler: RemovableScheduler, <::State as HasCorpus>::Corpus: Corpus, { @@ -239,16 +240,17 @@ where impl Stage for StdTMinMutationalStage where - Z: HasScheduler + ExecutionProcessor + ExecutesInput + HasFeedback, + Z: HasScheduler + ExecutionProcessor + ExecutesInput + HasFeedback, Z::Scheduler: RemovableScheduler, E: HasObservers + UsesState, E::Observers: ObserversTuple + Serialize, EM: EventFirer, FF: FeedbackFactory, - F: Feedback, + 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 @@ -302,13 +304,13 @@ pub static TMIN_STAGE_NAME: &str = "tmin"; impl TMinMutationalStage for StdTMinMutationalStage where - Z: HasScheduler + ExecutionProcessor + ExecutesInput + HasFeedback, + Z: HasScheduler + ExecutionProcessor + ExecutesInput + HasFeedback, Z::Scheduler: RemovableScheduler, E: HasObservers + UsesState, E::Observers: ObserversTuple + Serialize, EM: EventFirer, FF: FeedbackFactory, - F: Feedback, + F: Feedback, Self::Input: MutatedTransform + Clone + HasLen + Hash, Z::State: HasMetadata + HasExecutions @@ -317,6 +319,7 @@ where + HasMaxSize + HasNamedMetadata + HasCurrentTestcase, + Z::Feedback: Feedback, M: Mutator, IP: MutatedTransformPost + Clone, <::State as HasCorpus>::Corpus: Corpus, // delete me @@ -391,24 +394,23 @@ impl HasObserverHandle for MapEqualityFeedback { } } -impl Feedback for MapEqualityFeedback +impl StateInitializer for MapEqualityFeedback {} + +impl Feedback for MapEqualityFeedback where M: MapObserver, C: AsRef, S: State, + OT: MatchName, { - fn is_interesting( + fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &S::Input, + _input: &I, observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { let obs = observers .get(self.observer_handle()) .expect("Should have been provided valid observer name."); diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index ed9922cd60..8eb4c87dc0 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -33,7 +33,7 @@ use crate::monitors::ScalabilityMonitor; use crate::{ corpus::{Corpus, CorpusId, HasCurrentCorpusId, HasTestcase, InMemoryCorpus, Testcase}, events::{Event, EventFirer, LogSeverity}, - feedbacks::Feedback, + feedbacks::StateInitializer, fuzzer::{Evaluator, ExecuteInputResult}, generators::Generator, inputs::{Input, NopInput, UsesInput}, @@ -1161,8 +1161,8 @@ where objective: &mut O, ) -> Result where - F: Feedback, - O: Feedback, + F: StateInitializer, + O: StateInitializer, C: Serialize + DeserializeOwned, SC: Serialize + DeserializeOwned, { diff --git a/libafl_frida/src/asan/errors.rs b/libafl_frida/src/asan/errors.rs index 147997f632..745830ca0f 100644 --- a/libafl_frida/src/asan/errors.rs +++ b/libafl_frida/src/asan/errors.rs @@ -14,11 +14,10 @@ use frida_gum::interceptor::Interceptor; use frida_gum::ModuleDetails; use libafl::{ corpus::Testcase, - events::EventFirer, executors::ExitKind, - feedbacks::Feedback, + feedbacks::{Feedback, StateInitializer}, inputs::HasTargetBytes, - observers::{Observer, ObserversTuple}, + observers::Observer, state::State, Error, HasMetadata, }; @@ -647,24 +646,23 @@ pub struct AsanErrorsFeedback { phantom: PhantomData, } -impl Feedback for AsanErrorsFeedback +impl StateInitializer for AsanErrorsFeedback {} + +impl Feedback for AsanErrorsFeedback where S: State + Debug, S::Input: HasTargetBytes, + OT: MatchNameRef, { #[allow(clippy::wrong_self_convention)] - fn is_interesting( + fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, _input: &S::Input, observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { let observer = observers .get(&self.observer_handle) .expect("An AsanErrorsFeedback needs an AsanErrorsObserver"); @@ -677,16 +675,13 @@ where } } - fn append_metadata( + fn append_metadata( &mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - { + ) -> Result<(), Error> { if let Some(errors) = &self.errors { testcase.add_metadata(errors.clone()); } diff --git a/libafl_libfuzzer/runtime/src/feedbacks.rs b/libafl_libfuzzer/runtime/src/feedbacks.rs index 4380d787fe..e67b5f8a72 100644 --- a/libafl_libfuzzer/runtime/src/feedbacks.rs +++ b/libafl_libfuzzer/runtime/src/feedbacks.rs @@ -5,15 +5,13 @@ use std::borrow::Cow; use libafl::{ alloc, corpus::Testcase, - events::EventFirer, executors::ExitKind, - feedbacks::{Feedback, MinMapFeedback}, + feedbacks::{Feedback, MinMapFeedback, StateInitializer}, inputs::{BytesInput, Input}, - observers::ObserversTuple, state::State, Error, HasMetadata, }; -use libafl_bolts::{impl_serdeany, Named}; +use libafl_bolts::{impl_serdeany, tuples::MatchNameRef, Named}; use libafl_targets::OomFeedback; use serde::{Deserialize, Serialize}; @@ -43,22 +41,20 @@ impl Named for LibfuzzerKeepFeedback { } } -impl Feedback for LibfuzzerKeepFeedback +impl StateInitializer for LibfuzzerKeepFeedback {} + +impl Feedback for LibfuzzerKeepFeedback where S: State, { - fn is_interesting( + fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, _input: &S::Input, _observers: &OT, _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { Ok(*self.keep.borrow()) } @@ -119,22 +115,21 @@ impl LibfuzzerCrashCauseFeedback { } } -impl Feedback for LibfuzzerCrashCauseFeedback +impl StateInitializer for LibfuzzerCrashCauseFeedback {} + +impl Feedback for LibfuzzerCrashCauseFeedback where S: State, + OT: MatchNameRef, { - fn is_interesting( + fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &S::Input, + _input: &BytesInput, _observers: &OT, exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { + ) -> Result { self.exit_kind = *exit_kind; Ok(false) } @@ -143,16 +138,13 @@ where Ok(false) } - fn append_metadata( + fn append_metadata( &mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, - testcase: &mut Testcase, - ) -> Result<(), Error> - where - OT: ObserversTuple, - { + testcase: &mut Testcase, + ) -> Result<(), Error> { match self.exit_kind { ExitKind::Crash | ExitKind::Oom if OomFeedback::oomed() => { self.set_filename("oom", testcase); @@ -183,4 +175,4 @@ where } } -pub type ShrinkMapFeedback = MinMapFeedback, usize>; +pub type ShrinkMapFeedback = MinMapFeedback>; diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index 0d05c03ed9..ca983db24b 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -89,7 +89,7 @@ pub unsafe fn inproc_qemu_timeout_handler( E: HasObservers + HasInProcessHooks + Executor, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasExecutions + HasSolutions + HasCorpus, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me @@ -139,9 +139,11 @@ where where ED: EmulatorDriver, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, S: Unpin + State + HasExecutions + HasCorpus + HasSolutions, - Z: HasObjective + HasScheduler + ExecutionProcessor, + Z: HasObjective + + HasScheduler + + ExecutionProcessor, S::Solutions: Corpus, //delete me ::Input: Clone, //delete me { @@ -328,6 +330,7 @@ where S: State + HasSolutions, SP: ShMemProvider, Z: HasObjective, + Z::Objective: Feedback, { pub fn new( emulator: Emulator, @@ -383,7 +386,7 @@ where OT: ObserversTuple + Debug, ET: EmulatorModuleTuple, SP: ShMemProvider, - OF: Feedback, + OF: Feedback, Z: HasObjective, { fn run_target( diff --git a/libafl_targets/src/libfuzzer/observers/oom.rs b/libafl_targets/src/libfuzzer/observers/oom.rs index 2925aaf09e..35d59d511d 100644 --- a/libafl_targets/src/libfuzzer/observers/oom.rs +++ b/libafl_targets/src/libfuzzer/observers/oom.rs @@ -2,7 +2,12 @@ use alloc::borrow::Cow; use core::{ffi::c_void, fmt::Debug}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use libafl::{executors::ExitKind, feedbacks::Feedback, observers::Observer, state::State, Error}; +use libafl::{ + executors::ExitKind, + feedbacks::{Feedback, StateInitializer}, + observers::Observer, + Error, +}; use libafl_bolts::Named; use libc::SIGABRT; use serde::{Deserialize, Serialize}; @@ -138,15 +143,14 @@ impl Named for OomFeedback { } } -impl Feedback for OomFeedback -where - S: State, -{ - fn is_interesting( +impl StateInitializer for OomFeedback {} + +impl Feedback for OomFeedback { + fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &S::Input, + _input: &I, _observers: &OT, _exit_kind: &ExitKind, ) -> Result { diff --git a/libafl_targets/src/windows_asan.rs b/libafl_targets/src/windows_asan.rs index 35149d3281..3ba804dd3e 100644 --- a/libafl_targets/src/windows_asan.rs +++ b/libafl_targets/src/windows_asan.rs @@ -34,7 +34,7 @@ pub unsafe fn setup_asan_callback(_executor: &E, _event_mgr: &EM, where E: Executor + HasObservers, EM: EventFirer + EventRestarter, - OF: Feedback, + OF: Feedback, E::State: HasSolutions + HasCorpus + HasExecutions, E::Observers: ObserversTuple<::Input, E::State>, Z: HasObjective,