Introduce feedbacks hit tracking for testcases (#2248)
* introduce feedbacks hit tracking for testcases * make Testcase::hit_feedbacks into Cow<&str> instead of String rename get_hit_feedbacks to append_hit_feedbacks update documentation * simplify ConstFeedback * rename Feedback::last_result to prev_result * impl TODO prev_result for NewHashFeedback, ListFeedback, TransferredFeedback, NautilusFeedback * rename prev_result to last_result * add docs * introduce Objectives hit tracking * update docs * update Cargo.toml docs * update docs * track Feedbacks & Objectives hit in Fuzzer::add_input * fmt * clippy * fix type error in OomFeedback::last_result * impl last_result for AsanErrorsFeedback * add track_hit_feedbacks as a feature to libafl_libfuzzer_runtime * fix clippy * change return type of Feedback::last_result to a Result * remove expect in NewHashFeedback::is_interesting * move Error::premature_last_result to libafl from libafl_bolts
This commit is contained in:
parent
e4446b908c
commit
bce0f08294
@ -26,6 +26,9 @@ document-features = ["dep:document-features"]
|
|||||||
## Enables features that need rust's `std` lib to work, like print, env, ... support
|
## Enables features that need rust's `std` lib to work, like print, env, ... support
|
||||||
std = ["serde_json", "serde_json/std", "nix", "serde/std", "bincode", "wait-timeout", "uuid", "backtrace", "serial_test", "libafl_bolts/std", "typed-builder"]
|
std = ["serde_json", "serde_json/std", "nix", "serde/std", "bincode", "wait-timeout", "uuid", "backtrace", "serial_test", "libafl_bolts/std", "typed-builder"]
|
||||||
|
|
||||||
|
## Tracks the Feedbacks and the Objectives that were interesting for a Testcase
|
||||||
|
track_hit_feedbacks = ["std"]
|
||||||
|
|
||||||
## Collects performance statistics of the fuzzing pipeline and displays it on `Monitor` components
|
## Collects performance statistics of the fuzzing pipeline and displays it on `Monitor` components
|
||||||
introspection = []
|
introspection = []
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
//! It will contain a respective input, and metadata.
|
//! It will contain a respective input, and metadata.
|
||||||
|
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
use alloc::{borrow::Cow, vec::Vec};
|
||||||
use core::{
|
use core::{
|
||||||
cell::{Ref, RefMut},
|
cell::{Ref, RefMut},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
@ -67,6 +69,12 @@ where
|
|||||||
disabled: bool,
|
disabled: bool,
|
||||||
/// has found crash (or timeout) or not
|
/// has found crash (or timeout) or not
|
||||||
objectives_found: usize,
|
objectives_found: usize,
|
||||||
|
/// Vector of `Feedback` names that deemed this `Testcase` as corpus worthy
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_feedbacks: Vec<Cow<'static, str>>,
|
||||||
|
/// Vector of `Feedback` names that deemed this `Testcase` as solution worthy
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_objectives: Vec<Cow<'static, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> HasMetadata for Testcase<I>
|
impl<I> HasMetadata for Testcase<I>
|
||||||
@ -211,6 +219,34 @@ where
|
|||||||
self.disabled = disabled;
|
self.disabled = disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the hit feedbacks
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
pub fn hit_feedbacks(&self) -> &Vec<Cow<'static, str>> {
|
||||||
|
&self.hit_feedbacks
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the hit feedbacks (mutable)
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
pub fn hit_feedbacks_mut(&mut self) -> &mut Vec<Cow<'static, str>> {
|
||||||
|
&mut self.hit_feedbacks
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the hit objectives
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
pub fn hit_objectives(&self) -> &Vec<Cow<'static, str>> {
|
||||||
|
&self.hit_objectives
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the hit objectives (mutable)
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
pub fn hit_objectives_mut(&mut self) -> &mut Vec<Cow<'static, str>> {
|
||||||
|
&mut self.hit_objectives
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new Testcase instance given an input
|
/// Create a new Testcase instance given an input
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(mut input: I) -> Self {
|
pub fn new(mut input: I) -> Self {
|
||||||
@ -230,6 +266,10 @@ where
|
|||||||
parent_id: None,
|
parent_id: None,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
objectives_found: 0,
|
objectives_found: 0,
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_feedbacks: Vec::new(),
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_objectives: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,6 +292,10 @@ where
|
|||||||
parent_id: Some(parent_id),
|
parent_id: Some(parent_id),
|
||||||
disabled: false,
|
disabled: false,
|
||||||
objectives_found: 0,
|
objectives_found: 0,
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_feedbacks: Vec::new(),
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_objectives: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,6 +318,10 @@ where
|
|||||||
parent_id: None,
|
parent_id: None,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
objectives_found: 0,
|
objectives_found: 0,
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_feedbacks: Vec::new(),
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_objectives: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,6 +344,10 @@ where
|
|||||||
parent_id: None,
|
parent_id: None,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
objectives_found: 0,
|
objectives_found: 0,
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_feedbacks: Vec::new(),
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_objectives: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,6 +400,10 @@ where
|
|||||||
metadata_path: None,
|
metadata_path: None,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
objectives_found: 0,
|
objectives_found: 0,
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_feedbacks: Vec::new(),
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
hit_objectives: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,4 +97,9 @@ where
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ use libafl_bolts::{
|
|||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
use crate::feedbacks::premature_last_result_err;
|
||||||
use crate::{
|
use crate::{
|
||||||
events::EventFirer,
|
events::EventFirer,
|
||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
@ -61,6 +63,9 @@ where
|
|||||||
o1_ref: Handle<O1>,
|
o1_ref: Handle<O1>,
|
||||||
/// The second observer to compare against
|
/// The second observer to compare against
|
||||||
o2_ref: Handle<O2>,
|
o2_ref: Handle<O2>,
|
||||||
|
// The previous run's result of `Self::is_interesting`
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
last_result: Option<bool>,
|
||||||
/// The function used to compare the two observers
|
/// The function used to compare the two observers
|
||||||
compare_fn: F,
|
compare_fn: F,
|
||||||
phantomm: PhantomData<(I, S)>,
|
phantomm: PhantomData<(I, S)>,
|
||||||
@ -86,6 +91,8 @@ where
|
|||||||
o1_ref,
|
o1_ref,
|
||||||
o2_ref,
|
o2_ref,
|
||||||
name: Cow::from(name),
|
name: Cow::from(name),
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
last_result: None,
|
||||||
compare_fn,
|
compare_fn,
|
||||||
phantomm: PhantomData,
|
phantomm: PhantomData,
|
||||||
})
|
})
|
||||||
@ -108,6 +115,8 @@ where
|
|||||||
o1_ref: self.o1_ref.clone(),
|
o1_ref: self.o1_ref.clone(),
|
||||||
o2_ref: self.o2_ref.clone(),
|
o2_ref: self.o2_ref.clone(),
|
||||||
compare_fn: self.compare_fn.clone(),
|
compare_fn: self.compare_fn.clone(),
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
last_result: None,
|
||||||
phantomm: self.phantomm,
|
phantomm: self.phantomm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,8 +178,17 @@ where
|
|||||||
let o2: &O2 = observers
|
let o2: &O2 = observers
|
||||||
.get(&self.o2_ref)
|
.get(&self.o2_ref)
|
||||||
.ok_or_else(|| err(self.o2_ref.name()))?;
|
.ok_or_else(|| err(self.o2_ref.name()))?;
|
||||||
|
let res = (self.compare_fn)(o1, o2) == DiffResult::Diff;
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
{
|
||||||
|
self.last_result = Some(res);
|
||||||
|
}
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
Ok((self.compare_fn)(o1, o2) == DiffResult::Diff)
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
self.last_result.ok_or(premature_last_result_err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +143,10 @@ where
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(!self.novelty.is_empty())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Named for ListFeedback<T>
|
impl<T> Named for ListFeedback<T>
|
||||||
|
@ -18,6 +18,8 @@ use libafl_bolts::{
|
|||||||
use num_traits::PrimInt;
|
use num_traits::PrimInt;
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
use crate::feedbacks::premature_last_result_err;
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Testcase,
|
corpus::Testcase,
|
||||||
events::{Event, EventFirer},
|
events::{Event, EventFirer},
|
||||||
@ -391,6 +393,9 @@ pub struct MapFeedback<C, N, O, R, T> {
|
|||||||
map_ref: Handle<C>,
|
map_ref: Handle<C>,
|
||||||
/// Name of the feedback as shown in the `UserStats`
|
/// Name of the feedback as shown in the `UserStats`
|
||||||
stats_name: Cow<'static, str>,
|
stats_name: Cow<'static, str>,
|
||||||
|
// The previous run's result of [`Self::is_interesting`]
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
last_result: Option<bool>,
|
||||||
/// Phantom Data of Reducer
|
/// Phantom Data of Reducer
|
||||||
phantom: PhantomData<(C, N, O, R, T)>,
|
phantom: PhantomData<(C, N, O, R, T)>,
|
||||||
}
|
}
|
||||||
@ -424,7 +429,12 @@ where
|
|||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
OT: ObserversTuple<S>,
|
OT: ObserversTuple<S>,
|
||||||
{
|
{
|
||||||
Ok(self.is_interesting_default(state, manager, input, observers, exit_kind))
|
let res = self.is_interesting_default(state, manager, input, observers, exit_kind);
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
{
|
||||||
|
self.last_result = Some(res);
|
||||||
|
}
|
||||||
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustversion::not(nightly)]
|
#[rustversion::not(nightly)]
|
||||||
@ -440,7 +450,13 @@ where
|
|||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
OT: ObserversTuple<S>,
|
OT: ObserversTuple<S>,
|
||||||
{
|
{
|
||||||
Ok(self.is_interesting_default(state, manager, input, observers, exit_kind))
|
let res = self.is_interesting_default(state, manager, input, observers, exit_kind);
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
{
|
||||||
|
self.last_result = Some(res);
|
||||||
|
}
|
||||||
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_metadata<EM, OT>(
|
fn append_metadata<EM, OT>(
|
||||||
@ -533,6 +549,11 @@ where
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
self.last_result.ok_or(premature_last_result_err())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specialize for the common coverage map size, maximization of u8s
|
/// Specialize for the common coverage map size, maximization of u8s
|
||||||
@ -648,7 +669,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
{
|
||||||
|
self.last_result = Some(interesting);
|
||||||
|
}
|
||||||
Ok(interesting)
|
Ok(interesting)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -699,6 +723,8 @@ where
|
|||||||
name: map_observer.name().clone(),
|
name: map_observer.name().clone(),
|
||||||
map_ref: map_observer.handle(),
|
map_ref: map_observer.handle(),
|
||||||
stats_name: create_stats_name(map_observer.name()),
|
stats_name: create_stats_name(map_observer.name()),
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
last_result: None,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,6 +740,8 @@ where
|
|||||||
map_ref: map_observer.handle(),
|
map_ref: map_observer.handle(),
|
||||||
stats_name: create_stats_name(&name),
|
stats_name: create_stats_name(&name),
|
||||||
name,
|
name,
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
last_result: None,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
// TODO: make S of Feedback<S> an associated type when specialisation + AT is stable
|
// TODO: make S of Feedback<S> an associated type when specialisation + AT is stable
|
||||||
|
|
||||||
use alloc::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
use alloc::vec::Vec;
|
||||||
use core::{
|
use core::{
|
||||||
fmt::{self, Debug, Formatter},
|
fmt::{self, Debug, Formatter},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
@ -35,12 +37,10 @@ use crate::{
|
|||||||
state::State,
|
state::State,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod map;
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub mod concolic;
|
pub mod concolic;
|
||||||
pub mod differential;
|
pub mod differential;
|
||||||
|
pub mod map;
|
||||||
#[cfg(feature = "nautilus")]
|
#[cfg(feature = "nautilus")]
|
||||||
pub mod nautilus;
|
pub mod nautilus;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -113,6 +113,21 @@ where
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// CUT MY LIFE INTO PIECES; THIS IS MY LAST [`Feedback::is_interesting`] run
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error>;
|
||||||
|
|
||||||
|
/// 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`]
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn append_hit_feedbacks(&self, list: &mut Vec<Cow<'static, str>>) -> Result<(), Error> {
|
||||||
|
if self.last_result()? {
|
||||||
|
list.push(self.name().clone());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// 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)]
|
||||||
@ -211,7 +226,14 @@ where
|
|||||||
self.second.init_state(state)?;
|
self.second.init_state(state)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
FL::last_result(&self.first, &self.second)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn append_hit_feedbacks(&self, list: &mut Vec<Cow<'static, str>>) -> Result<(), Error> {
|
||||||
|
FL::append_hit_feedbacks(&self.first, &self.second, list)
|
||||||
|
}
|
||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
fn is_interesting<EM, OT>(
|
fn is_interesting<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -326,6 +348,20 @@ where
|
|||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
OT: ObserversTuple<S>;
|
OT: ObserversTuple<S>;
|
||||||
|
|
||||||
|
/// Get the result of the last `Self::is_interesting` run
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(first: &A, second: &B) -> Result<bool, Error>;
|
||||||
|
|
||||||
|
/// 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`]
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn append_hit_feedbacks(
|
||||||
|
first: &A,
|
||||||
|
second: &B,
|
||||||
|
list: &mut Vec<Cow<'static, str>>,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
/// If this pair is interesting (with introspection features enabled)
|
/// If this pair is interesting (with introspection features enabled)
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
@ -407,6 +443,27 @@ where
|
|||||||
let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
|
let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
|
||||||
Ok(a || b)
|
Ok(a || b)
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(first: &A, second: &B) -> Result<bool, Error> {
|
||||||
|
Ok(first.last_result()? || second.last_result()?)
|
||||||
|
}
|
||||||
|
/// 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,
|
||||||
|
list: &mut Vec<Cow<'static, str>>,
|
||||||
|
) -> 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")]
|
#[cfg(feature = "introspection")]
|
||||||
fn is_pair_interesting_introspection<EM, OT>(
|
fn is_pair_interesting_introspection<EM, OT>(
|
||||||
@ -460,6 +517,28 @@ where
|
|||||||
|
|
||||||
second.is_interesting(state, manager, input, observers, exit_kind)
|
second.is_interesting(state, manager, input, observers, exit_kind)
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(first: &A, second: &B) -> Result<bool, Error> {
|
||||||
|
if first.last_result()? {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The second must have run if the first wasn't interesting
|
||||||
|
second.last_result()
|
||||||
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn append_hit_feedbacks(
|
||||||
|
first: &A,
|
||||||
|
second: &B,
|
||||||
|
list: &mut Vec<Cow<'static, str>>,
|
||||||
|
) -> 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")]
|
#[cfg(feature = "introspection")]
|
||||||
fn is_pair_interesting_introspection<EM, OT>(
|
fn is_pair_interesting_introspection<EM, OT>(
|
||||||
@ -514,6 +593,23 @@ where
|
|||||||
Ok(a && b)
|
Ok(a && b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(first: &A, second: &B) -> Result<bool, Error> {
|
||||||
|
Ok(first.last_result()? && second.last_result()?)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn append_hit_feedbacks(
|
||||||
|
first: &A,
|
||||||
|
second: &B,
|
||||||
|
list: &mut Vec<Cow<'static, str>>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if first.last_result()? && second.last_result()? {
|
||||||
|
first.append_hit_feedbacks(list)?;
|
||||||
|
second.append_hit_feedbacks(list)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
fn is_pair_interesting_introspection<EM, OT>(
|
fn is_pair_interesting_introspection<EM, OT>(
|
||||||
first: &mut A,
|
first: &mut A,
|
||||||
@ -567,6 +663,30 @@ where
|
|||||||
second.is_interesting(state, manager, input, observers, exit_kind)
|
second.is_interesting(state, manager, input, observers, exit_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(first: &A, second: &B) -> Result<bool, Error> {
|
||||||
|
if !first.last_result()? {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The second must have run if the first wasn't interesting
|
||||||
|
second.last_result()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn append_hit_feedbacks(
|
||||||
|
first: &A,
|
||||||
|
second: &B,
|
||||||
|
list: &mut Vec<Cow<'static, str>>,
|
||||||
|
) -> 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")]
|
#[cfg(feature = "introspection")]
|
||||||
fn is_pair_interesting_introspection<EM, OT>(
|
fn is_pair_interesting_introspection<EM, OT>(
|
||||||
first: &mut A,
|
first: &mut A,
|
||||||
@ -684,6 +804,11 @@ where
|
|||||||
fn discard_metadata(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
|
fn discard_metadata(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
|
||||||
self.first.discard_metadata(state, input)
|
self.first.discard_metadata(state, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(!self.first.last_result()?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, S> Named for NotFeedback<A, S>
|
impl<A, S> Named for NotFeedback<A, S>
|
||||||
@ -785,11 +910,19 @@ where
|
|||||||
{
|
{
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`CrashFeedback`] reports as interesting if the target crashed.
|
/// A [`CrashFeedback`] reports as interesting if the target crashed.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct CrashFeedback;
|
pub struct CrashFeedback {
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
// The previous run's result of `Self::is_interesting`
|
||||||
|
last_result: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<S> Feedback<S> for CrashFeedback
|
impl<S> Feedback<S> for CrashFeedback
|
||||||
where
|
where
|
||||||
@ -808,11 +941,17 @@ where
|
|||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
OT: ObserversTuple<S>,
|
OT: ObserversTuple<S>,
|
||||||
{
|
{
|
||||||
if let ExitKind::Crash = exit_kind {
|
let res = matches!(exit_kind, ExitKind::Crash);
|
||||||
Ok(true)
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
} else {
|
{
|
||||||
Ok(false)
|
self.last_result = Some(res);
|
||||||
}
|
}
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
self.last_result.ok_or(premature_last_result_err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -828,7 +967,10 @@ impl CrashFeedback {
|
|||||||
/// Creates a new [`CrashFeedback`]
|
/// Creates a new [`CrashFeedback`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self
|
Self {
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
last_result: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -846,7 +988,11 @@ impl<S: State, T> FeedbackFactory<CrashFeedback, S, T> for CrashFeedback {
|
|||||||
|
|
||||||
/// A [`TimeoutFeedback`] reduces the timeout value of a run.
|
/// A [`TimeoutFeedback`] reduces the timeout value of a run.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct TimeoutFeedback;
|
pub struct TimeoutFeedback {
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
// The previous run's result of `Self::is_interesting`
|
||||||
|
last_result: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<S> Feedback<S> for TimeoutFeedback
|
impl<S> Feedback<S> for TimeoutFeedback
|
||||||
where
|
where
|
||||||
@ -865,11 +1011,17 @@ where
|
|||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
OT: ObserversTuple<S>,
|
OT: ObserversTuple<S>,
|
||||||
{
|
{
|
||||||
if let ExitKind::Timeout = exit_kind {
|
let res = matches!(exit_kind, ExitKind::Timeout);
|
||||||
Ok(true)
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
} else {
|
{
|
||||||
Ok(false)
|
self.last_result = Some(res);
|
||||||
}
|
}
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
self.last_result.ok_or(premature_last_result_err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -885,7 +1037,10 @@ impl TimeoutFeedback {
|
|||||||
/// Returns a new [`TimeoutFeedback`].
|
/// Returns a new [`TimeoutFeedback`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self
|
Self {
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
last_result: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -904,7 +1059,11 @@ impl<S: State, T> FeedbackFactory<TimeoutFeedback, S, T> for TimeoutFeedback {
|
|||||||
|
|
||||||
/// A [`DiffExitKindFeedback`] checks if there is a difference in the [`crate::executors::ExitKind`]s in a [`crate::executors::DiffExecutor`].
|
/// A [`DiffExitKindFeedback`] checks if there is a difference in the [`crate::executors::ExitKind`]s in a [`crate::executors::DiffExecutor`].
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct DiffExitKindFeedback;
|
pub struct DiffExitKindFeedback {
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
// The previous run's result of `Self::is_interesting`
|
||||||
|
last_result: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<S> Feedback<S> for DiffExitKindFeedback
|
impl<S> Feedback<S> for DiffExitKindFeedback
|
||||||
where
|
where
|
||||||
@ -923,7 +1082,16 @@ where
|
|||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
OT: ObserversTuple<S>,
|
OT: ObserversTuple<S>,
|
||||||
{
|
{
|
||||||
Ok(matches!(exit_kind, ExitKind::Diff { .. }))
|
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<bool, Error> {
|
||||||
|
self.last_result.ok_or(premature_last_result_err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -939,7 +1107,10 @@ impl DiffExitKindFeedback {
|
|||||||
/// Returns a new [`DiffExitKindFeedback`].
|
/// Returns a new [`DiffExitKindFeedback`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self
|
Self {
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
last_result: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1008,6 +1179,11 @@ where
|
|||||||
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
|
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Named for TimeFeedback {
|
impl Named for TimeFeedback {
|
||||||
@ -1055,10 +1231,12 @@ where
|
|||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
OT: ObserversTuple<S>,
|
OT: ObserversTuple<S>,
|
||||||
{
|
{
|
||||||
Ok(match self {
|
Ok((*self).into())
|
||||||
ConstFeedback::True => true,
|
}
|
||||||
ConstFeedback::False => false,
|
|
||||||
})
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok((*self).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1087,3 +1265,18 @@ impl From<bool> for ConstFeedback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ConstFeedback> for bool {
|
||||||
|
fn from(value: ConstFeedback) -> Self {
|
||||||
|
match value {
|
||||||
|
ConstFeedback::True => true,
|
||||||
|
ConstFeedback::False => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
/// Error if [`Feedback::last_result`] is called before the `Feedback` is actually run.
|
||||||
|
pub(crate) fn premature_last_result_err() -> Error {
|
||||||
|
Error::illegal_state("last_result called before Feedback was run")
|
||||||
|
}
|
||||||
|
@ -123,4 +123,8 @@ where
|
|||||||
fn discard_metadata(&mut self, _state: &mut S, _input: &NautilusInput) -> Result<(), Error> {
|
fn discard_metadata(&mut self, _state: &mut S, _input: &NautilusInput) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ use libafl_bolts::{
|
|||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
use crate::feedbacks::premature_last_result_err;
|
||||||
use crate::{
|
use crate::{
|
||||||
events::EventFirer,
|
events::EventFirer,
|
||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
@ -85,6 +87,9 @@ pub struct NewHashFeedback<O, S> {
|
|||||||
o_ref: Handle<O>,
|
o_ref: Handle<O>,
|
||||||
/// Initial capacity of hash set
|
/// Initial capacity of hash set
|
||||||
capacity: usize,
|
capacity: usize,
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
// The previous run's result of `Self::is_interesting`
|
||||||
|
last_result: Option<bool>,
|
||||||
phantom: PhantomData<S>,
|
phantom: PhantomData<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,18 +128,22 @@ where
|
|||||||
.get_mut::<NewHashFeedbackMetadata>(&self.name)
|
.get_mut::<NewHashFeedbackMetadata>(&self.name)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match observer.hash() {
|
let res = match observer.hash() {
|
||||||
Some(hash) => {
|
Some(hash) => backtrace_state.update_hash_set(hash)?,
|
||||||
let res = backtrace_state
|
|
||||||
.update_hash_set(hash)
|
|
||||||
.expect("Failed to update the hash state");
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
// We get here if the hash was not updated, i.e the first run or if no crash happens
|
// We get here if the hash was not updated, i.e the first run or if no crash happens
|
||||||
Ok(false)
|
false
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
{
|
||||||
|
self.last_result = Some(res);
|
||||||
}
|
}
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
self.last_result.ok_or(premature_last_result_err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,6 +187,8 @@ where
|
|||||||
name: Cow::from(NEWHASHFEEDBACK_PREFIX.to_string() + observer.name()),
|
name: Cow::from(NEWHASHFEEDBACK_PREFIX.to_string() + observer.name()),
|
||||||
o_ref: observer.handle(),
|
o_ref: observer.handle(),
|
||||||
capacity,
|
capacity,
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
last_result: None,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,11 @@ where
|
|||||||
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
|
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Named for StdOutToMetadataFeedback {
|
impl Named for StdOutToMetadataFeedback {
|
||||||
@ -180,6 +185,10 @@ where
|
|||||||
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
|
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Named for StdErrToMetadataFeedback {
|
impl Named for StdErrToMetadataFeedback {
|
||||||
|
@ -6,11 +6,12 @@ use alloc::borrow::Cow;
|
|||||||
use libafl_bolts::{impl_serdeany, Error, Named};
|
use libafl_bolts::{impl_serdeany, Error, Named};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
use crate::feedbacks::premature_last_result_err;
|
||||||
use crate::{
|
use crate::{
|
||||||
events::EventFirer, executors::ExitKind, feedbacks::Feedback, observers::ObserversTuple,
|
events::EventFirer, executors::ExitKind, feedbacks::Feedback, observers::ObserversTuple,
|
||||||
state::State, HasMetadata,
|
state::State, HasMetadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Constant name of the [`TransferringMetadata`].
|
/// Constant name of the [`TransferringMetadata`].
|
||||||
pub const TRANSFERRED_FEEDBACK_NAME: Cow<'static, str> =
|
pub const TRANSFERRED_FEEDBACK_NAME: Cow<'static, str> =
|
||||||
Cow::Borrowed("transferred_feedback_internal");
|
Cow::Borrowed("transferred_feedback_internal");
|
||||||
@ -37,7 +38,11 @@ impl TransferringMetadata {
|
|||||||
/// Simple feedback which may be used to test whether the testcase was transferred from another node
|
/// Simple feedback which may be used to test whether the testcase was transferred from another node
|
||||||
/// in a multi-node fuzzing arrangement.
|
/// in a multi-node fuzzing arrangement.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct TransferredFeedback;
|
pub struct TransferredFeedback {
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
// The previous run's result of `Self::is_interesting`
|
||||||
|
last_result: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Named for TransferredFeedback {
|
impl Named for TransferredFeedback {
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
@ -66,6 +71,15 @@ where
|
|||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
OT: ObserversTuple<S>,
|
OT: ObserversTuple<S>,
|
||||||
{
|
{
|
||||||
Ok(state.metadata::<TransferringMetadata>()?.transferring)
|
let res = state.metadata::<TransferringMetadata>()?.transferring;
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
{
|
||||||
|
self.last_result = Some(res);
|
||||||
|
}
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
self.last_result.ok_or(premature_last_result_err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -465,6 +465,9 @@ 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());
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
self.feedback_mut()
|
||||||
|
.append_hit_feedbacks(testcase.hit_feedbacks_mut())?;
|
||||||
self.feedback_mut()
|
self.feedback_mut()
|
||||||
.append_metadata(state, manager, observers, &mut testcase)?;
|
.append_metadata(state, manager, observers, &mut testcase)?;
|
||||||
let idx = state.corpus_mut().add(testcase)?;
|
let idx = state.corpus_mut().add(testcase)?;
|
||||||
@ -507,6 +510,9 @@ where
|
|||||||
if let Ok(mut tc) = state.current_testcase_mut() {
|
if let Ok(mut tc) = state.current_testcase_mut() {
|
||||||
tc.found_objective();
|
tc.found_objective();
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
self.objective_mut()
|
||||||
|
.append_hit_feedbacks(testcase.hit_objectives_mut())?;
|
||||||
self.objective_mut()
|
self.objective_mut()
|
||||||
.append_metadata(state, manager, observers, &mut testcase)?;
|
.append_metadata(state, manager, observers, &mut testcase)?;
|
||||||
state.solutions_mut().add(testcase)?;
|
state.solutions_mut().add(testcase)?;
|
||||||
@ -621,6 +627,9 @@ where
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
if is_solution {
|
if is_solution {
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
self.objective_mut()
|
||||||
|
.append_hit_feedbacks(testcase.hit_objectives_mut())?;
|
||||||
self.objective_mut()
|
self.objective_mut()
|
||||||
.append_metadata(state, manager, &*observers, &mut testcase)?;
|
.append_metadata(state, manager, &*observers, &mut testcase)?;
|
||||||
let idx = state.solutions_mut().add(testcase)?;
|
let idx = state.solutions_mut().add(testcase)?;
|
||||||
@ -656,6 +665,9 @@ where
|
|||||||
&exit_kind,
|
&exit_kind,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
self.feedback_mut()
|
||||||
|
.append_hit_feedbacks(testcase.hit_feedbacks_mut())?;
|
||||||
// Add the input to the main corpus
|
// Add the input to the main corpus
|
||||||
self.feedback_mut()
|
self.feedback_mut()
|
||||||
.append_metadata(state, manager, &*observers, &mut testcase)?;
|
.append_metadata(state, manager, &*observers, &mut testcase)?;
|
||||||
|
@ -9,6 +9,8 @@ use libafl_bolts::{
|
|||||||
HasLen, Named,
|
HasLen, Named,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
use crate::feedbacks::premature_last_result_err;
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, HasCurrentCorpusId, Testcase},
|
corpus::{Corpus, HasCurrentCorpusId, Testcase},
|
||||||
events::EventFirer,
|
events::EventFirer,
|
||||||
@ -31,7 +33,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
use crate::{monitors::PerfFeature, state::HasClientPerfMonitor};
|
use crate::{monitors::PerfFeature, state::HasClientPerfMonitor};
|
||||||
|
|
||||||
/// Mutational stage which minimizes corpus entries.
|
/// Mutational stage which minimizes corpus entries.
|
||||||
///
|
///
|
||||||
/// You must provide at least one mutator that actually reduces size.
|
/// You must provide at least one mutator that actually reduces size.
|
||||||
@ -355,6 +356,9 @@ pub struct MapEqualityFeedback<C, M, S> {
|
|||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
map_ref: Handle<C>,
|
map_ref: Handle<C>,
|
||||||
orig_hash: u64,
|
orig_hash: u64,
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
// The previous run's result of `Self::is_interesting`
|
||||||
|
last_result: Option<bool>,
|
||||||
phantom: PhantomData<(M, S)>,
|
phantom: PhantomData<(M, S)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +397,16 @@ where
|
|||||||
let obs = observers
|
let obs = observers
|
||||||
.get(self.observer_handle())
|
.get(self.observer_handle())
|
||||||
.expect("Should have been provided valid observer name.");
|
.expect("Should have been provided valid observer name.");
|
||||||
Ok(obs.as_ref().hash_simple() == self.orig_hash)
|
let res = obs.as_ref().hash_simple() == self.orig_hash;
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
{
|
||||||
|
self.last_result = Some(res);
|
||||||
|
}
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
self.last_result.ok_or(premature_last_result_err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,6 +455,8 @@ where
|
|||||||
name: Cow::from("MapEq"),
|
name: Cow::from("MapEq"),
|
||||||
map_ref: obs.handle(),
|
map_ref: obs.handle(),
|
||||||
orig_hash: obs.as_ref().hash_simple(),
|
orig_hash: obs.as_ref().hash_simple(),
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
last_result: None,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ all-features = true
|
|||||||
default = ["serdeany_autoreg"]
|
default = ["serdeany_autoreg"]
|
||||||
cmplog = ["iced-x86"]
|
cmplog = ["iced-x86"]
|
||||||
serdeany_autoreg = ["libafl_bolts/serdeany_autoreg"]
|
serdeany_autoreg = ["libafl_bolts/serdeany_autoreg"]
|
||||||
|
track_hit_feedbacks = ["libafl/track_hit_feedbacks"]
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = { version = "1.0", features = ["parallel"] }
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
|
||||||
|
@ -701,6 +701,11 @@ where
|
|||||||
self.errors = None;
|
self.errors = None;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(self.errors.is_some())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Named for AsanErrorsFeedback<S> {
|
impl<S> Named for AsanErrorsFeedback<S> {
|
||||||
|
@ -10,6 +10,7 @@ publish = false
|
|||||||
default = ["fork"]
|
default = ["fork"]
|
||||||
## Enables forking mode for the LibAFL launcher (instead of starting new processes)
|
## Enables forking mode for the LibAFL launcher (instead of starting new processes)
|
||||||
fork = ["libafl/fork"]
|
fork = ["libafl/fork"]
|
||||||
|
track_hit_feedbacks = ["libafl/track_hit_feedbacks", "libafl_targets/track_hit_feedbacks"]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
@ -47,6 +48,7 @@ utf8-chars = "3.0.1"
|
|||||||
|
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = "0.69.4"
|
bindgen = "0.69.4"
|
||||||
cc = { version = "1.0", features = ["parallel"] }
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
@ -61,6 +61,11 @@ where
|
|||||||
{
|
{
|
||||||
Ok(*self.keep.borrow())
|
Ok(*self.keep.borrow())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(*self.keep.borrow())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
@ -133,6 +138,10 @@ where
|
|||||||
self.exit_kind = *exit_kind;
|
self.exit_kind = *exit_kind;
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
fn append_metadata<EM, OT>(
|
fn append_metadata<EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -93,7 +93,7 @@ fn minimize_crash_with_mutator<M: Mutator<BytesInput, TMinState>>(
|
|||||||
fuzzer.fuzz_one(&mut stages, &mut executor, &mut state, &mut mgr)?;
|
fuzzer.fuzz_one(&mut stages, &mut executor, &mut state, &mut mgr)?;
|
||||||
}
|
}
|
||||||
ExitKind::Timeout => {
|
ExitKind::Timeout => {
|
||||||
let factory = TimeoutFeedback;
|
let factory = TimeoutFeedback::new();
|
||||||
let tmin = StdTMinMutationalStage::new(
|
let tmin = StdTMinMutationalStage::new(
|
||||||
mutator,
|
mutator,
|
||||||
factory,
|
factory,
|
||||||
|
@ -7,7 +7,7 @@ use std::{
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
executors::{Executor, ExitKind, HasObservers},
|
executors::{Executor, ExitKind, HasObservers},
|
||||||
inputs::HasTargetBytes,
|
inputs::HasTargetBytes,
|
||||||
observers::{ObserversTuple, StdErrObserver, StdOutObserver, UsesObservers},
|
observers::{ObserversTuple, StdOutObserver, UsesObservers},
|
||||||
state::{HasExecutions, State, UsesState},
|
state::{HasExecutions, State, UsesState},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -153,6 +153,12 @@ pub struct NyxExecutorBuilder {
|
|||||||
// stderr: Option<StdErrObserver>,
|
// stderr: Option<StdErrObserver>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for NyxExecutorBuilder {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NyxExecutorBuilder {
|
impl NyxExecutorBuilder {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -41,8 +41,6 @@ use crate::{
|
|||||||
|
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
mod usermode;
|
mod usermode;
|
||||||
#[cfg(emulation_mode = "usermode")]
|
|
||||||
pub use usermode::*;
|
|
||||||
|
|
||||||
#[cfg(emulation_mode = "systemmode")]
|
#[cfg(emulation_mode = "systemmode")]
|
||||||
mod systemmode;
|
mod systemmode;
|
||||||
|
@ -59,7 +59,7 @@ windows_asan = ["common"] # Compile C code for ASAN on Windows
|
|||||||
whole_archive = [] # use +whole-archive to ensure the presence of weak symbols
|
whole_archive = [] # use +whole-archive to ensure the presence of weak symbols
|
||||||
cmplog_extended_instrumentation = [] # support for aflpp cmplog map, we will remove this once aflpp and libafl cmplog shares the same LLVM passes.
|
cmplog_extended_instrumentation = [] # support for aflpp cmplog map, we will remove this once aflpp and libafl cmplog shares the same LLVM passes.
|
||||||
function-logging = ["common"]
|
function-logging = ["common"]
|
||||||
|
track_hit_feedbacks = ["libafl/track_hit_feedbacks"]
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = "0.69.4"
|
bindgen = "0.69.4"
|
||||||
cc = { version = "1.0", features = ["parallel"] }
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
@ -167,4 +167,9 @@ where
|
|||||||
{
|
{
|
||||||
Ok(Self::oomed())
|
Ok(Self::oomed())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "track_hit_feedbacks")]
|
||||||
|
fn last_result(&self) -> Result<bool, Error> {
|
||||||
|
Ok(Self::oomed())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user