diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs
index b7e001b8f0..2103a894cb 100644
--- a/libafl/src/feedbacks/mod.rs
+++ b/libafl/src/feedbacks/mod.rs
@@ -108,26 +108,54 @@ where
{
}
-/// Compose [`Feedback`]`s` with an `AND` operation
-pub struct AndFeedback
+pub struct CombinedFeedback
where
A: Feedback,
B: Feedback,
+ FL: FeedbackLogic,
I: Input,
{
- /// The first [`Feedback`] to `AND`.
pub first: A,
- /// The second [`Feedback`] to `AND`.
pub second: B,
- /// The name
name: String,
- phantom: PhantomData<(I, S)>,
+ phantom: PhantomData<(I, S, FL)>,
}
-impl Feedback for AndFeedback
+impl Named for CombinedFeedback
where
A: Feedback,
B: Feedback,
+ FL: FeedbackLogic,
+ I: Input,
+{
+ fn name(&self) -> &str {
+ self.name.as_ref()
+ }
+}
+
+impl CombinedFeedback
+where
+ A: Feedback,
+ B: Feedback,
+ FL: FeedbackLogic,
+ I: Input,
+{
+ pub fn new(first: A, second: B) -> Self {
+ let name = format!("{} ({},{})", FL::name(), first.name(), second.name());
+ Self {
+ first,
+ second,
+ name,
+ phantom: PhantomData,
+ }
+ }
+}
+
+impl Feedback for CombinedFeedback
+where
+ A: Feedback,
+ B: Feedback,
+ FL: FeedbackLogic,
I: Input,
{
fn is_interesting(
@@ -142,14 +170,15 @@ where
EM: EventFirer,
OT: ObserversTuple,
{
- let a = self
- .first
- .is_interesting(state, manager, input, observers, exit_kind)?;
- let b = a
- && self
- .second
- .is_interesting(state, manager, input, observers, exit_kind)?;
- Ok(b)
+ FL::is_pair_interesting(
+ &mut self.first,
+ &mut self.second,
+ state,
+ manager,
+ input,
+ observers,
+ exit_kind,
+ )
}
#[cfg(feature = "introspection")]
@@ -167,27 +196,17 @@ where
EM: EventFirer,
OT: ObserversTuple,
{
- // Execute this feedback
- let a = self.first.is_interesting_with_perf(
+ FL::is_pair_interesting_with_perf(
+ &mut self.first,
+ &mut self.second,
state,
manager,
input,
observers,
- &exit_kind,
+ exit_kind,
feedback_stats,
feedback_index,
- )?;
- let b = a
- && self.second.is_interesting_with_perf(
- state,
- manager,
- input,
- observers,
- &exit_kind,
- feedback_stats,
- feedback_index + 1,
- )?;
- Ok(b)
+ )
}
#[inline]
@@ -203,60 +222,62 @@ where
}
}
-impl Named for AndFeedback
+pub trait FeedbackLogic: 'static
where
A: Feedback,
B: Feedback,
I: Input,
{
- #[inline]
- fn name(&self) -> &str {
- &self.name
+ fn name() -> &'static str;
+
+ fn is_pair_interesting(
+ first: &mut A,
+ second: &mut B,
+ state: &mut S,
+ manager: &mut EM,
+ input: &I,
+ observers: &OT,
+ exit_kind: &ExitKind,
+ ) -> Result
+ where
+ EM: EventFirer,
+ OT: ObserversTuple;
+
+ #[cfg(feature = "introspection")]
+ fn is_pair_interesting_with_perf(
+ first: &mut A,
+ second: &mut B,
+ state: &mut S,
+ manager: &mut EM,
+ input: &I,
+ observers: &OT,
+ exit_kind: &ExitKind,
+ feedback_stats: &mut [u64; NUM_FEEDBACKS],
+ feedback_index: usize,
+ ) -> Result
+ where
+ EM: EventFirer,
+ OT: ObserversTuple;
+}
+
+pub struct LogicEagerOr {}
+pub struct LogicFastOr {}
+pub struct LogicEagerAnd {}
+pub struct LogicFastAnd {}
+
+impl FeedbackLogic for LogicEagerOr
+where
+ A: Feedback,
+ B: Feedback,
+ I: Input,
+{
+ fn name() -> &'static str {
+ "Eager OR"
}
-}
-impl AndFeedback
-where
- A: Feedback,
- B: Feedback,
- I: Input,
-{
- /// Creates a new [`AndFeedback`], resulting in the `AND` of two feedbacks.
- pub fn new(first: A, second: B) -> Self {
- let name = format!("And({}, {})", first.name(), second.name());
- Self {
- first,
- second,
- name,
- phantom: PhantomData,
- }
- }
-}
-
-/// Compose feedbacks with an OR operation
-pub struct OrFeedback
-where
- A: Feedback,
- B: Feedback,
- I: Input,
-{
- /// The first [`Feedback`]
- pub first: A,
- /// The second [`Feedback`], `OR`ed with the first.
- pub second: B,
- /// The name
- name: String,
- phantom: PhantomData<(I, S)>,
-}
-
-impl Feedback for OrFeedback
-where
- A: Feedback,
- B: Feedback,
- I: Input,
-{
- fn is_interesting(
- &mut self,
+ fn is_pair_interesting(
+ first: &mut A,
+ second: &mut B,
state: &mut S,
manager: &mut EM,
input: &I,
@@ -267,19 +288,15 @@ where
EM: EventFirer,
OT: ObserversTuple,
{
- let a = self
- .first
- .is_interesting(state, manager, input, observers, exit_kind)?;
- let b = a
- || self
- .second
- .is_interesting(state, manager, input, observers, exit_kind)?;
- Ok(b)
+ let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
+ let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
+ Ok(a || b)
}
#[cfg(feature = "introspection")]
- fn is_interesting_with_perf(
- &mut self,
+ fn is_pair_interesting_with_perf(
+ first: &mut A,
+ second: &mut B,
state: &mut S,
manager: &mut EM,
input: &I,
@@ -293,7 +310,7 @@ where
OT: ObserversTuple,
{
// Execute this feedback
- let a = self.first.is_interesting_with_perf(
+ let a = first.is_interesting_with_perf(
state,
manager,
input,
@@ -302,62 +319,254 @@ where
feedback_stats,
feedback_index,
)?;
- let b = a
- || self.second.is_interesting_with_perf(
- state,
- manager,
- input,
- observers,
- &exit_kind,
- feedback_stats,
- feedback_index + 1,
- )?;
- Ok(b)
- }
- #[inline]
- fn append_metadata(&mut self, state: &mut S, testcase: &mut Testcase) -> Result<(), Error> {
- self.first.append_metadata(state, testcase)?;
- self.second.append_metadata(state, testcase)
- }
-
- #[inline]
- fn discard_metadata(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
- self.first.discard_metadata(state, input)?;
- self.second.discard_metadata(state, input)
+ let b = second.is_interesting_with_perf(
+ state,
+ manager,
+ input,
+ observers,
+ &exit_kind,
+ feedback_stats,
+ feedback_index + 1,
+ )?;
+ Ok(a || b)
}
}
-impl Named for OrFeedback
+impl FeedbackLogic for LogicFastOr
where
A: Feedback,
B: Feedback,
I: Input,
{
- #[inline]
- fn name(&self) -> &str {
- &self.name
+ fn name() -> &'static str {
+ "Fast OR"
}
-}
-impl OrFeedback
-where
- A: Feedback,
- B: Feedback,
- I: Input,
-{
- /// Creates a new [`OrFeedback`] for two feedbacks.
- pub fn new(first: A, second: B) -> Self {
- let name = format!("Or({}, {})", first.name(), second.name());
- Self {
- first,
- second,
- name,
- phantom: PhantomData,
+ fn is_pair_interesting(
+ first: &mut A,
+ second: &mut B,
+ state: &mut S,
+ manager: &mut EM,
+ input: &I,
+ observers: &OT,
+ exit_kind: &ExitKind,
+ ) -> Result
+ where
+ EM: EventFirer,
+ OT: ObserversTuple,
+ {
+ let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
+ if a {
+ return Ok(true);
}
+
+ second.is_interesting(state, manager, input, observers, exit_kind)
+ }
+
+ #[cfg(feature = "introspection")]
+ fn is_pair_interesting_with_perf(
+ first: &mut A,
+ second: &mut B,
+ state: &mut S,
+ manager: &mut EM,
+ input: &I,
+ observers: &OT,
+ exit_kind: &ExitKind,
+ feedback_stats: &mut [u64; NUM_FEEDBACKS],
+ feedback_index: usize,
+ ) -> Result
+ where
+ EM: EventFirer,
+ OT: ObserversTuple,
+ {
+ // Execute this feedback
+ let a = first.is_interesting_with_perf(
+ state,
+ manager,
+ input,
+ observers,
+ &exit_kind,
+ feedback_stats,
+ feedback_index,
+ )?;
+
+ if a {
+ return Ok(true);
+ }
+
+ second.is_interesting_with_perf(
+ state,
+ manager,
+ input,
+ observers,
+ &exit_kind,
+ feedback_stats,
+ feedback_index + 1,
+ )
}
}
+impl FeedbackLogic for LogicEagerAnd
+where
+ A: Feedback,
+ B: Feedback,
+ I: Input,
+{
+ fn name() -> &'static str {
+ "Eager AND"
+ }
+
+ fn is_pair_interesting(
+ first: &mut A,
+ second: &mut B,
+ state: &mut S,
+ manager: &mut EM,
+ input: &I,
+ observers: &OT,
+ exit_kind: &ExitKind,
+ ) -> Result
+ where
+ EM: EventFirer,
+ OT: ObserversTuple,
+ {
+ let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
+ let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
+ Ok(a && b)
+ }
+
+ #[cfg(feature = "introspection")]
+ fn is_pair_interesting_with_perf(
+ first: &mut A,
+ second: &mut B,
+ state: &mut S,
+ manager: &mut EM,
+ input: &I,
+ observers: &OT,
+ exit_kind: &ExitKind,
+ feedback_stats: &mut [u64; NUM_FEEDBACKS],
+ feedback_index: usize,
+ ) -> Result
+ where
+ EM: EventFirer,
+ OT: ObserversTuple,
+ {
+ // Execute this feedback
+ let a = first.is_interesting_with_perf(
+ state,
+ manager,
+ input,
+ observers,
+ &exit_kind,
+ feedback_stats,
+ feedback_index,
+ )?;
+
+ let b = second.is_interesting_with_perf(
+ state,
+ manager,
+ input,
+ observers,
+ &exit_kind,
+ feedback_stats,
+ feedback_index + 1,
+ )?;
+ Ok(a && b)
+ }
+}
+
+impl FeedbackLogic for LogicFastAnd
+where
+ A: Feedback,
+ B: Feedback,
+ I: Input,
+{
+ fn name() -> &'static str {
+ "Fast AND"
+ }
+
+ fn is_pair_interesting(
+ first: &mut A,
+ second: &mut B,
+ state: &mut S,
+ manager: &mut EM,
+ input: &I,
+ observers: &OT,
+ exit_kind: &ExitKind,
+ ) -> Result
+ where
+ EM: EventFirer,
+ OT: ObserversTuple,
+ {
+ let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
+ if a == false {
+ return Ok(false);
+ }
+
+ second.is_interesting(state, manager, input, observers, exit_kind)
+ }
+
+ #[cfg(feature = "introspection")]
+ fn is_pair_interesting_with_perf(
+ first: &mut A,
+ second: &mut B,
+ state: &mut S,
+ manager: &mut EM,
+ input: &I,
+ observers: &OT,
+ exit_kind: &ExitKind,
+ feedback_stats: &mut [u64; NUM_FEEDBACKS],
+ feedback_index: usize,
+ ) -> Result
+ where
+ EM: EventFirer,
+ OT: ObserversTuple,
+ {
+ // Execute this feedback
+ let a = first.is_interesting_with_perf(
+ state,
+ manager,
+ input,
+ observers,
+ &exit_kind,
+ feedback_stats,
+ feedback_index,
+ )?;
+
+ if a == false {
+ return Ok(false);
+ }
+
+ second.is_interesting_with_perf(
+ state,
+ manager,
+ input,
+ observers,
+ &exit_kind,
+ feedback_stats,
+ feedback_index + 1,
+ )
+ }
+}
+
+/// Combine two feedbacks with an eager AND operation,
+/// will call all feedbacks functions even if not necessery to conclude the result
+pub type EagerAndFeedback = CombinedFeedback;
+
+/// Combine two feedbacks with an fast AND operation,
+/// might skip calling feedbacks functions if not necessery to conclude the result
+pub type FastAndFeedback = CombinedFeedback;
+
+/// Combine two feedbacks with an eager OR operation,
+/// will call all feedbacks functions even if not necessery to conclude the result
+pub type EagerOrFeedback = CombinedFeedback;
+
+/// Combine two feedbacks with an fast OR operation,
+/// might skip calling feedbacks functions if not necessery to conclude the result
+/// This means any feedback that is not first might be skipped, use caution when using with
+/// `TimeFeedback`
+pub type FastOrFeedback = CombinedFeedback;
+
/// Compose feedbacks with an OR operation
pub struct NotFeedback
where
@@ -438,7 +647,18 @@ macro_rules! feedback_and {
( $head:expr, $($tail:expr), +) => {
// recursive call
- $crate::feedbacks::AndFeedback::new($head , feedback_and!($($tail),+))
+ $crate::feedbacks::EagerAndFeedback::new($head , feedback_and!($($tail),+))
+ };
+}
+///
+/// Variadic macro to create a chain of (fast) AndFeedback
+#[macro_export]
+macro_rules! feedback_and_fast {
+ ( $last:expr ) => { $last };
+
+ ( $head:expr, $($tail:expr), +) => {
+ // recursive call
+ $crate::feedbacks::FastAndFeedback::new($head , feedback_and_fast!($($tail),+))
};
}
@@ -449,7 +669,17 @@ macro_rules! feedback_or {
( $head:expr, $($tail:expr), +) => {
// recursive call
- $crate::feedbacks::OrFeedback::new($head , feedback_or!($($tail),+))
+ $crate::feedbacks::EagerOrFeedback::new($head , feedback_or!($($tail),+))
+ };
+}
+
+#[macro_export]
+macro_rules! feedback_or_fast {
+ ( $last:expr ) => { $last };
+
+ ( $head:expr, $($tail:expr), +) => {
+ // recursive call
+ $crate::feedbacks::FastOrFeedback::new($head , feedback_or_fast!($($tail),+))
};
}