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
multipart_inputs = ["arrayvec", "rand_trait"]
## Share objectives across nodes
share_objectives = []
#! ## LibAFL-Bolts Features
## Provide the `#[derive(SerdeAny)]` macro.

View File

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

View File

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

View File

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

View File

@ -700,7 +700,6 @@ where
}
return Ok(Some((event, false)));
}
#[cfg(feature = "share_objectives")]
Event::Objective { .. } => {
log::info!("Received new Objective");
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(
state,
Event::Objective {
#[cfg(feature = "share_objectives")]
input: input.clone(),
input: fuzzer.share_objectives().then_some(input.clone()),
objective_size: state.solutions().count(),
time: libafl_bolts::current_time(),
},

View File

@ -70,6 +70,12 @@ pub trait HasObjective {
/// The objective feedback (mutable)
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
@ -292,6 +298,8 @@ pub struct StdFuzzer<CS, F, IF, OF> {
feedback: F,
objective: OF,
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>
@ -331,6 +339,14 @@ impl<CS, F, IF, OF> HasObjective for StdFuzzer<CS, F, IF, OF> {
fn objective_mut(&mut self) -> &mut OF {
&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>
@ -480,14 +496,11 @@ where
},
)?;
}
if exec_res.is_solution() {
manager.fire(
state,
Event::Objective {
#[cfg(feature = "share_objectives")]
input: input.clone(),
input: self.share_objectives.then_some(input.clone()),
objective_size: state.solutions().count(),
time: current_time(),
},
@ -677,9 +690,7 @@ where
manager.fire(
state,
Event::Objective {
#[cfg(feature = "share_objectives")]
input: input.clone(),
input: self.share_objectives.then_some(input.clone()),
objective_size: state.solutions().count(),
time: current_time(),
},
@ -802,10 +813,16 @@ where
)?;
res.1
}
#[cfg(feature = "share_objectives")]
Event::Objective { ref input, .. } => {
Event::Objective {
input: Some(ref unwrapped_input),
..
} => {
let res = self.evaluate_input_with_observers(
state, executor, manager, input, false,
state,
executor,
manager,
unwrapped_input,
false,
)?;
res.1
}
@ -966,6 +983,7 @@ impl<CS, F, IF, OF> StdFuzzer<CS, F, IF, OF> {
feedback,
objective,
input_filter,
share_objectives: false,
}
}
}

View File

@ -19,7 +19,7 @@ use crate::{
corpus::{Corpus, CorpusId, HasCurrentCorpusId},
events::{Event, EventConfig, EventFirer, llmp::LlmpEventConverter},
executors::{Executor, ExitKind, HasObservers},
fuzzer::{Evaluator, EvaluatorObservers, ExecutionProcessor},
fuzzer::{Evaluator, EvaluatorObservers, ExecutionProcessor, HasObjective},
inputs::{Input, InputConverter},
stages::{Restartable, RetryCountRestartHelper, Stage},
state::{
@ -248,7 +248,7 @@ where
+ MaybeHasClientPerfMonitor,
SHM: ShMem,
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]
fn perform(

View File

@ -218,7 +218,13 @@ impl DrCovModuleEntry {
pub fn to_module_line(&self) -> String {
format!(
"{: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()
)
}
}