From 0fdfa1d7a10bf00109a77d586fb0462655cd7bfb Mon Sep 17 00:00:00 2001 From: lazymio Date: Thu, 3 Apr 2025 23:24:38 +0800 Subject: [PATCH] Add back executions to Testcase (#3115) * Add back executions to Testcase * Small clippy --------- Co-authored-by: Dongjia "toka" Zhang --- libafl/src/corpus/inmemory_ondisk.rs | 1 + libafl/src/corpus/ondisk.rs | 2 ++ libafl/src/corpus/testcase.rs | 24 ++++++++++++++++++++++++ libafl/src/executors/inprocess/mod.rs | 1 + libafl/src/fuzzer/mod.rs | 5 +++++ libafl/src/stages/tmin.rs | 3 +++ 6 files changed, 36 insertions(+) diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index d4442a01f9..70b48bfc08 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -407,6 +407,7 @@ impl InMemoryOnDiskCorpus { let ondisk_meta = OnDiskMetadata { metadata: testcase.metadata_map(), exec_time: testcase.exec_time(), + executions: testcase.executions(), }; let mut tmpfile = File::create(&tmpfile_path)?; diff --git a/libafl/src/corpus/ondisk.rs b/libafl/src/corpus/ondisk.rs index 4a69769108..72179a6531 100644 --- a/libafl/src/corpus/ondisk.rs +++ b/libafl/src/corpus/ondisk.rs @@ -43,6 +43,8 @@ pub struct OnDiskMetadata<'a> { pub metadata: &'a SerdeAnyMap, /// The exec time for this [`Testcase`] pub exec_time: &'a Option, + /// The executions of this [`Testcase`] + pub executions: &'a u64, } /// A corpus able to store [`Testcase`]s to disk, and load them from disk, when they are being used. diff --git a/libafl/src/corpus/testcase.rs b/libafl/src/corpus/testcase.rs index 1c9c4bfccf..3e2763e661 100644 --- a/libafl/src/corpus/testcase.rs +++ b/libafl/src/corpus/testcase.rs @@ -50,6 +50,8 @@ pub struct Testcase { cached_len: Option, /// Number of fuzzing iterations of this particular input updated in `perform_mutational` scheduled_count: usize, + /// Number of executions done at discovery time + executions: u64, /// Parent [`CorpusId`], if known parent_id: Option, /// If the testcase is "disabled" @@ -145,6 +147,24 @@ impl Testcase { &mut self.metadata_path } + /// Get the executions + #[inline] + pub fn executions(&self) -> &u64 { + &self.executions + } + + /// Get the executions (mutable) + #[inline] + pub fn executions_mut(&mut self) -> &mut u64 { + &mut self.executions + } + + /// Set the executions + #[inline] + pub fn set_executions(&mut self, executions: u64) { + self.executions = executions; + } + /// Get the execution time of the testcase #[inline] pub fn exec_time(&self) -> &Option { @@ -228,6 +248,7 @@ impl Testcase { metadata_path: None, exec_time: None, cached_len: None, + executions: 0, scheduled_count: 0, parent_id: None, disabled: false, @@ -252,6 +273,7 @@ impl Testcase { metadata_path: None, exec_time: None, cached_len: None, + executions: 0, scheduled_count: 0, parent_id: Some(parent_id), disabled: false, @@ -278,6 +300,7 @@ impl Testcase { metadata_path: None, exec_time: None, cached_len: None, + executions: 0, scheduled_count: 0, parent_id: None, disabled: false, @@ -333,6 +356,7 @@ impl Default for Testcase { #[cfg(feature = "std")] metadata_path: None, disabled: false, + executions: 0, objectives_found: 0, #[cfg(feature = "track_hit_feedbacks")] hit_feedbacks: Vec::new(), diff --git a/libafl/src/executors/inprocess/mod.rs b/libafl/src/executors/inprocess/mod.rs index b04b7b739c..d3942a9cb4 100644 --- a/libafl/src/executors/inprocess/mod.rs +++ b/libafl/src/executors/inprocess/mod.rs @@ -345,6 +345,7 @@ pub fn run_observers_and_save_state( if is_solution { let mut new_testcase = Testcase::from(input.clone()); + new_testcase.set_executions(*state.executions()); new_testcase.add_metadata(exitkind); new_testcase.set_parent_id_optional(*state.corpus().current()); diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index 821adfbf39..203cb7e500 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -360,6 +360,7 @@ where OT: ObserversTuple + Serialize, S: HasCorpus + MaybeHasClientPerfMonitor + + HasExecutions + HasCurrentTestcase + HasSolutions + HasLastFoundTime @@ -420,6 +421,7 @@ where let corpus = if exec_res.is_corpus() { // Add the input to the main corpus let mut testcase = Testcase::from(input.clone()); + testcase.set_executions(*state.executions()); #[cfg(feature = "track_hit_feedbacks")] self.feedback_mut() .append_hit_feedbacks(testcase.hit_feedbacks_mut())?; @@ -435,6 +437,7 @@ where if exec_res.is_solution() { // The input is a solution, add it to the respective corpus let mut testcase = Testcase::from(input.clone()); + testcase.set_executions(*state.executions()); testcase.add_metadata(*exit_kind); testcase.set_parent_id_optional(*state.corpus().current()); if let Ok(mut tc) = state.current_testcase_mut() { @@ -675,6 +678,7 @@ where let observers = executor.observers(); // Always consider this to be "interesting" let mut testcase = Testcase::from(input.clone()); + testcase.set_executions(*state.executions()); // Maybe a solution #[cfg(not(feature = "introspection"))] @@ -763,6 +767,7 @@ where fn add_disabled_input(&mut self, state: &mut S, input: I) -> Result { let mut testcase = Testcase::from(input.clone()); + testcase.set_executions(*state.executions()); testcase.set_disabled(true); // Add the disabled input to the main corpus let id = state.corpus_mut().add_disabled(testcase)?; diff --git a/libafl/src/stages/tmin.rs b/libafl/src/stages/tmin.rs index 2153da064d..60d3b9a79a 100644 --- a/libafl/src/stages/tmin.rs +++ b/libafl/src/stages/tmin.rs @@ -284,6 +284,9 @@ where .feedback_mut() .is_interesting(state, manager, &base, &*observers, &exit_kind)?; let mut testcase = Testcase::from(base); + testcase.set_executions(*state.executions()); + testcase.set_parent_id(base_corpus_id); + fuzzer .feedback_mut() .append_metadata(state, manager, &*observers, &mut testcase)?;