convert share_objectives into a runtime option (#3033)

* add share_objectives field to StdFuzzer

* uhhh maybe add field to StdState instead

* trivial

* implement to handle_in_client()

* fmt

* revert changes to state

* no gating on receiving objectives

* add query method to hasobjectives

* make input field of Event::Objective optional

* fmt and clippy

* move setter to hasobjectives

* better way to handle incoming objective

* fmt

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
This commit is contained in:
Dhanvith Nayak 2025-03-07 18:48:48 +05:30 committed by GitHub
parent 76539fa247
commit 41f16890b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 44 additions and 28 deletions

View File

@ -142,9 +142,6 @@ unicode = ["libafl_bolts/alloc", "ahash/std", "serde/rc", "bitvec"]
## Enable multi-part input formats and mutators ## Enable multi-part input formats and mutators
multipart_inputs = ["arrayvec", "rand_trait"] multipart_inputs = ["arrayvec", "rand_trait"]
## Share objectives across nodes
share_objectives = []
#! ## LibAFL-Bolts Features #! ## LibAFL-Bolts Features
## Provide the `#[derive(SerdeAny)]` macro. ## Provide the `#[derive(SerdeAny)]` macro.

View File

@ -291,9 +291,10 @@ where
} }
Ok(()) Ok(())
} }
Event::Objective {
#[cfg(feature = "share_objectives")] input: Some(unwrapped_input),
Event::Objective { input, .. } => { ..
} => {
log::debug!("Received new Objective"); log::debug!("Received new Objective");
let Some(converter) = self.converter_back.as_mut() else { let Some(converter) = self.converter_back.as_mut() else {
@ -304,7 +305,7 @@ where
state, state,
executor, executor,
manager, manager,
&converter.convert(input)?, &converter.convert(unwrapped_input)?,
false, false,
)?; )?;

View File

@ -377,8 +377,6 @@ where
return Ok(Some((event, false))); return Ok(Some((event, false)));
} }
#[cfg(feature = "share_objectives")]
Event::Objective { .. } => { Event::Objective { .. } => {
#[cfg(feature = "std")] #[cfg(feature = "std")]
log::debug!("[{}] Received new Objective", std::process::id()); log::debug!("[{}] Received new Objective", std::process::id());

View File

@ -300,8 +300,7 @@ pub enum Event<I> {
/// A new objective was found /// A new objective was found
Objective { Objective {
/// Input of newly found Objective /// Input of newly found Objective
#[cfg(feature = "share_objectives")] input: Option<I>,
input: I,
/// Objective corpus size /// Objective corpus size
objective_size: usize, objective_size: usize,
/// The time when this event was created /// The time when this event was created

View File

@ -700,7 +700,6 @@ where
} }
return Ok(Some((event, false))); return Ok(Some((event, false)));
} }
#[cfg(feature = "share_objectives")]
Event::Objective { .. } => { Event::Objective { .. } => {
log::info!("Received new Objective"); log::info!("Received new Objective");
return Ok(Some((event, false))); return Ok(Some((event, false)));

View File

@ -430,9 +430,7 @@ pub fn run_observers_and_save_state<E, EM, F, I, OF, S, Z>(
.fire( .fire(
state, state,
Event::Objective { Event::Objective {
#[cfg(feature = "share_objectives")] input: fuzzer.share_objectives().then_some(input.clone()),
input: input.clone(),
objective_size: state.solutions().count(), objective_size: state.solutions().count(),
time: libafl_bolts::current_time(), time: libafl_bolts::current_time(),
}, },

View File

@ -70,6 +70,12 @@ pub trait HasObjective {
/// The objective feedback (mutable) /// The objective feedback (mutable)
fn objective_mut(&mut self) -> &mut Self::Objective; fn objective_mut(&mut self) -> &mut Self::Objective;
/// Whether to share objective testcases among fuzzing nodes
fn share_objectives(&self) -> bool;
/// Sets whether to share objectives among nodes
fn set_share_objectives(&mut self, share_objectives: bool);
} }
/// Evaluates if an input is interesting using the feedback /// Evaluates if an input is interesting using the feedback
@ -292,6 +298,8 @@ pub struct StdFuzzer<CS, F, IF, OF> {
feedback: F, feedback: F,
objective: OF, objective: OF,
input_filter: IF, input_filter: IF,
// Handles whether to share objective testcases among nodes
share_objectives: bool,
} }
impl<CS, F, I, IF, OF, S> HasScheduler<I, S> for StdFuzzer<CS, F, IF, OF> impl<CS, F, I, IF, OF, S> HasScheduler<I, S> for StdFuzzer<CS, F, IF, OF>
@ -331,6 +339,14 @@ impl<CS, F, IF, OF> HasObjective for StdFuzzer<CS, F, IF, OF> {
fn objective_mut(&mut self) -> &mut OF { fn objective_mut(&mut self) -> &mut OF {
&mut self.objective &mut self.objective
} }
fn set_share_objectives(&mut self, share_objectives: bool) {
self.share_objectives = share_objectives;
}
fn share_objectives(&self) -> bool {
self.share_objectives
}
} }
impl<CS, EM, F, I, IF, OF, OT, S> ExecutionProcessor<EM, I, OT, S> for StdFuzzer<CS, F, IF, OF> impl<CS, EM, F, I, IF, OF, OT, S> ExecutionProcessor<EM, I, OT, S> for StdFuzzer<CS, F, IF, OF>
@ -480,14 +496,11 @@ where
}, },
)?; )?;
} }
if exec_res.is_solution() { if exec_res.is_solution() {
manager.fire( manager.fire(
state, state,
Event::Objective { Event::Objective {
#[cfg(feature = "share_objectives")] input: self.share_objectives.then_some(input.clone()),
input: input.clone(),
objective_size: state.solutions().count(), objective_size: state.solutions().count(),
time: current_time(), time: current_time(),
}, },
@ -677,9 +690,7 @@ where
manager.fire( manager.fire(
state, state,
Event::Objective { Event::Objective {
#[cfg(feature = "share_objectives")] input: self.share_objectives.then_some(input.clone()),
input: input.clone(),
objective_size: state.solutions().count(), objective_size: state.solutions().count(),
time: current_time(), time: current_time(),
}, },
@ -802,10 +813,16 @@ where
)?; )?;
res.1 res.1
} }
#[cfg(feature = "share_objectives")] Event::Objective {
Event::Objective { ref input, .. } => { input: Some(ref unwrapped_input),
..
} => {
let res = self.evaluate_input_with_observers( let res = self.evaluate_input_with_observers(
state, executor, manager, input, false, state,
executor,
manager,
unwrapped_input,
false,
)?; )?;
res.1 res.1
} }
@ -966,6 +983,7 @@ impl<CS, F, IF, OF> StdFuzzer<CS, F, IF, OF> {
feedback, feedback,
objective, objective,
input_filter, input_filter,
share_objectives: false,
} }
} }
} }

View File

@ -19,7 +19,7 @@ use crate::{
corpus::{Corpus, CorpusId, HasCurrentCorpusId}, corpus::{Corpus, CorpusId, HasCurrentCorpusId},
events::{Event, EventConfig, EventFirer, llmp::LlmpEventConverter}, events::{Event, EventConfig, EventFirer, llmp::LlmpEventConverter},
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
fuzzer::{Evaluator, EvaluatorObservers, ExecutionProcessor}, fuzzer::{Evaluator, EvaluatorObservers, ExecutionProcessor, HasObjective},
inputs::{Input, InputConverter}, inputs::{Input, InputConverter},
stages::{Restartable, RetryCountRestartHelper, Stage}, stages::{Restartable, RetryCountRestartHelper, Stage},
state::{ state::{
@ -248,7 +248,7 @@ where
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
SHM: ShMem, SHM: ShMem,
SP: ShMemProvider<ShMem = SHM>, SP: ShMemProvider<ShMem = SHM>,
Z: EvaluatorObservers<E, EM, I, S> + ExecutionProcessor<EM, I, E::Observers, S>, Z: EvaluatorObservers<E, EM, I, S> + ExecutionProcessor<EM, I, E::Observers, S> + HasObjective,
{ {
#[inline] #[inline]
fn perform( fn perform(

View File

@ -218,7 +218,13 @@ impl DrCovModuleEntry {
pub fn to_module_line(&self) -> String { pub fn to_module_line(&self) -> String {
format!( format!(
"{:03}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, {}", "{:03}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, {}",
self.id, self.base, self.end, self.entry, self.checksum, self.timestamp, self.path.display() self.id,
self.base,
self.end,
self.entry,
self.checksum,
self.timestamp,
self.path.display()
) )
} }
} }