combined executor

This commit is contained in:
Andrea Fioraldi 2021-05-16 22:59:22 +02:00 committed by Omree
parent a3a2b47b2a
commit f81a52e14d
4 changed files with 167 additions and 23 deletions

View File

@ -1,22 +1,43 @@
//! A `CombinedExecutor` wraps a primary executor and a secondary one
use core::marker::PhantomData;
use crate::{
executors::{Executor, ExitKind, HasExecHooksTuple, HasObservers, HasObserversHooks},
executors::{
Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks,
},
inputs::Input,
observers::ObserversTuple,
Error,
};
/// A [`CombinedExecutor`] wraps a primary executor, forwarding its methods, and a secondary one
pub struct CombinedExecutor<A, B> {
pub struct CombinedExecutor<A, B, I>
where
A: Executor<I>,
B: Executor<I>,
I: Input,
{
primary: A,
secondary: B,
exec_tmout: Duration,
phantom: PhantomData<I>,
}
impl<A, B> CombinedExecutor<A, B> {
impl<A, B, I> CombinedExecutor<A, B, I>
where
A: Executor<I>,
B: Executor<I>,
I: Input,
{
/// Create a new `CombinedExecutor`, wrapping the given `executor`s.
pub fn new<EM, I, S, Z>(primary: A, secondary: B) -> Self {
Self { primary, secondary }
pub fn new(primary: A, secondary: B) -> Self {
Self {
primary,
secondary,
phantom: PhantomData,
}
}
/// Retrieve the primary `Executor` that is wrapped by this `CombinedExecutor`.
@ -30,26 +51,22 @@ impl<A, B> CombinedExecutor<A, B> {
}
}
impl<A, B, EM, I, S, Z> Executor<EM, I, S, Z> for CombinedExecutor<A, B>
impl<A, B, I> Executor<I> for CombinedExecutor<A, B, I>
where
A: Executor<EM, I, S, Z>,
B: Executor<EM, I, S, Z>,
A: Executor<I>,
B: Executor<I>,
I: Input,
{
fn run_target(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<ExitKind, Error> {
self.primary.run_target(fuzzer, state, mgr, input)
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
self.primary.run_target(input)
}
}
impl<A, B, OT> HasObservers<OT> for CombinedExecutor<A, B>
impl<A, B, I, OT> HasObservers<OT> for CombinedExecutor<A, B, I>
where
A: HasObservers<OT>,
A: Executor<I> + HasObservers<OT>,
B: Executor<I>,
I: Input,
OT: ObserversTuple,
{
#[inline]
@ -63,10 +80,40 @@ where
}
}
impl<A, B, EM, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z> for CombinedExecutor<A, B>
impl<A, B, EM, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z> for TimeoutExecutor<A, B, I>
where
A: HasObservers<OT>,
A: Executor<I> + HasObservers<OT>,
B: Executor<I>,
I: Input,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
{
}
impl<A, B, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for TimeoutExecutor<A, B, I>
where
A: Executor<I> + HasObservers<OT>,
B: Executor<I>,
I: Input,
{
#[inline]
fn pre_exec(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
self.primary.pre_exec(fuzzer, state, mgr, input)
}
#[inline]
fn post_exec(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
self.primary.post_exec(fuzzer, state, mgr, input)
}
}

View File

@ -4,6 +4,8 @@ pub mod inprocess;
pub use inprocess::InProcessExecutor;
pub mod timeout;
pub use timeout::TimeoutExecutor;
pub mod combined;
pub use combined::CombinedExecutor;
#[cfg(all(feature = "std", unix))]
pub mod forkserver;

View File

@ -0,0 +1,96 @@
use alloc::{
string::{String, ToString},
};
use core::marker::PhantomData;
use num::Integer;
use serde::{Deserialize, Serialize};
use crate::{
bolts::tuples::Named,
executors::ExitKind,
feedbacks::{Feedback, FeedbackState, FeedbackStatesTuple},
inputs::Input,
observers::{CmpObserver, ObserversTuple},
state::{HasFeedbackStates, HasMetadata},
utils::AsSlice,
Error,
};
/// A state metadata holding a list of values logged from comparisons
#[derive(Serialize, Deserialize)]
pub struct CmpValuesMetadata {
/// A `list` of values.
pub list: Vec<(u64, u64)>,
}
crate::impl_serdeany!(CmpValuesMetadata);
impl AsSlice<(u64, u64)> for CmpValuesMetadata {
/// Convert to a slice
#[must_use]
fn as_slice(&self) -> &[(u64, u64)] {
self.list.as_slice()
}
}
impl CmpValuesMetadata {
/// Creates a new [`struct@CmpValuesMetadata`]
#[must_use]
pub fn new(list: Vec<(u64, u64)>) -> Self {
Self { list }
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CmpFeedback<T> {
name: String,
phantom: PhantomData<T>
}
impl<I, S, T> Feedback<I, S> for CmpFeedback<T>
where
I: Input,
{
fn is_interesting<OT>(
&mut self,
_state: &mut S,
_input: &I,
observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
OT: ObserversTuple,
{
// TODO Replace with match_name_type when stable
let observer = observers.match_name::<CmpObserver<T>>(self.name()).unwrap();
// TODO
Ok(false)
}
}
impl Named for CmpFeedback {
#[inline]
fn name(&self) -> &str {
self.name.as_str()
}
}
impl CmpFeedback {
/// Creates a new [`CmpFeedback`]
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
name: name.to_string(),
phantom: PhantomData
}
}
/// Creates a new [`CmpFeedback`]
#[must_use]
pub fn new_with_observer(observer: &CmpObserver<T>) -> Self {
Self {
name: observer.name().to_string(),
phantom: PhantomData
}
}
}

View File

@ -6,6 +6,7 @@ use alloc::{
};
use core::slice::from_raw_parts_mut;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use serde::{Deserialize, Serialize};
use crate::{
@ -18,7 +19,7 @@ use crate::{
Error,
};
/// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information
/// A [`CmpObserver`] observes the traced comparisons during the current execution
pub trait CmpObserver<T>: Observer {
/// Get the number of usable cmps (all by default)
fn usable_count(&self) -> usize;
@ -28,8 +29,6 @@ pub trait CmpObserver<T>: Observer {
fn executions_for(idx: usize) -> usize;
fn kind_for(idx: usize) -> CmpKind;
fn bytes_for(idx: usize) -> usize;
fn values_of(idx: usize, execution: usize) -> (T, T);