Fire events in append_metadata not in is_interesting (#1936)

* stuff

* ok

* Recalc filled slightly differently... (#1939)

* Recalc filled slightly differently...

* Make requested changes as per PR review

* unused

* fix

---------

Co-authored-by: Dan Blackwell <danblackwell95@yahoo.co.uk>
This commit is contained in:
Dongjia "toka" Zhang 2024-03-15 13:24:26 +01:00 committed by GitHub
parent b3ddab3bce
commit ee6385c25b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 106 additions and 97 deletions

View File

@ -62,9 +62,10 @@ where
} }
#[inline] #[inline]
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM,
_observers: &OT, _observers: &OT,
testcase: &mut Testcase<PacketData>, testcase: &mut Testcase<PacketData>,
) -> Result<(), Error> { ) -> Result<(), Error> {

View File

@ -455,7 +455,7 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
new_testcase.set_parent_id_optional(*state.corpus().current()); new_testcase.set_parent_id_optional(*state.corpus().current());
fuzzer fuzzer
.objective_mut() .objective_mut()
.append_metadata(state, observers, &mut new_testcase) .append_metadata(state, event_mgr, observers, &mut new_testcase)
.expect("Failed adding metadata"); .expect("Failed adding metadata");
state state
.solutions_mut() .solutions_mut()

View File

@ -67,14 +67,16 @@ where
Ok(false) Ok(false)
} }
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM,
observers: &OT, observers: &OT,
testcase: &mut Testcase<S::Input>, testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{ {
if let Some(metadata) = observers if let Some(metadata) = observers
.match_name::<ConcolicObserver>(&self.name) .match_name::<ConcolicObserver>(&self.name)

View File

@ -318,6 +318,8 @@ where
{ {
/// Contains information about untouched entries /// Contains information about untouched entries
pub history_map: Vec<T>, pub history_map: Vec<T>,
/// Tells us how many non-initial entries there are in `history_map`
pub num_covered_map_indexes: usize,
} }
libafl_bolts::impl_serdeany!( libafl_bolts::impl_serdeany!(
@ -327,21 +329,29 @@ libafl_bolts::impl_serdeany!(
impl<T> MapFeedbackMetadata<T> impl<T> MapFeedbackMetadata<T>
where where
T: Default + Copy + 'static + Serialize + DeserializeOwned, T: Default + Copy + 'static + Serialize + DeserializeOwned + PartialEq,
{ {
/// Create new `MapFeedbackMetadata` /// Create new `MapFeedbackMetadata`
#[must_use] #[must_use]
pub fn new(map_size: usize) -> Self { pub fn new(map_size: usize) -> Self {
Self { Self {
history_map: vec![T::default(); map_size], history_map: vec![T::default(); map_size],
num_covered_map_indexes: 0,
} }
} }
/// Create new `MapFeedbackMetadata` using a name and a map. /// Create new `MapFeedbackMetadata` using a name and a map.
/// The map can be shared. /// The map can be shared.
/// `initial_elem_value` is used to calculate `Self.num_covered_map_indexes`
#[must_use] #[must_use]
pub fn with_history_map(history_map: Vec<T>) -> Self { pub fn with_history_map(history_map: Vec<T>, initial_elem_value: T) -> Self {
Self { history_map } let num_covered_map_indexes = history_map
.iter()
.fold(0, |acc, x| acc + usize::from(*x != initial_elem_value));
Self {
history_map,
num_covered_map_indexes,
}
} }
/// Reset the map /// Reset the map
@ -350,6 +360,7 @@ where
for i in 0..cnt { for i in 0..cnt {
self.history_map[i] = T::default(); self.history_map[i] = T::default();
} }
self.num_covered_map_indexes = 0;
Ok(()) Ok(())
} }
@ -359,6 +370,9 @@ where
for i in 0..cnt { for i in 0..cnt {
self.history_map[i] = value; self.history_map[i] = value;
} }
// assume that resetting the map should indicate no coverage,
// regardless of value
self.num_covered_map_indexes = 0;
Ok(()) Ok(())
} }
} }
@ -366,8 +380,6 @@ where
/// The most common AFL-like feedback type /// The most common AFL-like feedback type
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MapFeedback<N, O, R, S, T> { pub struct MapFeedback<N, O, R, S, T> {
/// For tracking, always keep indexes and/or novelties, even if the map isn't considered `interesting`.
always_track: bool,
/// Indexes used in the last observation /// Indexes used in the last observation
indexes: bool, indexes: bool,
/// New indexes observed in the last observation /// New indexes observed in the last observation
@ -418,7 +430,7 @@ where
EM: EventFirer<State = S>, EM: EventFirer<State = S>,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
{ {
self.is_interesting_default(state, manager, input, observers, exit_kind) Ok(self.is_interesting_default(state, manager, input, observers, exit_kind))
} }
#[rustversion::not(nightly)] #[rustversion::not(nightly)]
@ -434,17 +446,19 @@ where
EM: EventFirer<State = S>, EM: EventFirer<State = S>,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
{ {
self.is_interesting_default(state, manager, input, observers, exit_kind) Ok(self.is_interesting_default(state, manager, input, observers, exit_kind))
} }
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM,
observers: &OT, observers: &OT,
testcase: &mut Testcase<S::Input>, testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{ {
if let Some(novelties) = self.novelties.as_mut().map(core::mem::take) { if let Some(novelties) = self.novelties.as_mut().map(core::mem::take) {
let meta = MapNoveltiesMetadata::new(novelties); let meta = MapNoveltiesMetadata::new(novelties);
@ -471,6 +485,9 @@ where
.enumerate() .enumerate()
.filter(|(_, value)| *value != initial) .filter(|(_, value)| *value != initial)
{ {
if history_map[i] == initial {
map_state.num_covered_map_indexes += 1;
}
history_map[i] = R::reduce(history_map[i], value); history_map[i] = R::reduce(history_map[i], value);
indices.push(i); indices.push(i);
} }
@ -483,9 +500,43 @@ where
.enumerate() .enumerate()
.filter(|(_, value)| *value != initial) .filter(|(_, value)| *value != initial)
{ {
if history_map[i] == initial {
map_state.num_covered_map_indexes += 1;
}
history_map[i] = R::reduce(history_map[i], value); history_map[i] = R::reduce(history_map[i], value);
} }
} }
debug_assert!(
history_map
.iter()
.fold(0, |acc, x| acc + usize::from(*x != initial))
== map_state.num_covered_map_indexes,
"history_map had {} filled, but map_state.num_covered_map_indexes was {}",
history_map
.iter()
.fold(0, |acc, x| acc + usize::from(*x != initial)),
map_state.num_covered_map_indexes,
);
// at this point you are executing this code, the testcase is always interesting
let covered = map_state.num_covered_map_indexes;
let len = history_map.len();
// opt: if not tracking optimisations, we technically don't show the *current* history
// map but the *last* history map; this is better than walking over and allocating
// unnecessarily
manager.fire(
state,
Event::UpdateUserStats {
name: self.stats_name.to_string(),
value: UserStats::new(
UserStatsValue::Ratio(covered as u64, len as u64),
AggregatorOps::Avg,
),
phantom: PhantomData,
},
)?;
Ok(()) Ok(())
} }
} }
@ -503,7 +554,7 @@ where
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, _manager: &mut EM,
_input: &S::Input, _input: &S::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
@ -604,32 +655,6 @@ where
} }
} }
let initial = observer.initial();
if interesting {
let len = history_map.len();
let filled = history_map.iter().filter(|&&i| i != initial).count();
// opt: if not tracking optimisations, we technically don't show the *current* history
// map but the *last* history map; this is better than walking over and allocating
// unnecessarily
manager.fire(
state,
Event::UpdateUserStats {
name: self.stats_name.to_string(),
value: UserStats::new(
UserStatsValue::Ratio(
self.novelties
.as_ref()
.map_or(filled, |novelties| filled + novelties.len())
as u64,
len as u64,
),
AggregatorOps::Avg,
),
phantom: PhantomData,
},
)?;
}
Ok(interesting) Ok(interesting)
} }
} }
@ -678,7 +703,6 @@ where
name: MAPFEEDBACK_PREFIX.to_string() + map_observer.name(), name: MAPFEEDBACK_PREFIX.to_string() + map_observer.name(),
observer_name: map_observer.name().to_string(), observer_name: map_observer.name().to_string(),
stats_name: create_stats_name(map_observer.name()), stats_name: create_stats_name(map_observer.name()),
always_track: false,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -692,7 +716,6 @@ where
name: MAPFEEDBACK_PREFIX.to_string() + map_observer.name(), name: MAPFEEDBACK_PREFIX.to_string() + map_observer.name(),
observer_name: map_observer.name().to_string(), observer_name: map_observer.name().to_string(),
stats_name: create_stats_name(map_observer.name()), stats_name: create_stats_name(map_observer.name()),
always_track: false,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -707,17 +730,9 @@ where
observer_name: observer_name.to_string(), observer_name: observer_name.to_string(),
stats_name: create_stats_name(name), stats_name: create_stats_name(name),
phantom: PhantomData, phantom: PhantomData,
always_track: false,
} }
} }
/// For tracking, enable `always_track` mode, that also adds `novelties` or `indexes`,
/// even if the map is not novel for this feedback.
/// This is useful in combination with `load_initial_inputs_forced`, or other feedbacks.
pub fn set_always_track(&mut self, always_track: bool) {
self.always_track = always_track;
}
/// Creating a new `MapFeedback` with a specific name. This is usefully whenever the same /// Creating a new `MapFeedback` with a specific name. This is usefully whenever the same
/// feedback is needed twice, but with a different history. Using `new()` always results in the /// feedback is needed twice, but with a different history. Using `new()` always results in the
/// same name and therefore also the same history. /// same name and therefore also the same history.
@ -729,7 +744,6 @@ where
name: name.to_string(), name: name.to_string(),
observer_name: map_observer.name().to_string(), observer_name: map_observer.name().to_string(),
stats_name: create_stats_name(name), stats_name: create_stats_name(name),
always_track: false,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -748,7 +762,6 @@ where
observer_name: observer_name.to_string(), observer_name: observer_name.to_string(),
stats_name: create_stats_name(name), stats_name: create_stats_name(name),
name: name.to_string(), name: name.to_string(),
always_track: false,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -759,11 +772,11 @@ where
fn is_interesting_default<EM, OT>( fn is_interesting_default<EM, OT>(
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, _manager: &mut EM,
_input: &S::Input, _input: &S::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> bool
where where
EM: EventFirer<State = S>, EM: EventFirer<State = S>,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
@ -816,32 +829,7 @@ where
} }
} }
if interesting || self.always_track { interesting
let len = history_map.len();
let filled = history_map.iter().filter(|&&i| i != initial).count();
// opt: if not tracking optimisations, we technically don't show the *current* history
// map but the *last* history map; this is better than walking over and allocating
// unnecessarily
manager.fire(
state,
Event::UpdateUserStats {
name: self.stats_name.to_string(),
value: UserStats::new(
UserStatsValue::Ratio(
self.novelties
.as_ref()
.map_or(filled, |novelties| filled + novelties.len())
as u64,
len as u64,
),
AggregatorOps::Avg,
),
phantom: PhantomData,
},
)?;
}
Ok(interesting)
} }
} }
@ -915,9 +903,10 @@ where
} }
} }
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM,
_observers: &OT, _observers: &OT,
testcase: &mut Testcase<S::Input>, testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> ) -> Result<(), Error>

View File

@ -109,14 +109,16 @@ where
/// Append to the testcase the generated metadata in case of a new corpus item /// Append to the testcase the generated metadata in case of a new corpus item
#[inline] #[inline]
#[allow(unused_variables)] #[allow(unused_variables)]
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM,
observers: &OT, observers: &OT,
testcase: &mut Testcase<S::Input>, testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{ {
Ok(()) Ok(())
} }
@ -245,17 +247,21 @@ where
} }
#[inline] #[inline]
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM,
observers: &OT, observers: &OT,
testcase: &mut Testcase<S::Input>, testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{ {
self.first.append_metadata(state, observers, testcase)?; self.first
self.second.append_metadata(state, observers, testcase) .append_metadata(state, manager, observers, testcase)?;
self.second
.append_metadata(state, manager, observers, testcase)
} }
#[inline] #[inline]
@ -659,16 +665,19 @@ where
} }
#[inline] #[inline]
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM,
observers: &OT, observers: &OT,
testcase: &mut Testcase<S::Input>, testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{ {
self.first.append_metadata(state, observers, testcase) self.first
.append_metadata(state, manager, observers, testcase)
} }
#[inline] #[inline]
@ -915,14 +924,16 @@ where
/// Append to the testcase the generated metadata in case of a new corpus item /// Append to the testcase the generated metadata in case of a new corpus item
#[inline] #[inline]
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM,
observers: &OT, observers: &OT,
testcase: &mut Testcase<S::Input>, testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{ {
let observer = observers.match_name::<TimeObserver>(self.name()).unwrap(); let observer = observers.match_name::<TimeObserver>(self.name()).unwrap();
*testcase.exec_time_mut() = *observer.last_runtime(); *testcase.exec_time_mut() = *observer.last_runtime();
@ -1212,9 +1223,10 @@ pub mod pybind {
})?) })?)
} }
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
state: &mut PythonStdState, state: &mut PythonStdState,
_manager: &mut EM,
observers: &OT, observers: &OT,
testcase: &mut Testcase<BytesInput>, testcase: &mut Testcase<BytesInput>,
) -> Result<(), Error> ) -> Result<(), Error>
@ -1655,17 +1667,19 @@ pub mod pybind {
}) })
} }
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
state: &mut PythonStdState, state: &mut PythonStdState,
manager: &mut EM,
observers: &OT, observers: &OT,
testcase: &mut Testcase<BytesInput>, testcase: &mut Testcase<BytesInput>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
OT: ObserversTuple<PythonStdState>, OT: ObserversTuple<PythonStdState>,
EM: EventFirer<State = PythonStdState>,
{ {
unwrap_me_mut!(self.wrapper, f, { unwrap_me_mut!(self.wrapper, f, {
f.append_metadata(state, observers, testcase) f.append_metadata(state, manager, observers, testcase)
}) })
} }

View File

@ -99,9 +99,10 @@ where
Ok(false) Ok(false)
} }
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
state: &mut S, state: &mut S,
_manager: &mut EM,
_observers: &OT, _observers: &OT,
testcase: &mut Testcase<S::Input>, testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> ) -> Result<(), Error>

View File

@ -381,7 +381,7 @@ where
// Add the input to the main corpus // Add the input to the main corpus
let mut testcase = Testcase::with_executions(input.clone(), *state.executions()); let mut testcase = Testcase::with_executions(input.clone(), *state.executions());
self.feedback_mut() self.feedback_mut()
.append_metadata(state, observers, &mut testcase)?; .append_metadata(state, manager, observers, &mut testcase)?;
let idx = state.corpus_mut().add(testcase)?; let idx = state.corpus_mut().add(testcase)?;
self.scheduler_mut().on_add(state, idx)?; self.scheduler_mut().on_add(state, idx)?;
@ -419,7 +419,7 @@ where
let mut testcase = Testcase::with_executions(input, *state.executions()); let mut testcase = Testcase::with_executions(input, *state.executions());
testcase.set_parent_id_optional(*state.corpus().current()); testcase.set_parent_id_optional(*state.corpus().current());
self.objective_mut() self.objective_mut()
.append_metadata(state, observers, &mut testcase)?; .append_metadata(state, manager, observers, &mut testcase)?;
state.solutions_mut().add(testcase)?; state.solutions_mut().add(testcase)?;
if send_events { if send_events {
@ -517,7 +517,7 @@ where
if is_solution { if is_solution {
self.objective_mut() self.objective_mut()
.append_metadata(state, observers, &mut testcase)?; .append_metadata(state, manager, observers, &mut testcase)?;
let idx = state.solutions_mut().add(testcase)?; let idx = state.solutions_mut().add(testcase)?;
manager.fire( manager.fire(
@ -546,7 +546,7 @@ where
// Add the input to the main corpus // Add the input to the main corpus
self.feedback_mut() self.feedback_mut()
.append_metadata(state, observers, &mut testcase)?; .append_metadata(state, manager, observers, &mut testcase)?;
let idx = state.corpus_mut().add(testcase)?; let idx = state.corpus_mut().add(testcase)?;
self.scheduler_mut().on_add(state, idx)?; self.scheduler_mut().on_add(state, idx)?;

View File

@ -166,7 +166,7 @@ where
let mut testcase = Testcase::with_executions(base, *state.executions()); let mut testcase = Testcase::with_executions(base, *state.executions());
fuzzer fuzzer
.feedback_mut() .feedback_mut()
.append_metadata(state, observers, &mut testcase)?; .append_metadata(state, manager, observers, &mut testcase)?;
let prev = state.corpus_mut().replace(base_corpus_idx, testcase)?; let prev = state.corpus_mut().replace(base_corpus_idx, testcase)?;
fuzzer fuzzer
.scheduler_mut() .scheduler_mut()

View File

@ -651,9 +651,10 @@ where
} }
} }
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM,
_observers: &OT, _observers: &OT,
testcase: &mut Testcase<S::Input>, testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> ) -> Result<(), Error>

View File

@ -131,9 +131,10 @@ where
Ok(false) Ok(false)
} }
fn append_metadata<OT>( fn append_metadata<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM,
_observers: &OT, _observers: &OT,
testcase: &mut Testcase<S::Input>, testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> ) -> Result<(), Error>