commit
6d844e1fa3
@ -31,6 +31,7 @@ default = ["std"]
|
|||||||
std = []
|
std = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
tuple_list = "0.1.2"
|
||||||
hashbrown = { version = "0.9", features = ["serde"] } # A faster hashmap, nostd compatible
|
hashbrown = { version = "0.9", features = ["serde"] } # A faster hashmap, nostd compatible
|
||||||
libc = "0.2" # For (*nix) libc
|
libc = "0.2" # For (*nix) libc
|
||||||
num = "*"
|
num = "*"
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
//! The engine is the core piece of every good fuzzer
|
//! The engine is the core piece of every good fuzzer
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use crate::corpus::{Corpus, Testcase};
|
use crate::corpus::{Corpus, Testcase};
|
||||||
use crate::events::{Event, EventManager};
|
use crate::events::{Event, EventManager};
|
||||||
use crate::executors::Executor;
|
use crate::executors::{Executor, HasObservers};
|
||||||
use crate::feedbacks::Feedback;
|
use crate::feedbacks::FeedbacksTuple;
|
||||||
use crate::generators::Generator;
|
use crate::generators::Generator;
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
use crate::stages::Stage;
|
use crate::observers::ObserversTuple;
|
||||||
|
use crate::stages::StagesTuple;
|
||||||
use crate::utils::{current_milliseconds, Rand};
|
use crate::utils::{current_milliseconds, Rand};
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
@ -22,10 +22,11 @@ pub trait StateMetadata: Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The state a fuzz run.
|
/// The state a fuzz run.
|
||||||
pub struct State<I, R>
|
pub struct State<I, R, FT>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
{
|
{
|
||||||
/// How many times the executor ran the harness/target
|
/// How many times the executor ran the harness/target
|
||||||
executions: usize,
|
executions: usize,
|
||||||
@ -34,14 +35,15 @@ where
|
|||||||
/// Metadata stored for this state by one of the components
|
/// Metadata stored for this state by one of the components
|
||||||
metadatas: HashMap<&'static str, Box<dyn StateMetadata>>,
|
metadatas: HashMap<&'static str, Box<dyn StateMetadata>>,
|
||||||
// additional_corpuses: HashMap<&'static str, Box<dyn Corpus>>,
|
// additional_corpuses: HashMap<&'static str, Box<dyn Corpus>>,
|
||||||
feedbacks: Vec<Box<dyn Feedback<I>>>,
|
feedbacks: FT,
|
||||||
phantom: PhantomData<R>,
|
phantom: PhantomData<(I, R)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, R> State<I, R>
|
impl<I, R, FT> State<I, R, FT>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
{
|
{
|
||||||
/// Get executions
|
/// Get executions
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -98,39 +100,31 @@ where
|
|||||||
|
|
||||||
/// Returns vector of feebacks
|
/// Returns vector of feebacks
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn feedbacks(&self) -> &[Box<dyn Feedback<I>>] {
|
pub fn feedbacks(&self) -> &FT {
|
||||||
&self.feedbacks
|
&self.feedbacks
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns vector of feebacks (mutable)
|
/// Returns vector of feebacks (mutable)
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn feedbacks_mut(&mut self) -> &mut Vec<Box<dyn Feedback<I>>> {
|
pub fn feedbacks_mut(&mut self) -> &mut FT {
|
||||||
&mut self.feedbacks
|
&mut self.feedbacks
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a feedback
|
// TODO move some of these, like evaluate_input, to Engine
|
||||||
#[inline]
|
|
||||||
pub fn add_feedback(&mut self, feedback: Box<dyn Feedback<I>>) {
|
|
||||||
self.feedbacks_mut().push(feedback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO move some of these, like evaluate_input, to FuzzingEngine
|
|
||||||
|
|
||||||
/// Runs the input and triggers observers and feedback
|
/// Runs the input and triggers observers and feedback
|
||||||
pub fn evaluate_input<E>(&mut self, input: &I, executor: &mut E) -> Result<u32, AflError>
|
pub fn evaluate_input<E, OT>(&mut self, input: &I, executor: &mut E) -> Result<u32, AflError>
|
||||||
where
|
where
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
executor.reset_observers()?;
|
executor.reset_observers()?;
|
||||||
executor.run_target(&input)?;
|
executor.run_target(&input)?;
|
||||||
self.set_executions(self.executions() + 1);
|
self.set_executions(self.executions() + 1);
|
||||||
executor.post_exec_observers()?;
|
executor.post_exec_observers()?;
|
||||||
|
|
||||||
let mut fitness = 0;
|
|
||||||
let observers = executor.observers();
|
let observers = executor.observers();
|
||||||
for feedback in self.feedbacks_mut() {
|
let fitness = self.feedbacks_mut().is_interesting_all(&input, observers)?;
|
||||||
fitness += feedback.is_interesting(&input, observers)?;
|
|
||||||
}
|
|
||||||
Ok(fitness)
|
Ok(fitness)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,10 +132,7 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn discard_input(&mut self, input: &I) -> Result<(), AflError> {
|
pub fn discard_input(&mut self, input: &I) -> Result<(), AflError> {
|
||||||
// TODO: This could probably be automatic in the feedback somehow?
|
// TODO: This could probably be automatic in the feedback somehow?
|
||||||
for feedback in self.feedbacks_mut() {
|
self.feedbacks_mut().discard_metadata_all(&input)
|
||||||
feedback.discard_metadata(input)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new testcase, appending the metadata from each feedback
|
/// Creates a new testcase, appending the metadata from each feedback
|
||||||
@ -149,10 +140,7 @@ where
|
|||||||
pub fn input_to_testcase(&mut self, input: I, fitness: u32) -> Result<Testcase<I>, AflError> {
|
pub fn input_to_testcase(&mut self, input: I, fitness: u32) -> Result<Testcase<I>, AflError> {
|
||||||
let mut testcase = Testcase::new(input);
|
let mut testcase = Testcase::new(input);
|
||||||
testcase.set_fitness(fitness);
|
testcase.set_fitness(fitness);
|
||||||
for feedback in self.feedbacks_mut() {
|
self.feedbacks_mut().append_metadata_all(&mut testcase)?;
|
||||||
feedback.append_metadata(&mut testcase)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(testcase)
|
Ok(testcase)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,20 +179,21 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_initial_inputs<G, C, E, EM>(
|
pub fn generate_initial_inputs<G, C, E, OT, EM>(
|
||||||
&mut self,
|
&mut self,
|
||||||
rand: &mut R,
|
rand: &mut R,
|
||||||
corpus: &mut C,
|
corpus: &mut C,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
engine: &mut Engine<E, I>,
|
engine: &mut Engine<E, OT, I>,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
num: usize,
|
num: usize,
|
||||||
) -> Result<(), AflError>
|
) -> Result<(), AflError>
|
||||||
where
|
where
|
||||||
G: Generator<I, R>,
|
G: Generator<I, R>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
EM: EventManager<C, E, I, R>,
|
OT: ObserversTuple,
|
||||||
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
{
|
{
|
||||||
let mut added = 0;
|
let mut added = 0;
|
||||||
for _ in 0..num {
|
for _ in 0..num {
|
||||||
@ -226,29 +215,31 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new(feedbacks: FT) -> Self {
|
||||||
Self {
|
Self {
|
||||||
executions: 0,
|
executions: 0,
|
||||||
start_time: current_milliseconds(),
|
start_time: current_milliseconds(),
|
||||||
metadatas: HashMap::default(),
|
metadatas: HashMap::default(),
|
||||||
feedbacks: vec![],
|
feedbacks: feedbacks,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Engine<E, I>
|
pub struct Engine<E, OT, I>
|
||||||
where
|
where
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
executor: E,
|
executor: E,
|
||||||
phantom: PhantomData<I>,
|
phantom: PhantomData<(OT, I)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, I> Engine<E, I>
|
impl<E, OT, I> Engine<E, OT, I>
|
||||||
where
|
where
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// Return the executor
|
/// Return the executor
|
||||||
@ -271,35 +262,33 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Fuzzer<EM, E, C, I, R>
|
pub trait Fuzzer<ST, EM, E, OT, FT, C, I, R>
|
||||||
where
|
where
|
||||||
EM: EventManager<C, E, I, R>,
|
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
|
||||||
E: Executor<I>,
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn stages(&self) -> &[Box<dyn Stage<EM, E, C, I, R>>];
|
fn stages(&self) -> &ST;
|
||||||
|
|
||||||
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<EM, E, C, I, R>>>;
|
fn stages_mut(&mut self) -> &mut ST;
|
||||||
|
|
||||||
fn add_stage(&mut self, stage: Box<dyn Stage<EM, E, C, I, R>>) {
|
|
||||||
self.stages_mut().push(stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fuzz_one(
|
fn fuzz_one(
|
||||||
&mut self,
|
&mut self,
|
||||||
rand: &mut R,
|
rand: &mut R,
|
||||||
state: &mut State<I, R>,
|
state: &mut State<I, R, FT>,
|
||||||
corpus: &mut C,
|
corpus: &mut C,
|
||||||
engine: &mut Engine<E, I>,
|
engine: &mut Engine<E, OT, I>,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<usize, AflError> {
|
) -> Result<usize, AflError> {
|
||||||
let (_, idx) = corpus.next(rand)?;
|
let (_, idx) = corpus.next(rand)?;
|
||||||
|
|
||||||
for stage in self.stages_mut() {
|
self.stages_mut()
|
||||||
stage.perform(rand, state, corpus, engine, manager, idx)?;
|
.perform_all(rand, state, corpus, engine, manager, idx)?;
|
||||||
}
|
|
||||||
|
|
||||||
manager.process(state, corpus)?;
|
manager.process(state, corpus)?;
|
||||||
Ok(idx)
|
Ok(idx)
|
||||||
@ -308,9 +297,9 @@ where
|
|||||||
fn fuzz_loop(
|
fn fuzz_loop(
|
||||||
&mut self,
|
&mut self,
|
||||||
rand: &mut R,
|
rand: &mut R,
|
||||||
state: &mut State<I, R>,
|
state: &mut State<I, R, FT>,
|
||||||
corpus: &mut C,
|
corpus: &mut C,
|
||||||
engine: &mut Engine<E, I>,
|
engine: &mut Engine<E, OT, I>,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
) -> Result<(), AflError> {
|
) -> Result<(), AflError> {
|
||||||
let mut last = current_milliseconds();
|
let mut last = current_milliseconds();
|
||||||
@ -328,44 +317,58 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StdFuzzer<EM, E, C, I, R>
|
pub struct StdFuzzer<ST, EM, E, OT, FT, C, I, R>
|
||||||
where
|
where
|
||||||
EM: EventManager<C, E, I, R>,
|
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
|
||||||
E: Executor<I>,
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
stages: Vec<Box<dyn Stage<EM, E, C, I, R>>>,
|
stages: ST,
|
||||||
|
phantom: PhantomData<(EM, E, OT, FT, C, I, R)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EM, E, C, I, R> Fuzzer<EM, E, C, I, R> for StdFuzzer<EM, E, C, I, R>
|
impl<ST, EM, E, OT, FT, C, I, R> Fuzzer<ST, EM, E, OT, FT, C, I, R>
|
||||||
|
for StdFuzzer<ST, EM, E, OT, FT, C, I, R>
|
||||||
where
|
where
|
||||||
EM: EventManager<C, E, I, R>,
|
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
|
||||||
E: Executor<I>,
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn stages(&self) -> &[Box<dyn Stage<EM, E, C, I, R>>] {
|
fn stages(&self) -> &ST {
|
||||||
&self.stages
|
&self.stages
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<EM, E, C, I, R>>> {
|
fn stages_mut(&mut self) -> &mut ST {
|
||||||
&mut self.stages
|
&mut self.stages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EM, E, C, I, R> StdFuzzer<EM, E, C, I, R>
|
impl<ST, EM, E, OT, FT, C, I, R> StdFuzzer<ST, EM, E, OT, FT, C, I, R>
|
||||||
where
|
where
|
||||||
EM: EventManager<C, E, I, R>,
|
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
|
||||||
E: Executor<I>,
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
pub fn new() -> Self {
|
pub fn new(stages: ST) -> Self {
|
||||||
Self { stages: vec![] }
|
Self {
|
||||||
|
stages: stages,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,8 +377,6 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::io::stderr;
|
use std::io::stderr;
|
||||||
|
|
||||||
@ -388,6 +389,7 @@ mod tests {
|
|||||||
use crate::inputs::bytes::BytesInput;
|
use crate::inputs::bytes::BytesInput;
|
||||||
use crate::mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator};
|
use crate::mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator};
|
||||||
use crate::stages::mutational::StdMutationalStage;
|
use crate::stages::mutational::StdMutationalStage;
|
||||||
|
use crate::tuples::tuple_list;
|
||||||
use crate::utils::StdRand;
|
use crate::utils::StdRand;
|
||||||
|
|
||||||
fn harness<I>(_executor: &dyn Executor<I>, _buf: &[u8]) -> ExitKind {
|
fn harness<I>(_executor: &dyn Executor<I>, _buf: &[u8]) -> ExitKind {
|
||||||
@ -402,18 +404,15 @@ mod tests {
|
|||||||
let testcase = Testcase::new(vec![0; 4]).into();
|
let testcase = Testcase::new(vec![0; 4]).into();
|
||||||
corpus.add(testcase);
|
corpus.add(testcase);
|
||||||
|
|
||||||
let executor = InMemoryExecutor::<BytesInput>::new(harness);
|
let executor = InMemoryExecutor::<BytesInput, _>::new(harness, tuple_list!());
|
||||||
let mut state = State::new();
|
let mut state = State::new(tuple_list!());
|
||||||
|
|
||||||
let mut events_manager = LoggerEventManager::new(stderr());
|
let mut events_manager = LoggerEventManager::new(stderr());
|
||||||
let mut engine = Engine::new(executor);
|
let mut engine = Engine::new(executor);
|
||||||
let mut mutator = StdScheduledMutator::new();
|
let mut mutator = StdScheduledMutator::new();
|
||||||
mutator.add_mutation(mutation_bitflip);
|
mutator.add_mutation(mutation_bitflip);
|
||||||
let stage = StdMutationalStage::new(mutator);
|
let stage = StdMutationalStage::new(mutator);
|
||||||
let mut fuzzer = StdFuzzer::new();
|
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
|
||||||
fuzzer.add_stage(Box::new(stage));
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
for i in 0..1000 {
|
for i in 0..1000 {
|
||||||
fuzzer
|
fuzzer
|
||||||
|
@ -14,13 +14,15 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
use crate::corpus::Corpus;
|
||||||
use crate::engines::State;
|
use crate::engines::State;
|
||||||
use crate::executors::Executor;
|
use crate::executors::Executor;
|
||||||
|
use crate::feedbacks::FeedbacksTuple;
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
use crate::serde_anymap::{Ptr, PtrMut};
|
use crate::observers::ObserversTuple;
|
||||||
|
use crate::serde_anymap::{Ptr, PtrMut, SerdeAny};
|
||||||
use crate::utils::Rand;
|
use crate::utils::Rand;
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
use crate::{corpus::Corpus, serde_anymap::SerdeAny};
|
|
||||||
|
|
||||||
/// Indicate if an event worked or not
|
/// Indicate if an event worked or not
|
||||||
pub enum BrokerEventResult {
|
pub enum BrokerEventResult {
|
||||||
@ -33,7 +35,7 @@ pub enum BrokerEventResult {
|
|||||||
pub trait ShowStats {}
|
pub trait ShowStats {}
|
||||||
|
|
||||||
/// A custom event, for own messages, with own handler.
|
/// A custom event, for own messages, with own handler.
|
||||||
pub trait CustomEvent<I>: SerdeAny + Serialize
|
pub trait CustomEvent<I, OT>: SerdeAny + Serialize
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
@ -48,9 +50,10 @@ where
|
|||||||
/// Events sent around in the library
|
/// Events sent around in the library
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(bound = "I: serde::de::DeserializeOwned")]
|
#[serde(bound = "I: serde::de::DeserializeOwned")]
|
||||||
pub enum Event<'a, I>
|
pub enum Event<'a, I, OT>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
LoadInitial {
|
LoadInitial {
|
||||||
sender_id: u64,
|
sender_id: u64,
|
||||||
@ -59,7 +62,7 @@ where
|
|||||||
NewTestcase {
|
NewTestcase {
|
||||||
sender_id: u64,
|
sender_id: u64,
|
||||||
input: Ptr<'a, I>,
|
input: Ptr<'a, I>,
|
||||||
observers: PtrMut<'a, crate::observers::observer_serde::NamedSerdeAnyMap>,
|
observers: PtrMut<'a, OT>,
|
||||||
corpus_count: usize,
|
corpus_count: usize,
|
||||||
},
|
},
|
||||||
UpdateStats {
|
UpdateStats {
|
||||||
@ -90,14 +93,14 @@ where
|
|||||||
Custom {
|
Custom {
|
||||||
sender_id: u64,
|
sender_id: u64,
|
||||||
// TODO: Allow custom events
|
// TODO: Allow custom events
|
||||||
// custom_event: Box<dyn CustomEvent<I>>,
|
// custom_event: Box<dyn CustomEvent<I, OT>>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I> Event<'a, I>
|
impl<'a, I, OT> Event<'a, I, OT>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
//CE: CustomEvent<I>,
|
OT: ObserversTuple, //CE: CustomEvent<I, OT>,
|
||||||
{
|
{
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
@ -159,29 +162,31 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait EventManager<C, E, I, R>
|
pub trait EventManager<C, E, OT, FT, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Fire an Event
|
/// Fire an Event
|
||||||
fn fire<'a>(&mut self, event: Event<'a, I>) -> Result<(), AflError>;
|
fn fire<'a>(&mut self, event: Event<'a, I, OT>) -> Result<(), AflError>;
|
||||||
|
|
||||||
/// Lookup for incoming events and process them.
|
/// Lookup for incoming events and process them.
|
||||||
/// Return the number of processes events or an error
|
/// Return the number of processes events or an error
|
||||||
fn process(&mut self, state: &mut State<I, R>, corpus: &mut C) -> Result<usize, AflError>;
|
fn process(&mut self, state: &mut State<I, R, FT>, corpus: &mut C) -> Result<usize, AflError>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn on_recv(&self, _state: &mut State<I, R>, _corpus: &mut C) -> Result<(), AflError> {
|
fn on_recv(&self, _state: &mut State<I, R, FT>, _corpus: &mut C) -> Result<(), AflError> {
|
||||||
// TODO: Better way to move out of testcase, or get ref
|
// TODO: Better way to move out of testcase, or get ref
|
||||||
//Ok(corpus.add(self.testcase.take().unwrap()))
|
//Ok(corpus.add(self.testcase.take().unwrap()))
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO the broker has a state? do we need to pass state and corpus?
|
// TODO the broker has a state? do we need to pass state and corpus?
|
||||||
fn handle_in_broker(&mut self, event: &Event<I>) -> Result<BrokerEventResult, AflError> {
|
fn handle_in_broker(&mut self, event: &Event<I, OT>) -> Result<BrokerEventResult, AflError> {
|
||||||
match event {
|
match event {
|
||||||
Event::LoadInitial {
|
Event::LoadInitial {
|
||||||
sender_id: _,
|
sender_id: _,
|
||||||
@ -238,8 +243,8 @@ where
|
|||||||
|
|
||||||
fn handle_in_client(
|
fn handle_in_client(
|
||||||
&mut self,
|
&mut self,
|
||||||
event: Event<I>,
|
event: Event<I, OT>,
|
||||||
_state: &mut State<I, R>,
|
_state: &mut State<I, R, FT>,
|
||||||
_corpus: &mut C,
|
_corpus: &mut C,
|
||||||
) -> Result<(), AflError> {
|
) -> Result<(), AflError> {
|
||||||
match event {
|
match event {
|
||||||
@ -263,7 +268,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*TODO
|
/*TODO
|
||||||
fn on_recv(&self, state: &mut State<I, R>, _corpus: &mut C) -> Result<(), AflError> {
|
fn on_recv(&self, state: &mut State<I, R, FT>, _corpus: &mut C) -> Result<(), AflError> {
|
||||||
println!(
|
println!(
|
||||||
"#{}\t exec/s: {}",
|
"#{}\t exec/s: {}",
|
||||||
state.executions(),
|
state.executions(),
|
||||||
@ -275,10 +280,16 @@ where
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub struct LoggerEventManager<C, E, I, R, W>
|
pub struct LoggerEventManager<C, E, OT, FT, I, R, W>
|
||||||
where
|
where
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
E: Executor<I>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
W: Write,
|
W: Write,
|
||||||
//CE: CustomEvent<I>,
|
//CE: CustomEvent<I, OT>,
|
||||||
{
|
{
|
||||||
writer: W,
|
writer: W,
|
||||||
count: usize,
|
count: usize,
|
||||||
@ -288,21 +299,24 @@ where
|
|||||||
execs_over_sec: u64,
|
execs_over_sec: u64,
|
||||||
corpus_count: usize,
|
corpus_count: usize,
|
||||||
|
|
||||||
phantom: PhantomData<(C, E, I, R)>,
|
phantom: PhantomData<(C, E, OT, FT, I, R)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl<C, E, I, R, W> EventManager<C, E, I, R> for LoggerEventManager<C, E, I, R, W>
|
impl<C, E, OT, FT, I, R, W> EventManager<C, E, OT, FT, I, R>
|
||||||
|
for LoggerEventManager<C, E, OT, FT, I, R, W>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
W: Write,
|
W: Write,
|
||||||
//CE: CustomEvent<I>,
|
//CE: CustomEvent<I, OT>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fire<'a>(&mut self, event: Event<'a, I>) -> Result<(), AflError> {
|
fn fire<'a>(&mut self, event: Event<'a, I, OT>) -> Result<(), AflError> {
|
||||||
match self.handle_in_broker(&event)? {
|
match self.handle_in_broker(&event)? {
|
||||||
BrokerEventResult::Forward => (), //self.handle_in_client(event, state, corpus)?,
|
BrokerEventResult::Forward => (), //self.handle_in_client(event, state, corpus)?,
|
||||||
// Ignore broker-only events
|
// Ignore broker-only events
|
||||||
@ -311,13 +325,17 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process(&mut self, _state: &mut State<I, R>, _corpus: &mut C) -> Result<usize, AflError> {
|
fn process(
|
||||||
|
&mut self,
|
||||||
|
_state: &mut State<I, R, FT>,
|
||||||
|
_corpus: &mut C,
|
||||||
|
) -> Result<usize, AflError> {
|
||||||
let c = self.count;
|
let c = self.count;
|
||||||
self.count = 0;
|
self.count = 0;
|
||||||
Ok(c)
|
Ok(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_in_broker(&mut self, event: &Event<I>) -> Result<BrokerEventResult, AflError> {
|
fn handle_in_broker(&mut self, event: &Event<I, OT>) -> Result<BrokerEventResult, AflError> {
|
||||||
match event {
|
match event {
|
||||||
Event::NewTestcase {
|
Event::NewTestcase {
|
||||||
sender_id: _,
|
sender_id: _,
|
||||||
@ -377,11 +395,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl<C, E, I, R, W> LoggerEventManager<C, E, I, R, W>
|
impl<C, E, OT, FT, I, R, W> LoggerEventManager<C, E, OT, FT, I, R, W>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
W: Write,
|
W: Write,
|
||||||
//TODO CE: CustomEvent,
|
//TODO CE: CustomEvent,
|
||||||
@ -400,16 +420,18 @@ where
|
|||||||
|
|
||||||
/// Eventmanager for multi-processed application
|
/// Eventmanager for multi-processed application
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub struct LlmpBrokerEventManager<C, E, I, R>
|
pub struct LlmpBrokerEventManager<C, E, OT, FT, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
//CE: CustomEvent<I>,
|
//CE: CustomEvent<I, OT>,
|
||||||
{
|
{
|
||||||
llmp_broker: llmp::LlmpBroker,
|
llmp_broker: llmp::LlmpBroker,
|
||||||
phantom: PhantomData<(C, E, I, R)>,
|
phantom: PhantomData<(C, E, OT, FT, I, R)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -424,35 +446,44 @@ const _LLMP_TAG_EVENT_TO_BOTH: llmp::Tag = 0x2B0741;
|
|||||||
|
|
||||||
/// Eventmanager for multi-processed application
|
/// Eventmanager for multi-processed application
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub struct LlmpClientEventManager<C, E, I, R>
|
pub struct LlmpClientEventManager<C, E, OT, FT, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
//CE: CustomEvent<I>,
|
//CE: CustomEvent<I, OT>,
|
||||||
{
|
{
|
||||||
_llmp_client: llmp::LlmpClient,
|
_llmp_client: llmp::LlmpClient,
|
||||||
phantom: PhantomData<(C, E, I, R)>,
|
phantom: PhantomData<(C, E, OT, FT, I, R)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl<C, E, I, R> EventManager<C, E, I, R> for LlmpBrokerEventManager<C, E, I, R>
|
impl<C, E, OT, FT, I, R> EventManager<C, E, OT, FT, I, R>
|
||||||
|
for LlmpBrokerEventManager<C, E, OT, FT, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Fire an Event
|
/// Fire an Event
|
||||||
fn fire<'a>(&mut self, event: Event<'a, I>) -> Result<(), AflError> {
|
fn fire<'a>(&mut self, event: Event<'a, I, OT>) -> Result<(), AflError> {
|
||||||
let serialized = postcard::to_allocvec(&event)?;
|
let serialized = postcard::to_allocvec(&event)?;
|
||||||
self.llmp_broker
|
self.llmp_broker
|
||||||
.send_buf(LLMP_TAG_EVENT_TO_CLIENT, &serialized)?;
|
.send_buf(LLMP_TAG_EVENT_TO_CLIENT, &serialized)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process(&mut self, _state: &mut State<I, R>, _corpus: &mut C) -> Result<usize, AflError> {
|
fn process(
|
||||||
|
&mut self,
|
||||||
|
_state: &mut State<I, R, FT>,
|
||||||
|
_corpus: &mut C,
|
||||||
|
) -> Result<usize, AflError> {
|
||||||
// TODO: iterators
|
// TODO: iterators
|
||||||
/*
|
/*
|
||||||
let mut handled = vec![];
|
let mut handled = vec![];
|
||||||
@ -481,13 +512,13 @@ where
|
|||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_recv(&self, _state: &mut State<I, R>, _corpus: &mut C) -> Result<(), AflError> {
|
fn on_recv(&self, _state: &mut State<I, R, FT>, _corpus: &mut C) -> Result<(), AflError> {
|
||||||
// TODO: Better way to move out of testcase, or get ref
|
// TODO: Better way to move out of testcase, or get ref
|
||||||
//Ok(corpus.add(self.testcase.take().unwrap()))
|
//Ok(corpus.add(self.testcase.take().unwrap()))
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_in_broker(&mut self, event: &Event<I>) -> Result<BrokerEventResult, AflError> {
|
fn handle_in_broker(&mut self, event: &Event<I, OT>) -> Result<BrokerEventResult, AflError> {
|
||||||
match event {
|
match event {
|
||||||
Event::LoadInitial {
|
Event::LoadInitial {
|
||||||
sender_id: _,
|
sender_id: _,
|
||||||
@ -542,8 +573,8 @@ where
|
|||||||
|
|
||||||
fn handle_in_client(
|
fn handle_in_client(
|
||||||
&mut self,
|
&mut self,
|
||||||
event: Event<I>,
|
event: Event<I, OT>,
|
||||||
/*client: &dyn EventManager<C, E, I, R>,*/ _state: &mut State<I, R>,
|
_state: &mut State<I, R, FT>,
|
||||||
_corpus: &mut C,
|
_corpus: &mut C,
|
||||||
) -> Result<(), AflError> {
|
) -> Result<(), AflError> {
|
||||||
match event {
|
match event {
|
||||||
@ -572,17 +603,16 @@ mod tests {
|
|||||||
|
|
||||||
use crate::events::Event;
|
use crate::events::Event;
|
||||||
use crate::inputs::bytes::BytesInput;
|
use crate::inputs::bytes::BytesInput;
|
||||||
use crate::observers::observer_serde::NamedSerdeAnyMap;
|
use crate::observers::{Observer, ObserversTuple, StdMapObserver};
|
||||||
use crate::observers::{Observer, StdMapObserver};
|
|
||||||
use crate::serde_anymap::{Ptr, PtrMut};
|
use crate::serde_anymap::{Ptr, PtrMut};
|
||||||
|
use crate::tuples::{tuple_list, tuple_list_type, MatchNameAndType, Named};
|
||||||
|
|
||||||
static mut MAP: [u32; 4] = [0; 4];
|
static mut MAP: [u32; 4] = [0; 4];
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_event_serde() {
|
fn test_event_serde() {
|
||||||
let mut map = NamedSerdeAnyMap::new();
|
|
||||||
let obv = StdMapObserver::new("test", unsafe { &mut MAP });
|
let obv = StdMapObserver::new("test", unsafe { &mut MAP });
|
||||||
map.insert(Box::new(obv), &"key".to_string());
|
let mut map = tuple_list!(obv);
|
||||||
|
|
||||||
let i = BytesInput::new(vec![0]);
|
let i = BytesInput::new(vec![0]);
|
||||||
let e = Event::NewTestcase {
|
let e = Event::NewTestcase {
|
||||||
@ -594,19 +624,20 @@ mod tests {
|
|||||||
|
|
||||||
let j = serde_json::to_string(&e).unwrap();
|
let j = serde_json::to_string(&e).unwrap();
|
||||||
|
|
||||||
let d: Event<BytesInput> = serde_json::from_str(&j).unwrap();
|
let d: Event<BytesInput, tuple_list_type!(StdMapObserver<u32>)> =
|
||||||
|
serde_json::from_str(&j).unwrap();
|
||||||
match d {
|
match d {
|
||||||
Event::NewTestcase {
|
Event::NewTestcase {
|
||||||
sender_id: _,
|
sender_id: _,
|
||||||
input: _,
|
input: _,
|
||||||
observers: obs,
|
observers,
|
||||||
corpus_count: _,
|
corpus_count: _,
|
||||||
} => {
|
} => {
|
||||||
let o = obs
|
let o = observers
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.get::<StdMapObserver<u32>>(&"key".to_string())
|
.match_name_type::<StdMapObserver<u32>>("test")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!("test".to_string(), *o.name());
|
assert_eq!("test", o.name());
|
||||||
}
|
}
|
||||||
_ => panic!("mistmatch".to_string()),
|
_ => panic!("mistmatch".to_string()),
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use core::ffi::c_void;
|
use core::ffi::c_void;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
use crate::executors::{Executor, ExitKind};
|
use crate::executors::{Executor, ExitKind, HasObservers};
|
||||||
use crate::inputs::{HasTargetBytes, Input};
|
use crate::inputs::{HasTargetBytes, Input};
|
||||||
use crate::observers::observer_serde::NamedSerdeAnyMap;
|
use crate::observers::ObserversTuple;
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
/// The (unsafe) pointer to the current inmem executor, for the current run.
|
/// The (unsafe) pointer to the current inmem executor, for the current run.
|
||||||
@ -14,23 +14,25 @@ static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null();
|
|||||||
type HarnessFunction<I> = fn(&dyn Executor<I>, &[u8]) -> ExitKind;
|
type HarnessFunction<I> = fn(&dyn Executor<I>, &[u8]) -> ExitKind;
|
||||||
|
|
||||||
/// The inmem executor simply calls a target function, then returns afterwards.
|
/// The inmem executor simply calls a target function, then returns afterwards.
|
||||||
pub struct InMemoryExecutor<I>
|
pub struct InMemoryExecutor<I, OT>
|
||||||
where
|
where
|
||||||
I: Input + HasTargetBytes,
|
I: Input + HasTargetBytes,
|
||||||
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
harness: HarnessFunction<I>,
|
harness: HarnessFunction<I>,
|
||||||
observers: NamedSerdeAnyMap,
|
observers: OT,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Executor<I> for InMemoryExecutor<I>
|
impl<I, OT> Executor<I> for InMemoryExecutor<I, OT>
|
||||||
where
|
where
|
||||||
I: Input + HasTargetBytes,
|
I: Input + HasTargetBytes,
|
||||||
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError> {
|
fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError> {
|
||||||
let bytes = input.target_bytes();
|
let bytes = input.target_bytes();
|
||||||
unsafe {
|
unsafe {
|
||||||
CURRENT_INMEMORY_EXECUTOR_PTR = self as *const InMemoryExecutor<I> as *const c_void;
|
CURRENT_INMEMORY_EXECUTOR_PTR = self as *const InMemoryExecutor<I, OT> as *const c_void;
|
||||||
}
|
}
|
||||||
let ret = (self.harness)(self, bytes.as_slice());
|
let ret = (self.harness)(self, bytes.as_slice());
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -38,30 +40,37 @@ where
|
|||||||
}
|
}
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, OT> HasObservers<OT> for InMemoryExecutor<I, OT>
|
||||||
|
where
|
||||||
|
I: Input + HasTargetBytes,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn observers(&self) -> &NamedSerdeAnyMap {
|
fn observers(&self) -> &OT {
|
||||||
&self.observers
|
&self.observers
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn observers_mut(&mut self) -> &mut NamedSerdeAnyMap {
|
fn observers_mut(&mut self) -> &mut OT {
|
||||||
&mut self.observers
|
&mut self.observers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> InMemoryExecutor<I>
|
impl<I, OT> InMemoryExecutor<I, OT>
|
||||||
where
|
where
|
||||||
I: Input + HasTargetBytes,
|
I: Input + HasTargetBytes,
|
||||||
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
pub fn new(harness_fn: HarnessFunction<I>) -> Self {
|
pub fn new(harness_fn: HarnessFunction<I>, observers: OT) -> Self {
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
unsafe {
|
unsafe {
|
||||||
os_signals::setup_crash_handlers::<I>();
|
os_signals::setup_crash_handlers::<I>();
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
harness: harness_fn,
|
harness: harness_fn,
|
||||||
observers: NamedSerdeAnyMap::new(),
|
observers: observers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,6 +178,7 @@ mod tests {
|
|||||||
use crate::executors::inmemory::InMemoryExecutor;
|
use crate::executors::inmemory::InMemoryExecutor;
|
||||||
use crate::executors::{Executor, ExitKind};
|
use crate::executors::{Executor, ExitKind};
|
||||||
use crate::inputs::{HasTargetBytes, Input, TargetBytes};
|
use crate::inputs::{HasTargetBytes, Input, TargetBytes};
|
||||||
|
use crate::tuples::{tuple_list, tuple_list_type};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -194,7 +204,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_inmem_exec() {
|
fn test_inmem_exec() {
|
||||||
let mut in_mem_executor = InMemoryExecutor::new(test_harness_fn_nop);
|
let mut in_mem_executor = InMemoryExecutor::new(test_harness_fn_nop, tuple_list!());
|
||||||
let mut input = NopInput {};
|
let mut input = NopInput {};
|
||||||
assert!(in_mem_executor.run_target(&mut input).is_ok());
|
assert!(in_mem_executor.run_target(&mut input).is_ok());
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
pub mod inmemory;
|
pub mod inmemory;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
|
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
use crate::observers::observer_serde::NamedSerdeAnyMap;
|
use crate::observers::ObserversTuple;
|
||||||
use crate::observers::Observer;
|
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
/// How an execution finished.
|
/// How an execution finished.
|
||||||
@ -15,6 +12,29 @@ pub enum ExitKind {
|
|||||||
Timeout,
|
Timeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HasObservers<OT>
|
||||||
|
where
|
||||||
|
OT: ObserversTuple,
|
||||||
|
{
|
||||||
|
/// Get the linked observers
|
||||||
|
fn observers(&self) -> &OT;
|
||||||
|
|
||||||
|
/// Get the linked observers
|
||||||
|
fn observers_mut(&mut self) -> &mut OT;
|
||||||
|
|
||||||
|
/// Reset the state of all the observes linked to this executor
|
||||||
|
#[inline]
|
||||||
|
fn reset_observers(&mut self) -> Result<(), AflError> {
|
||||||
|
self.observers_mut().reset_all()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the post exec hook for all the observes linked to this executor
|
||||||
|
#[inline]
|
||||||
|
fn post_exec_observers(&mut self) -> Result<(), AflError> {
|
||||||
|
self.observers_mut().post_exec_all()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An executor takes the given inputs, and runs the harness/target.
|
/// An executor takes the given inputs, and runs the harness/target.
|
||||||
pub trait Executor<I>
|
pub trait Executor<I>
|
||||||
where
|
where
|
||||||
@ -22,31 +42,4 @@ where
|
|||||||
{
|
{
|
||||||
/// Instruct the target about the input and run
|
/// Instruct the target about the input and run
|
||||||
fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError>;
|
fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError>;
|
||||||
|
|
||||||
/// Get the linked observers
|
|
||||||
fn observers(&self) -> &NamedSerdeAnyMap;
|
|
||||||
|
|
||||||
/// Get the linked observers
|
|
||||||
fn observers_mut(&mut self) -> &mut NamedSerdeAnyMap;
|
|
||||||
|
|
||||||
/// Add a linked observer
|
|
||||||
fn add_observer(&mut self, observer: Box<dyn Observer>) {
|
|
||||||
let name = observer.name().clone();
|
|
||||||
self.observers_mut().insert(observer, &name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reset the state of all the observes linked to this executor
|
|
||||||
#[inline]
|
|
||||||
fn reset_observers(&mut self) -> Result<(), AflError> {
|
|
||||||
self.observers_mut().for_each_mut(|_, x| Ok(x.reset()?))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run the post exec hook for all the observes linked to this executor
|
|
||||||
#[inline]
|
|
||||||
fn post_exec_observers(&mut self) -> Result<(), AflError> {
|
|
||||||
self.observers_mut()
|
|
||||||
.for_each_mut(|_, x| Ok(x.post_exec()?))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@ use alloc::vec::Vec;
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use num::Integer;
|
use num::Integer;
|
||||||
|
|
||||||
|
use crate::corpus::Testcase;
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
use crate::observers::observer_serde::NamedSerdeAnyMap;
|
use crate::observers::{MapObserver, Observer, ObserversTuple};
|
||||||
use crate::observers::MapObserver;
|
use crate::tuples::{MatchNameAndType, MatchType, Named, TupleList};
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
use crate::{corpus::Testcase, observers::Observer};
|
|
||||||
|
|
||||||
pub type MaxMapFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>;
|
pub type MaxMapFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>;
|
||||||
pub type MinMapFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;
|
pub type MinMapFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;
|
||||||
@ -19,12 +19,16 @@ pub type MinMapFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;
|
|||||||
/// Feedbacks evaluate the observers.
|
/// Feedbacks evaluate the observers.
|
||||||
/// Basically, they reduce the information provided by an observer to a value,
|
/// Basically, they reduce the information provided by an observer to a value,
|
||||||
/// indicating the "interestingness" of the last run.
|
/// indicating the "interestingness" of the last run.
|
||||||
pub trait Feedback<I>
|
pub trait Feedback<I>: Named + 'static
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55)
|
/// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55)
|
||||||
fn is_interesting(&mut self, input: &I, observers: &NamedSerdeAnyMap) -> Result<u32, AflError>;
|
fn is_interesting<OT: ObserversTuple>(
|
||||||
|
&mut self,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
) -> Result<u32, AflError>;
|
||||||
|
|
||||||
/// 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]
|
||||||
@ -37,13 +41,82 @@ where
|
|||||||
fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> {
|
fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The name of this feedback
|
pub trait FeedbacksTuple<I>: MatchType + MatchNameAndType
|
||||||
fn name(&self) -> &String;
|
where
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
fn is_interesting_all<OT: ObserversTuple>(
|
||||||
|
&mut self,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
) -> Result<u32, AflError>;
|
||||||
|
fn append_metadata_all(&mut self, testcase: &mut Testcase<I>) -> Result<(), AflError>;
|
||||||
|
fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError>;
|
||||||
|
//fn for_each(&self, f: fn(&dyn Feedback<I>));
|
||||||
|
//fn for_each_mut(&mut self, f: fn(&mut dyn Feedback<I>));
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> FeedbacksTuple<I> for ()
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
fn is_interesting_all<OT: ObserversTuple>(
|
||||||
|
&mut self,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
) -> Result<u32, AflError> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
fn append_metadata_all(&mut self, testcase: &mut Testcase<I>) -> Result<(), AflError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
//fn for_each(&self, f: fn(&dyn Feedback<I>)) {}
|
||||||
|
//fn for_each_mut(&mut self, f: fn(&mut dyn Feedback<I>)) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Head, Tail, I> FeedbacksTuple<I> for (Head, Tail)
|
||||||
|
where
|
||||||
|
Head: Feedback<I>,
|
||||||
|
Tail: FeedbacksTuple<I> + TupleList,
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
fn is_interesting_all<OT: ObserversTuple>(
|
||||||
|
&mut self,
|
||||||
|
input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
) -> Result<u32, AflError> {
|
||||||
|
Ok(self.0.is_interesting(input, observers)?
|
||||||
|
+ self.1.is_interesting_all(input, observers)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append_metadata_all(&mut self, testcase: &mut Testcase<I>) -> Result<(), AflError> {
|
||||||
|
self.0.append_metadata(testcase)?;
|
||||||
|
self.1.append_metadata_all(testcase)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError> {
|
||||||
|
self.0.discard_metadata(input)?;
|
||||||
|
self.1.discard_metadata_all(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*fn for_each(&self, f: fn(&dyn Feedback<I>)) {
|
||||||
|
f(&self.0);
|
||||||
|
self.1.for_each(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_each_mut(&mut self, f: fn(&mut dyn Feedback<I>)) {
|
||||||
|
f(self.0);
|
||||||
|
self.1.for_each_mut(f)
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Reducer function is used to aggregate values for the novelty search
|
/// A Reducer function is used to aggregate values for the novelty search
|
||||||
pub trait Reducer<T>
|
pub trait Reducer<T>: 'static
|
||||||
where
|
where
|
||||||
T: Integer + Copy + 'static,
|
T: Integer + Copy + 'static,
|
||||||
{
|
{
|
||||||
@ -102,7 +175,7 @@ where
|
|||||||
/// Contains information about untouched entries
|
/// Contains information about untouched entries
|
||||||
history_map: Vec<T>,
|
history_map: Vec<T>,
|
||||||
/// Name identifier of this instance
|
/// Name identifier of this instance
|
||||||
name: String,
|
name: &'static str,
|
||||||
/// Phantom Data of Reducer
|
/// Phantom Data of Reducer
|
||||||
phantom: PhantomData<(R, O)>,
|
phantom: PhantomData<(R, O)>,
|
||||||
}
|
}
|
||||||
@ -114,14 +187,14 @@ where
|
|||||||
O: MapObserver<T> + 'static,
|
O: MapObserver<T> + 'static,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
fn is_interesting(
|
fn is_interesting<OT: ObserversTuple>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_input: &I,
|
_input: &I,
|
||||||
observers: &NamedSerdeAnyMap,
|
observers: &OT,
|
||||||
) -> Result<u32, AflError> {
|
) -> Result<u32, AflError> {
|
||||||
let mut interesting = 0;
|
let mut interesting = 0;
|
||||||
// TODO optimize
|
// TODO optimize
|
||||||
let observer = observers.get::<O>(&self.name).unwrap();
|
let observer = observers.match_name_type::<O>(&self.name).unwrap();
|
||||||
let size = observer.map().len();
|
let size = observer.map().len();
|
||||||
for i in 0..size {
|
for i in 0..size {
|
||||||
let history = self.history_map[i];
|
let history = self.history_map[i];
|
||||||
@ -135,10 +208,17 @@ where
|
|||||||
|
|
||||||
Ok(interesting)
|
Ok(interesting)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, R, O> Named for MapFeedback<T, R, O>
|
||||||
|
where
|
||||||
|
T: Integer + Default + Copy + 'static,
|
||||||
|
R: Reducer<T>,
|
||||||
|
O: MapObserver<T> + 'static,
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &String {
|
fn name(&self) -> &str {
|
||||||
&self.name
|
self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,18 +232,18 @@ where
|
|||||||
pub fn new(name: &'static str, map_size: usize) -> Self {
|
pub fn new(name: &'static str, map_size: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
history_map: vec![T::default(); map_size],
|
history_map: vec![T::default(); map_size],
|
||||||
name: name.to_string(),
|
name: name,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_observer(map_observer: &O) -> Self {
|
/*pub fn new_with_observer(map_observer: &O) -> Self {
|
||||||
Self {
|
Self {
|
||||||
history_map: vec![T::default(); map_observer.map().len()],
|
history_map: vec![T::default(); map_observer.map().len()],
|
||||||
name: map_observer.name().to_string(),
|
name: map_observer.name(),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, R, O> MapFeedback<T, R, O>
|
impl<T, R, O> MapFeedback<T, R, O>
|
||||||
|
@ -19,6 +19,7 @@ pub mod mutators;
|
|||||||
pub mod observers;
|
pub mod observers;
|
||||||
pub mod serde_anymap;
|
pub mod serde_anymap;
|
||||||
pub mod stages;
|
pub mod stages;
|
||||||
|
pub mod tuples;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
extern crate num;
|
extern crate num;
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
use alloc::string::String;
|
|
||||||
use core::any::Any;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::serde_anymap::{ArrayMut, SerdeAny};
|
use crate::serde_anymap::ArrayMut;
|
||||||
|
use crate::tuples::{MatchNameAndType, MatchType, Named, TupleList};
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
// TODO register each observer in the Registry in new()
|
|
||||||
|
|
||||||
/// Observers observe different information about the target.
|
/// Observers observe different information about the target.
|
||||||
/// They can then be used by various sorts of feedback.
|
/// They can then be used by various sorts of feedback.
|
||||||
pub trait Observer: SerdeAny + 'static {
|
pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'static {
|
||||||
/// The testcase finished execution, calculate any changes.
|
/// The testcase finished execution, calculate any changes.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn flush(&mut self) -> Result<(), AflError> {
|
fn flush(&mut self) -> Result<(), AflError> {
|
||||||
@ -25,11 +21,53 @@ pub trait Observer: SerdeAny + 'static {
|
|||||||
fn post_exec(&mut self) -> Result<(), AflError> {
|
fn post_exec(&mut self) -> Result<(), AflError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name(&self) -> &String;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::create_serde_registry_for_trait!(observer_serde, crate::observers::Observer);
|
pub trait ObserversTuple:
|
||||||
|
MatchNameAndType + MatchType + serde::Serialize + serde::de::DeserializeOwned
|
||||||
|
{
|
||||||
|
fn reset_all(&mut self) -> Result<(), AflError>;
|
||||||
|
fn post_exec_all(&mut self) -> Result<(), AflError>;
|
||||||
|
//fn for_each(&self, f: fn(&dyn Observer));
|
||||||
|
//fn for_each_mut(&mut self, f: fn(&mut dyn Observer));
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObserversTuple for () {
|
||||||
|
fn reset_all(&mut self) -> Result<(), AflError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn post_exec_all(&mut self) -> Result<(), AflError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
//fn for_each(&self, f: fn(&dyn Observer)) { }
|
||||||
|
//fn for_each_mut(&mut self, f: fn(&mut dyn Observer)) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Head, Tail> ObserversTuple for (Head, Tail)
|
||||||
|
where
|
||||||
|
Head: Observer,
|
||||||
|
Tail: ObserversTuple + TupleList,
|
||||||
|
{
|
||||||
|
fn reset_all(&mut self) -> Result<(), AflError> {
|
||||||
|
self.0.reset()?;
|
||||||
|
self.1.reset_all()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_exec_all(&mut self) -> Result<(), AflError> {
|
||||||
|
self.0.post_exec()?;
|
||||||
|
self.1.post_exec_all()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*fn for_each(&self, f: fn(&dyn Observer)) {
|
||||||
|
f(&self.0);
|
||||||
|
self.1.for_each(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_each_mut(&mut self, f: fn(&mut dyn Observer)) {
|
||||||
|
f(&mut self.0);
|
||||||
|
self.1.for_each_mut(f)
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
/// A MapObserver observes the static map, as oftentimes used for afl-like coverage information
|
/// A MapObserver observes the static map, as oftentimes used for afl-like coverage information
|
||||||
pub trait MapObserver<T>
|
pub trait MapObserver<T>
|
||||||
@ -85,25 +123,15 @@ where
|
|||||||
fn reset(&mut self) -> Result<(), AflError> {
|
fn reset(&mut self) -> Result<(), AflError> {
|
||||||
self.reset_map()
|
self.reset_map()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &String {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SerdeAny for StdMapObserver<T>
|
impl<T> Named for StdMapObserver<T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn name(&self) -> &str {
|
||||||
self
|
self.name.as_str()
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +171,6 @@ where
|
|||||||
{
|
{
|
||||||
/// Creates a new MapObserver
|
/// Creates a new MapObserver
|
||||||
pub fn new(name: &'static str, map: &'static mut [T]) -> Self {
|
pub fn new(name: &'static str, map: &'static mut [T]) -> Self {
|
||||||
observer_serde::RegistryBuilder::register::<Self>();
|
|
||||||
let initial = if map.len() > 0 { map[0] } else { T::default() };
|
let initial = if map.len() > 0 { map[0] } else { T::default() };
|
||||||
Self {
|
Self {
|
||||||
map: ArrayMut::Cptr((map.as_mut_ptr(), map.len())),
|
map: ArrayMut::Cptr((map.as_mut_ptr(), map.len())),
|
||||||
@ -154,7 +181,6 @@ where
|
|||||||
|
|
||||||
/// Creates a new MapObserver from a raw pointer
|
/// Creates a new MapObserver from a raw pointer
|
||||||
pub fn new_from_ptr(name: &'static str, map_ptr: *mut T, len: usize) -> Self {
|
pub fn new_from_ptr(name: &'static str, map_ptr: *mut T, len: usize) -> Self {
|
||||||
observer_serde::RegistryBuilder::register::<Self>();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let initial = if len > 0 { *map_ptr } else { T::default() };
|
let initial = if len > 0 { *map_ptr } else { T::default() };
|
||||||
StdMapObserver {
|
StdMapObserver {
|
||||||
@ -166,6 +192,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@ -183,3 +210,4 @@ mod tests {
|
|||||||
assert_eq!(d.name(), o.name());
|
assert_eq!(d.name(), o.name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
@ -4,17 +4,22 @@ pub use mutational::StdMutationalStage;
|
|||||||
use crate::corpus::Corpus;
|
use crate::corpus::Corpus;
|
||||||
use crate::engines::{Engine, State};
|
use crate::engines::{Engine, State};
|
||||||
use crate::events::EventManager;
|
use crate::events::EventManager;
|
||||||
use crate::executors::Executor;
|
use crate::executors::{Executor, HasObservers};
|
||||||
|
use crate::feedbacks::FeedbacksTuple;
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
|
use crate::observers::ObserversTuple;
|
||||||
|
use crate::tuples::{MatchType, TupleList};
|
||||||
use crate::utils::Rand;
|
use crate::utils::Rand;
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
/// A stage is one step in the fuzzing process.
|
/// A stage is one step in the fuzzing process.
|
||||||
/// Multiple stages will be scheduled one by one for each input.
|
/// Multiple stages will be scheduled one by one for each input.
|
||||||
pub trait Stage<EM, E, C, I, R>
|
pub trait Stage<EM, E, OT, FT, C, I, R>
|
||||||
where
|
where
|
||||||
EM: EventManager<C, E, I, R>,
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
@ -23,10 +28,96 @@ where
|
|||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
rand: &mut R,
|
rand: &mut R,
|
||||||
state: &mut State<I, R>,
|
state: &mut State<I, R, FT>,
|
||||||
corpus: &mut C,
|
corpus: &mut C,
|
||||||
engine: &mut Engine<E, I>,
|
engine: &mut Engine<E, OT, I>,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: usize,
|
||||||
) -> Result<(), AflError>;
|
) -> Result<(), AflError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait StagesTuple<EM, E, OT, FT, C, I, R>
|
||||||
|
where
|
||||||
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
fn perform_all(
|
||||||
|
&mut self,
|
||||||
|
rand: &mut R,
|
||||||
|
state: &mut State<I, R, FT>,
|
||||||
|
corpus: &mut C,
|
||||||
|
engine: &mut Engine<E, OT, I>,
|
||||||
|
manager: &mut EM,
|
||||||
|
corpus_idx: usize,
|
||||||
|
) -> Result<(), AflError>;
|
||||||
|
fn for_each(&self, f: fn(&dyn Stage<EM, E, OT, FT, C, I, R>));
|
||||||
|
fn for_each_mut(&mut self, f: fn(&mut dyn Stage<EM, E, OT, FT, C, I, R>));
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<EM, E, OT, FT, C, I, R> StagesTuple<EM, E, OT, FT, C, I, R> for ()
|
||||||
|
where
|
||||||
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
fn perform_all(
|
||||||
|
&mut self,
|
||||||
|
rand: &mut R,
|
||||||
|
state: &mut State<I, R, FT>,
|
||||||
|
corpus: &mut C,
|
||||||
|
engine: &mut Engine<E, OT, I>,
|
||||||
|
manager: &mut EM,
|
||||||
|
corpus_idx: usize,
|
||||||
|
) -> Result<(), AflError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn for_each(&self, f: fn(&dyn Stage<EM, E, OT, FT, C, I, R>)) {}
|
||||||
|
fn for_each_mut(&mut self, f: fn(&mut dyn Stage<EM, E, OT, FT, C, I, R>)) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Head, Tail, EM, E, OT, FT, C, I, R> StagesTuple<EM, E, OT, FT, C, I, R> for (Head, Tail)
|
||||||
|
where
|
||||||
|
Head: Stage<EM, E, OT, FT, C, I, R>,
|
||||||
|
Tail: StagesTuple<EM, E, OT, FT, C, I, R> + TupleList,
|
||||||
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
fn perform_all(
|
||||||
|
&mut self,
|
||||||
|
rand: &mut R,
|
||||||
|
state: &mut State<I, R, FT>,
|
||||||
|
corpus: &mut C,
|
||||||
|
engine: &mut Engine<E, OT, I>,
|
||||||
|
manager: &mut EM,
|
||||||
|
corpus_idx: usize,
|
||||||
|
) -> Result<(), AflError> {
|
||||||
|
self.0
|
||||||
|
.perform(rand, state, corpus, engine, manager, corpus_idx)?;
|
||||||
|
self.1
|
||||||
|
.perform_all(rand, state, corpus, engine, manager, corpus_idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_each(&self, f: fn(&dyn Stage<EM, E, OT, FT, C, I, R>)) {
|
||||||
|
f(&self.0);
|
||||||
|
self.1.for_each(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_each_mut(&mut self, f: fn(&mut dyn Stage<EM, E, OT, FT, C, I, R>)) {
|
||||||
|
f(&mut self.0);
|
||||||
|
self.1.for_each_mut(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::events::EventManager;
|
use crate::events::EventManager;
|
||||||
use crate::executors::Executor;
|
use crate::executors::{Executor, HasObservers};
|
||||||
|
use crate::feedbacks::FeedbacksTuple;
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
use crate::mutators::Mutator;
|
use crate::mutators::Mutator;
|
||||||
|
use crate::observers::ObserversTuple;
|
||||||
use crate::stages::Corpus;
|
use crate::stages::Corpus;
|
||||||
use crate::stages::{Engine, Stage};
|
use crate::stages::{Engine, Stage};
|
||||||
use crate::utils::Rand;
|
use crate::utils::Rand;
|
||||||
@ -17,11 +19,13 @@ use crate::serde_anymap::{Ptr, PtrMut};
|
|||||||
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
|
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
|
||||||
/// Mutational stages will usually have a range of mutations that are
|
/// Mutational stages will usually have a range of mutations that are
|
||||||
/// being applied to the input one by one, between executions.
|
/// being applied to the input one by one, between executions.
|
||||||
pub trait MutationalStage<M, EM, E, C, I, R>: Stage<EM, E, C, I, R>
|
pub trait MutationalStage<M, EM, E, OT, FT, C, I, R>: Stage<EM, E, OT, FT, C, I, R>
|
||||||
where
|
where
|
||||||
M: Mutator<C, I, R>,
|
M: Mutator<C, I, R>,
|
||||||
EM: EventManager<C, E, I, R>,
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
@ -43,9 +47,9 @@ where
|
|||||||
fn perform_mutational(
|
fn perform_mutational(
|
||||||
&mut self,
|
&mut self,
|
||||||
rand: &mut R,
|
rand: &mut R,
|
||||||
state: &mut State<I, R>,
|
state: &mut State<I, R, FT>,
|
||||||
corpus: &mut C,
|
corpus: &mut C,
|
||||||
engine: &mut Engine<E, I>,
|
engine: &mut Engine<E, OT, I>,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: usize,
|
||||||
) -> Result<(), AflError> {
|
) -> Result<(), AflError> {
|
||||||
@ -82,24 +86,29 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The default mutational stage
|
/// The default mutational stage
|
||||||
pub struct StdMutationalStage<M, EM, E, C, I, R>
|
pub struct StdMutationalStage<M, EM, E, OT, FT, C, I, R>
|
||||||
where
|
where
|
||||||
M: Mutator<C, I, R>,
|
M: Mutator<C, I, R>,
|
||||||
EM: EventManager<C, E, I, R>,
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
mutator: M,
|
mutator: M,
|
||||||
phantom: PhantomData<(EM, E, C, I, R)>,
|
phantom: PhantomData<(EM, E, OT, FT, C, I, R)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, EM, E, C, I, R> MutationalStage<M, EM, E, C, I, R> for StdMutationalStage<M, EM, E, C, I, R>
|
impl<M, EM, E, OT, FT, C, I, R> MutationalStage<M, EM, E, OT, FT, C, I, R>
|
||||||
|
for StdMutationalStage<M, EM, E, OT, FT, C, I, R>
|
||||||
where
|
where
|
||||||
M: Mutator<C, I, R>,
|
M: Mutator<C, I, R>,
|
||||||
EM: EventManager<C, E, I, R>,
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
@ -117,11 +126,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, EM, E, C, I, R> Stage<EM, E, C, I, R> for StdMutationalStage<M, EM, E, C, I, R>
|
impl<M, EM, E, OT, FT, C, I, R> Stage<EM, E, OT, FT, C, I, R>
|
||||||
|
for StdMutationalStage<M, EM, E, OT, FT, C, I, R>
|
||||||
where
|
where
|
||||||
M: Mutator<C, I, R>,
|
M: Mutator<C, I, R>,
|
||||||
EM: EventManager<C, E, I, R>,
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
@ -130,9 +142,9 @@ where
|
|||||||
fn perform(
|
fn perform(
|
||||||
&mut self,
|
&mut self,
|
||||||
rand: &mut R,
|
rand: &mut R,
|
||||||
state: &mut State<I, R>,
|
state: &mut State<I, R, FT>,
|
||||||
corpus: &mut C,
|
corpus: &mut C,
|
||||||
engine: &mut Engine<E, I>,
|
engine: &mut Engine<E, OT, I>,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: usize,
|
||||||
) -> Result<(), AflError> {
|
) -> Result<(), AflError> {
|
||||||
@ -140,11 +152,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, EM, E, C, I, R> StdMutationalStage<M, EM, E, C, I, R>
|
impl<M, EM, E, OT, FT, C, I, R> StdMutationalStage<M, EM, E, OT, FT, C, I, R>
|
||||||
where
|
where
|
||||||
M: Mutator<C, I, R>,
|
M: Mutator<C, I, R>,
|
||||||
EM: EventManager<C, E, I, R>,
|
EM: EventManager<C, E, OT, FT, I, R>,
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
FT: FeedbacksTuple<I>,
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
R: Rand,
|
||||||
|
@ -1,16 +1,21 @@
|
|||||||
use tuple_list::TupleList;
|
pub use tuple_list::tuple_list;
|
||||||
use tuple_list::tuple_list;
|
pub use tuple_list::tuple_list_type;
|
||||||
use core::any::{TypeId, Any};
|
pub use tuple_list::TupleList;
|
||||||
|
|
||||||
|
use core::any::TypeId;
|
||||||
|
|
||||||
pub trait HasLen {
|
pub trait HasLen {
|
||||||
fn len(&self) -> usize;
|
fn len(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasLen for () {
|
impl HasLen for () {
|
||||||
fn len(&self) -> usize { 0 }
|
fn len(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Head, Tail> HasLen for (Head, Tail) where
|
impl<Head, Tail> HasLen for (Head, Tail)
|
||||||
|
where
|
||||||
Tail: TupleList + HasLen,
|
Tail: TupleList + HasLen,
|
||||||
{
|
{
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
@ -20,13 +25,20 @@ impl<Head, Tail> HasLen for (Head, Tail) where
|
|||||||
|
|
||||||
pub trait MatchFirstType {
|
pub trait MatchFirstType {
|
||||||
fn match_first_type<T: 'static>(&self) -> Option<&T>;
|
fn match_first_type<T: 'static>(&self) -> Option<&T>;
|
||||||
|
fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MatchFirstType for () {
|
impl MatchFirstType for () {
|
||||||
fn match_first_type<T: 'static>(&self) -> Option<&T> { None }
|
fn match_first_type<T: 'static>(&self) -> Option<&T> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Head, Tail> MatchFirstType for (Head, Tail) where
|
impl<Head, Tail> MatchFirstType for (Head, Tail)
|
||||||
|
where
|
||||||
Head: 'static,
|
Head: 'static,
|
||||||
Tail: TupleList + MatchFirstType,
|
Tail: TupleList + MatchFirstType,
|
||||||
{
|
{
|
||||||
@ -37,17 +49,32 @@ impl<Head, Tail> MatchFirstType for (Head, Tail) where
|
|||||||
self.1.match_first_type::<T>()
|
self.1.match_first_type::<T>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||||
|
if TypeId::of::<T>() == TypeId::of::<Head>() {
|
||||||
|
unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }
|
||||||
|
} else {
|
||||||
|
self.1.match_first_type_mut::<T>()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MatchType {
|
pub trait MatchType {
|
||||||
fn match_type<T: 'static>(&self, f: fn(t: &T));
|
fn match_type<T: 'static>(&self, f: fn(t: &T));
|
||||||
|
fn match_type_mut<T: 'static>(&mut self, f: fn(t: &mut T));
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MatchType for () {
|
impl MatchType for () {
|
||||||
fn match_type<T: 'static>(&self, f: fn(t: &T)) { () }
|
fn match_type<T: 'static>(&self, f: fn(t: &T)) {
|
||||||
|
()
|
||||||
|
}
|
||||||
|
fn match_type_mut<T: 'static>(&mut self, f: fn(t: &mut T)) {
|
||||||
|
()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Head, Tail> MatchType for (Head, Tail) where
|
impl<Head, Tail> MatchType for (Head, Tail)
|
||||||
|
where
|
||||||
Head: 'static,
|
Head: 'static,
|
||||||
Tail: TupleList + MatchType,
|
Tail: TupleList + MatchType,
|
||||||
{
|
{
|
||||||
@ -57,21 +84,35 @@ impl<Head, Tail> MatchType for (Head, Tail) where
|
|||||||
}
|
}
|
||||||
self.1.match_type::<T>(f);
|
self.1.match_type::<T>(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn match_type_mut<T: 'static>(&mut self, f: fn(t: &mut T)) {
|
||||||
|
if TypeId::of::<T>() == TypeId::of::<Head>() {
|
||||||
|
f(unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }.unwrap());
|
||||||
|
}
|
||||||
|
self.1.match_type_mut::<T>(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Named {
|
pub trait Named {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &str;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MatchNameAndType {
|
pub trait MatchNameAndType {
|
||||||
fn match_name_type<T: 'static>(&self, name: &'static str) -> Option<&T>;
|
fn match_name_type<T: 'static>(&self, name: &'static str) -> Option<&T>;
|
||||||
|
fn match_name_type_mut<T: 'static>(&mut self, name: &'static str) -> Option<&mut T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MatchNameAndType for () {
|
impl MatchNameAndType for () {
|
||||||
fn match_name_type<T: 'static>(&self, name: &'static str) -> Option<&T> { None }
|
fn match_name_type<T: 'static>(&self, name: &'static str) -> Option<&T> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn match_name_type_mut<T: 'static>(&mut self, name: &'static str) -> Option<&mut T> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Head, Tail> MatchNameAndType for (Head, Tail) where
|
impl<Head, Tail> MatchNameAndType for (Head, Tail)
|
||||||
|
where
|
||||||
Head: 'static + Named,
|
Head: 'static + Named,
|
||||||
Tail: TupleList + MatchNameAndType,
|
Tail: TupleList + MatchNameAndType,
|
||||||
{
|
{
|
||||||
@ -82,6 +123,14 @@ impl<Head, Tail> MatchNameAndType for (Head, Tail) where
|
|||||||
self.1.match_name_type::<T>(name)
|
self.1.match_name_type::<T>(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn match_name_type_mut<T: 'static>(&mut self, name: &'static str) -> Option<&mut T> {
|
||||||
|
if TypeId::of::<T>() == TypeId::of::<Head>() && name == self.0.name() {
|
||||||
|
unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }
|
||||||
|
} else {
|
||||||
|
self.1.match_name_type_mut::<T>(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Prepend<T>: TupleList {
|
pub trait Prepend<T>: TupleList {
|
||||||
@ -91,35 +140,41 @@ pub trait Prepend<T>: TupleList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Implement prepend for tuple list.
|
/// Implement prepend for tuple list.
|
||||||
impl<Tail, T> Prepend<T> for Tail where Tail: TupleList {
|
impl<Tail, T> Prepend<T> for Tail
|
||||||
|
where
|
||||||
|
Tail: TupleList,
|
||||||
|
{
|
||||||
type PreprendResult = Self;
|
type PreprendResult = Self;
|
||||||
|
|
||||||
fn prepend(self, value: T) -> (T, Self::PreprendResult) {
|
fn prepend(self, value: T) -> (T, Self::PreprendResult) {
|
||||||
(value, self)
|
(value, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Append<T>: TupleList {
|
pub trait Append<T>: TupleList {
|
||||||
type AppendResult: TupleList;
|
type AppendResult: TupleList;
|
||||||
|
|
||||||
fn append(self, value: T) -> Self::AppendResult;
|
fn append(self, value: T) -> Self::AppendResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implement append for an empty tuple list.
|
/// Implement append for an empty tuple list.
|
||||||
impl<T> Append<T> for () {
|
impl<T> Append<T> for () {
|
||||||
type AppendResult = (T, ());
|
type AppendResult = (T, ());
|
||||||
|
|
||||||
fn append(self, value: T) -> Self::AppendResult { (value, ()) }
|
fn append(self, value: T) -> Self::AppendResult {
|
||||||
|
(value, ())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implement append for non-empty tuple list.
|
/// Implement append for non-empty tuple list.
|
||||||
impl<Head, Tail, T> Append<T> for (Head, Tail) where
|
impl<Head, Tail, T> Append<T> for (Head, Tail)
|
||||||
|
where
|
||||||
Self: TupleList,
|
Self: TupleList,
|
||||||
Tail: Append<T>,
|
Tail: Append<T>,
|
||||||
(Head, Tail::AppendResult): TupleList,
|
(Head, Tail::AppendResult): TupleList,
|
||||||
{
|
{
|
||||||
type AppendResult = (Head, Tail::AppendResult);
|
type AppendResult = (Head, Tail::AppendResult);
|
||||||
|
|
||||||
fn append(self, value: T) -> Self::AppendResult {
|
fn append(self, value: T) -> Self::AppendResult {
|
||||||
let (head, tail) = self;
|
let (head, tail) = self;
|
||||||
return (head, tail.append(value));
|
return (head, tail.append(value));
|
||||||
@ -134,13 +189,13 @@ trait PlusOne {
|
|||||||
}
|
}
|
||||||
impl PlusOne for i32 { fn plus_one(&mut self) { *self += 1; } }
|
impl PlusOne for i32 { fn plus_one(&mut self) { *self += 1; } }
|
||||||
impl PlusOne for String { fn plus_one(&mut self) { self.push('1'); } }
|
impl PlusOne for String { fn plus_one(&mut self) { self.push('1'); } }
|
||||||
|
|
||||||
// Now we have to implement trait for an empty tuple,
|
// Now we have to implement trait for an empty tuple,
|
||||||
// thus defining initial condition.
|
// thus defining initial condition.
|
||||||
impl PlusOne for () {
|
impl PlusOne for () {
|
||||||
fn plus_one(&mut self) {}
|
fn plus_one(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we can implement trait for a non-empty tuple list,
|
// Now we can implement trait for a non-empty tuple list,
|
||||||
// thus defining recursion and supporting tuple lists of arbitrary length.
|
// thus defining recursion and supporting tuple lists of arbitrary length.
|
||||||
impl<Head, Tail> PlusOne for (Head, Tail) where
|
impl<Head, Tail> PlusOne for (Head, Tail) where
|
||||||
|
@ -22,8 +22,9 @@ use afl::mutators::HasMaxSize;
|
|||||||
use afl::observers::StdMapObserver;
|
use afl::observers::StdMapObserver;
|
||||||
use afl::stages::mutational::StdMutationalStage;
|
use afl::stages::mutational::StdMutationalStage;
|
||||||
use afl::utils::StdRand;
|
use afl::utils::StdRand;
|
||||||
|
use afl::tuples::tuple_list;
|
||||||
|
|
||||||
// const MAP_SIZE: usize = 65536;
|
const MAP_SIZE: usize = 65536;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -59,18 +60,12 @@ pub extern "C" fn afl_libfuzzer_main() {
|
|||||||
StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { __lafl_edges_map }, unsafe {
|
StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { __lafl_edges_map }, unsafe {
|
||||||
__lafl_max_edges_size as usize
|
__lafl_max_edges_size as usize
|
||||||
});
|
});
|
||||||
let edges_feedback = MaxMapFeedback::new_with_observer(&edges_observer);
|
let edges_feedback = MaxMapFeedback::<u8, StdMapObserver<u8>>::new(&NAME_COV_MAP, MAP_SIZE);
|
||||||
|
|
||||||
let mut executor = InMemoryExecutor::new(harness);
|
|
||||||
let mut state = State::new();
|
|
||||||
executor.add_observer(Box::new(edges_observer));
|
|
||||||
state.add_feedback(Box::new(edges_feedback));
|
|
||||||
|
|
||||||
|
let executor = InMemoryExecutor::new(harness, tuple_list!(edges_observer));
|
||||||
|
let mut state = State::new(tuple_list!(edges_feedback));
|
||||||
|
|
||||||
let mut engine = Engine::new(executor);
|
let mut engine = Engine::new(executor);
|
||||||
let mut mutator = HavocBytesMutator::new_default();
|
|
||||||
mutator.set_max_size(4096);
|
|
||||||
|
|
||||||
let stage = StdMutationalStage::new(mutator);
|
|
||||||
|
|
||||||
state
|
state
|
||||||
.generate_initial_inputs(
|
.generate_initial_inputs(
|
||||||
@ -83,9 +78,11 @@ pub extern "C" fn afl_libfuzzer_main() {
|
|||||||
)
|
)
|
||||||
.expect("Failed to load initial inputs");
|
.expect("Failed to load initial inputs");
|
||||||
|
|
||||||
let mut fuzzer = StdFuzzer::new();
|
let mut mutator = HavocBytesMutator::new_default();
|
||||||
|
mutator.set_max_size(4096);
|
||||||
|
|
||||||
fuzzer.add_stage(Box::new(stage));
|
let stage = StdMutationalStage::new(mutator);
|
||||||
|
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
|
||||||
|
|
||||||
fuzzer
|
fuzzer
|
||||||
.fuzz_loop(&mut rand, &mut state, &mut corpus, &mut engine, &mut events)
|
.fuzz_loop(&mut rand, &mut state, &mut corpus, &mut engine, &mut events)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user