This commit is contained in:
Andrea Fioraldi 2021-02-22 11:26:11 +01:00
parent 1585645972
commit c411fec271
24 changed files with 314 additions and 335 deletions

View File

@ -1,9 +1,9 @@
//! Compare the speed of rand implementations
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use libafl::utils::{
Lehmer64Rand, Rand, RomuDuoJrRand, RomuTrioRand, XorShift64Rand, Xoshiro256StarRand,
};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn criterion_benchmark(c: &mut Criterion) {
let mut xorshift = XorShift64Rand::new(1);

View File

@ -1,5 +1,4 @@
fn main() {
#[cfg(target_os = "windows")]
windows::build!(
windows::win32::system_services::HANDLE,
@ -7,5 +6,4 @@ fn main() {
// API needed for the shared memory
windows::win32::system_services::{CreateFileMappingA, OpenFileMappingA, MapViewOfFile, UnmapViewOfFile},
);
}

View File

@ -1,8 +1,8 @@
//! Bolts are no conceptual fuzzing elements, but they keep libafl-based fuzzers together.
pub mod bindings;
pub mod llmp;
pub mod ownedref;
pub mod serdeany;
pub mod shmem;
pub mod tuples;
pub mod bindings;

View File

@ -330,8 +330,8 @@ pub mod shmem {
use core::{mem::size_of, slice};
use std::ffi::CStr;
use crate::Error;
use super::ShMem;
use crate::Error;
/// The default Sharedmap impl for windows using shmctl & shmget
#[derive(Clone, Debug)]
@ -343,7 +343,6 @@ pub mod shmem {
}
// TODO complete
}
#[cfg(test)]

View File

@ -7,12 +7,7 @@ use alloc::vec::Vec;
use core::cell::RefCell;
use serde::{Deserialize, Serialize};
use crate::{
inputs::Input,
state::{HasCorpus, HasRand},
utils::Rand,
Error,
};
use crate::{inputs::Input, Error};
/// Corpus with all current testcases
pub trait Corpus<I>: serde::Serialize + serde::de::DeserializeOwned
@ -33,65 +28,41 @@ where
/// Get by id
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error>;
/// Current testcase scheduled
fn current(&self) -> &Option<usize>;
/// Current testcase scheduled (mut)
fn current_mut(&mut self) -> &mut Option<usize>;
}
pub trait CorpusScheduler {
/// Add an entry to the corpus and return its index
fn on_add<C, I, R, S>(
&self,
state: &mut S,
idx: usize,
testcase: &Testcase<I>,
) -> Result<(), Error>
pub trait CorpusScheduler<I, S>
where
S: HasCorpus<C, I> + HasRand<R>,
C: Corpus<I>,
I: Input,
R: Rand,
{
/// Add an entry to the corpus and return its index
fn on_add(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error> {
Ok(())
}
/// Replaces the testcase at the given idx
fn on_replace<C, I, R, S>(
&self,
state: &mut S,
idx: usize,
testcase: &Testcase<I>,
) -> Result<(), Error>
where
S: HasCorpus<C, I> + HasRand<R>,
C: Corpus<I>,
I: Input,
R: Rand,
{
fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error> {
Ok(())
}
/// Removes an entry from the corpus, returning it if it was present.
fn on_remove<C, I, R, S>(
fn on_remove(
&self,
state: &mut S,
idx: usize,
testcase: &Option<Testcase<I>>,
) -> Result<(), Error>
where
S: HasCorpus<C, I> + HasRand<R>,
C: Corpus<I>,
I: Input,
R: Rand,
{
) -> Result<(), Error> {
Ok(())
}
// TODO: IntoIter
/// Gets the next entry
fn next<C, I, R, S>(&self, state: &mut S) -> Result<usize, Error>
where
S: HasCorpus<C, I> + HasRand<R>,
C: Corpus<I>,
I: Input,
R: Rand;
fn next(&self, state: &mut S) -> Result<usize, Error>;
}
/*
@ -124,6 +95,7 @@ where
I: Input,
{
entries: Vec<RefCell<Testcase<I>>>,
current: Option<usize>,
}
impl<I> Corpus<I> for InMemoryCorpus<I>
@ -168,4 +140,14 @@ where
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error> {
Ok(&self.entries[idx])
}
/// Current testcase scheduled
fn current(&self) -> &Option<usize> {
&self.current
}
/// Current testcase scheduled (mut)
fn current_mut(&mut self) -> &mut Option<usize> {
&mut self.current
}
}

View File

@ -39,23 +39,25 @@ const _LLMP_TAG_RESTART: llmp::Tag = 0x8357A87;
const _LLMP_TAG_NO_RESTART: llmp::Tag = 0x57A7EE71;
#[derive(Clone, Debug)]
pub struct LlmpEventManager<I, SH, ST>
pub struct LlmpEventManager<I, S, SH, ST>
where
I: Input,
S: IfInteresting<I>,
SH: ShMem,
ST: Stats,
//CE: CustomEvent<I>,
{
stats: Option<ST>,
llmp: llmp::LlmpConnection<SH>,
phantom: PhantomData<I>,
phantom: PhantomData<(I, S)>,
}
#[cfg(feature = "std")]
#[cfg(unix)]
impl<I, ST> LlmpEventManager<I, UnixShMem, ST>
impl<I, S, ST> LlmpEventManager<I, S, UnixShMem, ST>
where
I: Input,
S: IfInteresting<I>,
ST: Stats,
{
/// Create llmp on a port
@ -78,9 +80,10 @@ where
}
}
impl<I, SH, ST> Drop for LlmpEventManager<I, SH, ST>
impl<I, S, SH, ST> Drop for LlmpEventManager<I, S, SH, ST>
where
I: Input,
S: IfInteresting<I>,
SH: ShMem,
ST: Stats,
{
@ -90,9 +93,10 @@ where
}
}
impl<I, SH, ST> LlmpEventManager<I, SH, ST>
impl<I, S, SH, ST> LlmpEventManager<I, S, SH, ST>
where
I: Input,
S: IfInteresting<I>,
SH: ShMem,
ST: Stats,
{
@ -248,7 +252,7 @@ where
}
// Handle arriving events in the client
fn handle_in_client<E, OT, S>(
fn handle_in_client<E, OT>(
&mut self,
state: &mut S,
sender_id: u32,
@ -258,7 +262,6 @@ where
where
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
S: IfInteresting<I>,
{
match event {
Event::NewTestcase {
@ -293,9 +296,10 @@ where
}
}
impl<I, SH, ST> EventManager<E, I, S> for LlmpEventManager<I, SH, ST>
impl<I, S, SH, ST> EventManager<I, S> for LlmpEventManager<I, S, SH, ST>
where
I: Input,
S: IfInteresting<I>,
SH: ShMem,
ST: Stats, //CE: CustomEvent<I>,
{
@ -311,11 +315,10 @@ where
}
}
fn process<E, OT, S>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
fn process<E, OT>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
where
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
S: IfInteresting<I>,
{
// TODO: Get around local event copy by moving handle_in_client
let mut events = vec![];
@ -344,7 +347,7 @@ where
Ok(count)
}
fn fire<S>(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> {
fn fire(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> {
let serialized = postcard::to_allocvec(&event)?;
self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?;
Ok(())
@ -356,11 +359,11 @@ where
/// This method is needed when the fuzzer run crashes and has to restart.
pub fn serialize_state_mgr<I, S, SH, ST>(
state: &S,
mgr: &LlmpEventManager<I, SH, ST>,
mgr: &LlmpEventManager<I, S, SH, ST>,
) -> Result<Vec<u8>, Error>
where
I: Input,
S: Serialize,
S: Serialize + IfInteresting<I>,
SH: ShMem,
ST: Stats,
{
@ -370,10 +373,10 @@ where
/// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)`
pub fn deserialize_state_mgr<I, S, SH, ST>(
state_corpus_serialized: &[u8],
) -> Result<(S, LlmpEventManager<I, SH, ST>), Error>
) -> Result<(S, LlmpEventManager<I, S, SH, ST>), Error>
where
I: Input,
S: DeserializeOwned,
S: DeserializeOwned + IfInteresting<I>,
SH: ShMem,
ST: Stats,
{
@ -386,22 +389,24 @@ where
/// A manager that can restart on the fly, storing states in-between (in `on_resatrt`)
#[derive(Clone, Debug)]
pub struct LlmpRestartingEventManager<I, SH, ST>
pub struct LlmpRestartingEventManager<I, S, SH, ST>
where
I: Input,
S: IfInteresting<I>,
SH: ShMem,
ST: Stats,
//CE: CustomEvent<I>,
{
/// The embedded llmp event manager
llmp_mgr: LlmpEventManager<I, SH, ST>,
llmp_mgr: LlmpEventManager<I, S, SH, ST>,
/// The sender to serialize the state for the next runner
sender: LlmpSender<SH>,
}
impl<I, SH, ST> EventManager<E, I, S> for LlmpRestartingEventManager<I, SH, ST>
impl<I, S, SH, ST> EventManager<I, S> for LlmpRestartingEventManager<I, S, SH, ST>
where
I: Input,
S: IfInteresting<I> + Serialize,
SH: ShMem,
ST: Stats, //CE: CustomEvent<I>,
{
@ -413,10 +418,7 @@ where
}
/// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner.
fn on_restart<S>(&mut self, state: &mut S) -> Result<(), Error>
where
S: Serialize,
{
fn on_restart(&mut self, state: &mut S) -> Result<(), Error> {
// First, reset the page to 0 so the next iteration can read read from the beginning of this page
unsafe { self.sender.reset() };
let state_corpus_serialized = serialize_state_mgr(state, &self.llmp_mgr)?;
@ -424,16 +426,15 @@ where
.send_buf(_LLMP_TAG_RESTART, &state_corpus_serialized)
}
fn process<E, OT, S>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
fn process<E, OT>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
where
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
S: IfInteresting<I>,
{
self.llmp_mgr.process(state, executor)
}
fn fire<S>(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error> {
fn fire(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error> {
// Check if we are going to crash in the event, in which case we store our current state for the next runner
self.llmp_mgr.fire(state, event)
}
@ -445,14 +446,15 @@ const _ENV_FUZZER_RECEIVER: &str = &"_AFL_ENV_FUZZER_RECEIVER";
/// The llmp (2 way) connection from a fuzzer to the broker (broadcasting all other fuzzer messages)
const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = &"_AFL_ENV_FUZZER_BROKER_CLIENT";
impl<I, SH, ST> LlmpRestartingEventManager<I, SH, ST>
impl<I, S, SH, ST> LlmpRestartingEventManager<I, S, SH, ST>
where
I: Input,
S: IfInteresting<I>,
SH: ShMem,
ST: Stats, //CE: CustomEvent<I>,
{
/// Create a new runner, the executed child doing the actual fuzzing.
pub fn new(llmp_mgr: LlmpEventManager<I, SH, ST>, sender: LlmpSender<SH>) -> Self {
pub fn new(llmp_mgr: LlmpEventManager<I, S, SH, ST>, sender: LlmpSender<SH>) -> Self {
Self { llmp_mgr, sender }
}
@ -471,13 +473,13 @@ where
/// The restarter will start a new process each time the child crashes or timeouts.
#[cfg(feature = "std")]
pub fn setup_restarting_mgr<I, S, SH, ST>(
//mgr: &mut LlmpEventManager<I, SH, ST>,
//mgr: &mut LlmpEventManager<I, S, SH, ST>,
stats: ST,
broker_port: u16,
) -> Result<(Option<S>, LlmpRestartingEventManager<I, SH, ST>), Error>
) -> Result<(Option<S>, LlmpRestartingEventManager<I, S, SH, ST>), Error>
where
I: Input,
S: DeserializeOwned,
S: DeserializeOwned + IfInteresting<I>,
SH: ShMem,
ST: Stats,
{
@ -485,7 +487,7 @@ where
// We start ourself as child process to actually fuzz
if std::env::var(_ENV_FUZZER_SENDER).is_err() {
mgr = LlmpEventManager::<I, SH, ST>::new_on_port(stats, broker_port)?;
mgr = LlmpEventManager::<I, S, SH, ST>::new_on_port(stats, broker_port)?;
if mgr.is_broker() {
// Yep, broker. Just loop here.
println!("Doing broker things. Run this tool again to start fuzzing in a client.");
@ -528,7 +530,7 @@ where
None => {
println!("First run. Let's set it all up");
// Mgr to send and receive msgs from/to all other fuzzer instances
let client_mgr = LlmpEventManager::<I, SH, ST>::existing_client_from_env(
let client_mgr = LlmpEventManager::<I, S, SH, ST>::existing_client_from_env(
_ENV_FUZZER_BROKER_CLIENT_INITIAL,
)?;
@ -537,7 +539,7 @@ where
// Restoring from a previous run, deserialize state and corpus.
Some((_sender, _tag, msg)) => {
println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len());
let (state, mgr): (S, LlmpEventManager<I, SH, ST>) = deserialize_state_mgr(&msg)?;
let (state, mgr): (S, LlmpEventManager<I, S, SH, ST>) = deserialize_state_mgr(&msg)?;
(Some(state), LlmpRestartingEventManager::new(mgr, sender))
}

View File

@ -5,14 +5,16 @@ use core::marker::PhantomData;
#[cfg(unix)]
use crate::{
events::{BrokerEventResult, Event, EventManager},
executors::{Executor, HasObservers},
inputs::Input,
observers::ObserversTuple,
stats::Stats,
Error,
};
/// A simple, single-threaded event manager that just logs
#[derive(Clone, Debug)]
pub struct LoggerEventManager<E, I, S, ST>
pub struct LoggerEventManager<I, S, ST>
where
I: Input,
ST: Stats, //CE: CustomEvent<I, OT>,
@ -21,15 +23,19 @@ where
stats: ST,
/// The events that happened since the last handle_in_broker
events: Vec<Event<I>>,
phantom: PhantomData<(E, S)>,
phantom: PhantomData<S>,
}
impl<E, I, S, ST> EventManager<E, I, S> for LoggerEventManager<E, I, S, ST>
impl<I, S, ST> EventManager<I, S> for LoggerEventManager<I, S, ST>
where
I: Input,
ST: Stats, //CE: CustomEvent<I, OT>,
{
fn process(&mut self, state: &mut S, _executor: &mut E) -> Result<usize, Error> {
fn process<E, OT>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
where
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
{
let count = self.events.len();
while self.events.len() > 0 {
let event = self.events.pop().unwrap();
@ -47,7 +53,7 @@ where
}
}
impl<E, I, S, ST> LoggerEventManager<E, I, S, ST>
impl<I, S, ST> LoggerEventManager<I, S, ST>
where
I: Input,
ST: Stats, //TODO CE: CustomEvent,

View File

@ -9,7 +9,10 @@ use core::{fmt, marker::PhantomData, time::Duration};
use serde::{Deserialize, Serialize};
use crate::{
executors::Executor, inputs::Input, observers::ObserversTuple, state::IfInteresting, Error,
executors::{Executor, HasObservers},
inputs::Input,
observers::ObserversTuple,
Error,
};
/// The log event severity
@ -146,7 +149,7 @@ where
/// EventManager is the main communications hub.
/// For the "normal" multi-processed mode, you may want to look into `RestartingEventManager`
pub trait EventManager<E, I, S>
pub trait EventManager<I, S>
where
I: Input,
{
@ -155,7 +158,10 @@ where
/// Lookup for incoming events and process them.
/// Return the number of processes events or an error
fn process(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>;
fn process<E, OT>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
where
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple;
/// Serialize all observers for this type and manager
fn serialize_observers<OT>(&mut self, observers: &OT) -> Result<Vec<u8>, Error>
@ -189,16 +195,17 @@ where
/// An eventmgr for tests, and as placeholder if you really don't need an event manager.
#[derive(Copy, Clone, Debug)]
pub struct NopEventManager<E, I, S> {
phantom: PhantomData<(E, I, S)>,
pub struct NopEventManager<I, S> {
phantom: PhantomData<(I, S)>,
}
impl<E, I, S> EventManager<E, I, S> for NopEventManager<E, I, S>
impl<I, S> EventManager<I, S> for NopEventManager<I, S>
where
I: Input,
{
fn process(&mut self, _state: &mut S, _executor: &mut E) -> Result<usize, Error>
fn process<E, OT>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
where
E: Executor<I>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
{
Ok(0)
}

View File

@ -56,7 +56,7 @@ where
#[inline]
fn pre_exec<EM, S>(&mut self, state: &mut S, event_mgr: &mut EM, input: &I) -> Result<(), Error>
where
EM: EventManager<I>,
EM: EventManager<I, S>,
{
#[cfg(unix)]
#[cfg(feature = "std")]
@ -69,7 +69,7 @@ where
#[inline]
fn post_exec<EM, S>(&mut self, _state: &S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error>
where
EM: EventManager<I>,
EM: EventManager<I, S>,
{
#[cfg(unix)]
#[cfg(feature = "std")]
@ -132,7 +132,7 @@ where
_event_mgr: &mut EM,
) -> Self
where
EM: EventManager<I>,
EM: EventManager<I, S>,
OC: Corpus<I>,
OFT: FeedbacksTuple<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
@ -200,7 +200,7 @@ pub mod unix_signals {
info: siginfo_t,
_void: c_void,
) where
EM: EventManager<I>,
EM: EventManager<I, S>,
OT: ObserversTuple,
OC: Corpus<I>,
OFT: FeedbacksTuple<I>,
@ -273,7 +273,7 @@ pub mod unix_signals {
info: siginfo_t,
_void: c_void,
) where
EM: EventManager<I>,
EM: EventManager<I, S>,
OT: ObserversTuple,
OC: Corpus<I>,
OFT: FeedbacksTuple<I>,
@ -346,7 +346,7 @@ pub mod unix_signals {
pub unsafe fn setup_crash_handlers<EM, I, OC, OFT, OT, R, S>()
where
EM: EventManager<I>,
EM: EventManager<I, S>,
OT: ObserversTuple,
OC: Corpus<I>,
OFT: FeedbacksTuple<I>,

View File

@ -87,21 +87,16 @@ where
_input: &I,
) -> Result<(), Error>
where
EM: EventManager<I>,
EM: EventManager<I, S>,
{
Ok(())
}
#[inline]
/// Called right after execution finished.
fn post_exec<EM, S>(
&mut self,
_state: &S,
_event_mgr: &mut EM,
_input: &I,
) -> Result<(), Error>
fn post_exec<EM, S>(&mut self, _state: &S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error>
where
EM: EventManager<I>,
EM: EventManager<I, S>,
{
Ok(())
}

View File

@ -1,20 +1,20 @@
use crate::{
corpus::{Corpus, CorpusScheduler},
corpus::CorpusScheduler,
events::{Event, EventManager},
executors::Executor,
executors::{Executor, HasObservers},
inputs::Input,
observers::ObserversTuple,
stages::StagesTuple,
state::{HasCorpus, HasExecutions, HasRand},
utils::{current_milliseconds, current_time, Rand},
state::HasExecutions,
utils::{current_milliseconds, current_time},
Error,
};
use core::marker::PhantomData;
/// Holds a set of stages
pub trait HasStages<ST, I>
pub trait HasStages<ST, E, EM, S>: Sized
where
ST: StagesTuple<I>,
I: Input,
ST: StagesTuple<E, EM, Self, S>,
{
fn stages(&self) -> &ST;
@ -22,9 +22,10 @@ where
}
/// Holds a scheduler
pub trait HasCorpusScheduler<CS>
pub trait HasCorpusScheduler<CS, I, S>
where
CS: CorpusScheduler,
CS: CorpusScheduler<I, S>,
I: Input,
{
fn scheduler(&self) -> &CS;
@ -32,50 +33,29 @@ where
}
/// The main fuzzer trait.
pub trait Fuzzer<CS, ST, I>: HasCorpusScheduler<CS> + HasStages<ST, I>
where
CS: CorpusScheduler,
ST: StagesTuple<I>,
I: Input,
{
fn fuzz_one<E, EM, S>(
&self,
state: &mut S,
executor: &mut E,
manager: &mut EM,
) -> Result<usize, Error>
where
EM: EventManager<I>,
E: Executor<I>;
pub trait Fuzzer<E, EM, S> {
fn fuzz_one(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result<usize, Error>;
fn fuzz_loop<E, EM, S>(
&self,
state: &mut S,
executor: &mut E,
manager: &mut EM,
) -> Result<usize, Error>
where
EM: EventManager<I>,
E: Executor<I>;
fn fuzz_loop(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result<usize, Error>;
}
/// Your default fuzzer instance, for everyday use.
#[derive(Clone, Debug)]
pub struct StdFuzzer<CS, ST, I>
pub struct StdFuzzer<CS, ST, E, EM, I, OT, S>
where
CS: CorpusScheduler,
ST: StagesTuple<I>,
CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>,
I: Input,
{
scheduler: CS,
stages: ST,
phantom: PhantomData<I>,
phantom: PhantomData<(E, EM, I, OT, S)>,
}
impl<CS, ST, I> HasStages<ST, I> for StdFuzzer<CS, ST, I>
impl<CS, ST, E, EM, I, OT, S> HasStages<ST, E, EM, S> for StdFuzzer<CS, ST, E, EM, I, OT, S>
where
CS: CorpusScheduler,
ST: StagesTuple<I>,
CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>,
I: Input,
{
fn stages(&self) -> &ST {
@ -87,10 +67,10 @@ where
}
}
impl<CS, ST, I> HasCorpusScheduler<CS> for StdFuzzer<CS, ST, I>
impl<CS, ST, E, EM, I, OT, S> HasCorpusScheduler<CS, I, S> for StdFuzzer<CS, ST, E, EM, I, OT, S>
where
CS: CorpusScheduler,
ST: StagesTuple<I>,
CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>,
I: Input,
{
fn scheduler(&self) -> &CS {
@ -102,25 +82,17 @@ where
}
}
impl<CS, ST, I> Fuzzer<CS, ST, I> for StdFuzzer<CS, ST, I>
impl<CS, ST, E, EM, I, OT, S> Fuzzer<E, EM, S> for StdFuzzer<CS, ST, E, EM, I, OT, S>
where
CS: CorpusScheduler,
ST: StagesTuple<I>,
CS: CorpusScheduler<I, S>,
S: HasExecutions,
ST: StagesTuple<E, EM, Self, S>,
EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
I: Input,
{
fn fuzz_one<C, E, EM, R, S>(
&self,
state: &mut S,
executor: &mut E,
manager: &mut EM,
) -> Result<usize, Error>
where
EM: EventManager<I>,
E: Executor<I>,
S: HasCorpus<C, I> + HasRand<R>,
C: Corpus<I>,
R: Rand,
{
fn fuzz_one(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result<usize, Error> {
let idx = self.scheduler().next(state)?;
self.stages()
@ -130,19 +102,7 @@ where
Ok(idx)
}
fn fuzz_loop<C, E, EM, R, S>(
&self,
state: &mut S,
executor: &mut E,
manager: &mut EM,
) -> Result<usize, Error>
where
EM: EventManager<I>,
E: Executor<I>,
S: HasCorpus<C, I> + HasRand<R> + HasExecutions,
C: Corpus<I>,
R: Rand,
{
fn fuzz_loop(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result<usize, Error> {
let mut last = current_milliseconds();
loop {
self.fuzz_one(state, executor, manager)?;
@ -162,10 +122,10 @@ where
}
}
impl<CS, ST, I> StdFuzzer<CS, ST, I>
impl<CS, ST, E, EM, I, OT, S> StdFuzzer<CS, ST, E, EM, I, OT, S>
where
CS: CorpusScheduler,
ST: StagesTuple<I>,
CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>,
I: Input,
{
pub fn new(scheduler: CS, stages: ST) -> Self {

View File

@ -5,7 +5,7 @@ use alloc::{borrow::ToOwned, rc::Rc, vec::Vec};
use core::{cell::RefCell, convert::From};
use serde::{Deserialize, Serialize};
use crate::inputs::{HasBytesVec, HasTargetBytes, HasLen, Input, TargetBytes};
use crate::inputs::{HasBytesVec, HasLen, HasTargetBytes, Input, TargetBytes};
/// A bytes input is the basic input
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)]

View File

@ -106,4 +106,3 @@ pub trait HasLen {
/// The lenght
fn len(&self) -> usize;
}

View File

@ -29,7 +29,7 @@ pub mod fuzzer;
pub use fuzzer::*;
use alloc::string::String;
use core::{fmt};
use core::fmt;
#[cfg(feature = "std")]
use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error};

View File

@ -7,32 +7,24 @@ pub use mutations::*;
pub mod token_mutations;
pub use token_mutations::*;
use crate::{
inputs::Input,
Error,
};
use crate::{inputs::Input, Error};
// TODO mutator stats method that produces something that can be sent with the NewTestcase event
// We can use it to report which mutations generated the testcase in the broker logs
/// A mutator takes input, and mutates it.
/// Simple as that.
pub trait Mutator<I>
pub trait Mutator<F, I, S>
where
I: Input,
{
/// Mutate a given input
fn mutate<F, S>(
&mut self,
fuzzer: &F,
state: &mut S,
input: &mut I,
stage_idx: i32,
) -> Result<(), Error>;
fn mutate(&self, fuzzer: &F, state: &mut S, input: &mut I, stage_idx: i32)
-> Result<(), Error>;
/// Post-process given the outcome of the execution
fn post_exec<F, S>(
&mut self,
fn post_exec(
&self,
_fuzzer: &F,
_state: &mut S,
_is_interesting: u32,

View File

@ -27,8 +27,7 @@ pub enum MutationResult {
// TODO maybe the mutator arg is not needed
/// The generic function type that identifies mutations
pub type MutationFunction<F, I, M, S> =
fn(&mut M, &F, &mut S, &mut I) -> Result<MutationResult, Error>;
pub type MutationFunction<F, I, M, S> = fn(&M, &F, &mut S, &mut I) -> Result<MutationResult, Error>;
pub trait ComposedByMutations<F, I, S>
where
@ -125,7 +124,7 @@ const INTERESTING_32: [i32; 27] = [
/// Bitflip mutation for inputs with a bytes vector
pub fn mutation_bitflip<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -148,7 +147,7 @@ where
}
pub fn mutation_byteflip<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -171,7 +170,7 @@ where
}
pub fn mutation_byteinc<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -195,7 +194,7 @@ where
}
pub fn mutation_bytedec<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -219,7 +218,7 @@ where
}
pub fn mutation_byteneg<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -242,7 +241,7 @@ where
}
pub fn mutation_byterand<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -265,7 +264,7 @@ where
}
pub fn mutation_byteadd<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -293,7 +292,7 @@ where
}
pub fn mutation_wordadd<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -323,7 +322,7 @@ where
}
pub fn mutation_dwordadd<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -353,7 +352,7 @@ where
}
pub fn mutation_qwordadd<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -383,7 +382,7 @@ where
}
pub fn mutation_byteinteresting<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -407,7 +406,7 @@ where
}
pub fn mutation_wordinteresting<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -437,7 +436,7 @@ where
}
pub fn mutation_dwordinteresting<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -467,7 +466,7 @@ where
}
pub fn mutation_bytesdelete<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -490,7 +489,7 @@ where
}
pub fn mutation_bytesexpand<F, I, M, R, S>(
mutator: &mut M,
mutator: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -520,7 +519,7 @@ where
}
pub fn mutation_bytesinsert<F, I, M, R, S>(
mutator: &mut M,
mutator: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -553,7 +552,7 @@ where
}
pub fn mutation_bytesrandinsert<F, I, M, R, S>(
mutator: &mut M,
mutator: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -586,7 +585,7 @@ where
}
pub fn mutation_bytesset<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -611,7 +610,7 @@ where
}
pub fn mutation_bytesrandset<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -636,7 +635,7 @@ where
}
pub fn mutation_bytescopy<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -661,7 +660,7 @@ where
}
pub fn mutation_bytesswap<F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -689,7 +688,7 @@ where
/// Crossover insert mutation
pub fn mutation_crossover_insert<C, F, I, M, R, S>(
mutator: &mut M,
mutator: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -704,10 +703,13 @@ where
let size = input.bytes().len();
// We don't want to use the testcase we're already using for splicing
let (other_testcase, idx) = state.random_corpus_entry()?;
if idx == state.corpus().current_testcase().1 {
let idx = state.rand_mut().below(state.corpus().count() as u64) as usize;
if let Some(cur) = state.corpus().current() {
if idx == *cur {
return Ok(MutationResult::Skipped);
}
}
let other_testcase = state.corpus().get(idx)?;
let mut other_ref = other_testcase.borrow_mut();
let other = other_ref.load_input()?;
@ -738,7 +740,7 @@ where
/// Crossover replace mutation
pub fn mutation_crossover_replace<C, F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -752,10 +754,13 @@ where
let size = input.bytes().len();
// We don't want to use the testcase we're already using for splicing
let (other_testcase, idx) = state.random_corpus_entry()?;
if idx == state.corpus().current_testcase().1 {
let idx = state.rand_mut().below(state.corpus().count() as u64) as usize;
if let Some(cur) = state.corpus().current() {
if idx == *cur {
return Ok(MutationResult::Skipped);
}
}
let other_testcase = state.corpus().get(idx)?;
let mut other_ref = other_testcase.borrow_mut();
let other = other_ref.load_input()?;
@ -792,7 +797,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
/// Splicing mutation from AFL
pub fn mutation_splice<C, F, I, M, R, S>(
_: &mut M,
_: &M,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -804,10 +809,13 @@ where
S: HasRand<R> + HasCorpus<C, I>,
{
// We don't want to use the testcase we're already using for splicing
let (other_testcase, idx) = state.random_corpus_entry()?;
if idx == state.corpus().current_testcase().1 {
let idx = state.rand_mut().below(state.corpus().count() as u64) as usize;
if let Some(cur) = state.corpus().current() {
if idx == *cur {
return Ok(MutationResult::Skipped);
}
}
let other_testcase = state.corpus().get(idx)?;
let mut other_ref = other_testcase.borrow_mut();
let other = other_ref.load_input()?;

View File

@ -15,27 +15,20 @@ use crate::{
pub use crate::mutators::mutations::*;
pub use crate::mutators::token_mutations::*;
pub trait ScheduledMutator<F, I, S>: Mutator<I> + ComposedByMutations<F, I, S>
pub trait ScheduledMutator<F, I, S>: Mutator<F, I, S> + ComposedByMutations<F, I, S>
where
I: Input,
{
/// Compute the number of iterations used to apply stacked mutations
fn iterations(&mut self, state: &mut S, input: &I) -> u64;
//{
// 1 << (1 + state.rand_mut().below(6))
//}
fn iterations(&self, state: &mut S, input: &I) -> u64;
/// Get the next mutation to apply
fn schedule(&mut self, mutations_count: usize, state: &mut S, input: &I) -> usize;
//{
// debug_assert!(mutations_count > 0);
// rand.below(mutations_count as u64) as usize
//}
fn schedule(&self, mutations_count: usize, state: &mut S, input: &I) -> usize;
/// New default implementation for mutate
/// Implementations must forward mutate() to this method
fn scheduled_mutate(
&mut self,
&self,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -50,18 +43,22 @@ where
}
}
#[derive(Clone)]
pub struct StdScheduledMutator<F, I, S>
pub struct StdScheduledMutator<F, I, R, S>
where
I: Input,
S: HasRand<R>,
R: Rand,
{
mutations: Vec<MutationFunction<F, I, Self, S>>,
max_size: usize,
phantom: PhantomData<R>,
}
impl<F, I, S> Debug for StdScheduledMutator<F, I, S>
impl<F, I, R, S> Debug for StdScheduledMutator<F, I, R, S>
where
I: Input,
S: HasRand<R>,
R: Rand,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
@ -74,12 +71,14 @@ where
}
}
impl<F, I, S> Mutator<I> for StdScheduledMutator<F, I, S>
impl<F, I, R, S> Mutator<F, I, S> for StdScheduledMutator<F, I, R, S>
where
I: Input,
S: HasRand<R>,
R: Rand,
{
fn mutate(
&mut self,
&self,
fuzzer: &F,
state: &mut S,
input: &mut I,
@ -89,9 +88,11 @@ where
}
}
impl<F, I, S> ComposedByMutations<F, I, S> for StdScheduledMutator<F, I, S>
impl<F, I, R, S> ComposedByMutations<F, I, S> for StdScheduledMutator<F, I, R, S>
where
I: Input,
S: HasRand<R>,
R: Rand,
{
#[inline]
fn mutation_by_idx(&self, index: usize) -> MutationFunction<F, I, Self, S> {
@ -109,16 +110,29 @@ where
}
}
impl<F, I, S> ScheduledMutator<F, I, S> for StdScheduledMutator<F, I, S>
impl<F, I, R, S> ScheduledMutator<F, I, S> for StdScheduledMutator<F, I, R, S>
where
I: Input,
S: HasRand<R>,
R: Rand,
{
// Just use the default methods
/// Compute the number of iterations used to apply stacked mutations
fn iterations(&self, state: &mut S, input: &I) -> u64 {
1 << (1 + state.rand_mut().below(6))
}
impl<F, I, S> HasMaxSize for StdScheduledMutator<F, I, S>
/// Get the next mutation to apply
fn schedule(&self, mutations_count: usize, state: &mut S, input: &I) -> usize {
debug_assert!(mutations_count > 0);
state.rand_mut().below(mutations_count as u64) as usize
}
}
impl<F, I, R, S> HasMaxSize for StdScheduledMutator<F, I, R, S>
where
I: Input,
S: HasRand<R>,
R: Rand,
{
#[inline]
fn max_size(&self) -> usize {
@ -131,15 +145,18 @@ where
}
}
impl<F, I, S> StdScheduledMutator<F, I, S>
impl<F, I, R, S> StdScheduledMutator<F, I, R, S>
where
I: Input,
S: HasRand<R>,
R: Rand,
{
/// Create a new StdScheduledMutator instance without mutations and corpus
pub fn new() -> Self {
Self {
mutations: vec![],
max_size: DEFAULT_MAX_SIZE,
phantom: PhantomData,
}
}
@ -148,6 +165,7 @@ where
StdScheduledMutator {
mutations: mutations,
max_size: DEFAULT_MAX_SIZE,
phantom: PhantomData,
}
}
}
@ -166,7 +184,7 @@ where
phantom: PhantomData<(C, F, I, R, S)>,
}
impl<C, F, I, R, S, SM> Mutator<I> for HavocBytesMutator<C, F, I, R, S, SM>
impl<C, F, I, R, S, SM> Mutator<F, I, S> for HavocBytesMutator<C, F, I, R, S, SM>
where
SM: ScheduledMutator<F, I, S> + HasMaxSize,
I: Input + HasBytesVec,
@ -176,8 +194,8 @@ where
{
/// Mutate bytes
fn mutate(
&mut self,
fuzzer: &mut F,
&self,
fuzzer: &F,
state: &mut S,
input: &mut I,
stage_idx: i32,
@ -246,7 +264,7 @@ where
}
}
impl<C, F, I, R, S> Default for HavocBytesMutator<C, F, I, R, S, StdScheduledMutator<F, I, S>>
impl<C, F, I, R, S> Default for HavocBytesMutator<C, F, I, R, S, StdScheduledMutator<F, I, R, S>>
where
I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
@ -255,7 +273,7 @@ where
{
/// Create a new HavocBytesMutator instance wrapping StdScheduledMutator
fn default() -> Self {
let mut scheduled = StdScheduledMutator::<F, I, S>::new();
let mut scheduled = StdScheduledMutator::<F, I, R, S>::new();
scheduled.add_mutation(mutation_bitflip);
scheduled.add_mutation(mutation_byteflip);
scheduled.add_mutation(mutation_byteinc);
@ -283,8 +301,8 @@ where
scheduled.add_mutation(mutation_bytescopy);
scheduled.add_mutation(mutation_bytesswap);
scheduled.add_mutation(mutation_tokeninsert);
scheduled.add_mutation(mutation_tokenreplace);
//scheduled.add_mutation(mutation_tokeninsert);
//scheduled.add_mutation(mutation_tokenreplace);
scheduled.add_mutation(mutation_crossover_insert);
scheduled.add_mutation(mutation_crossover_replace);

View File

@ -3,8 +3,8 @@
use crate::{
inputs::{HasBytesVec, Input},
state::{HasRand, HasMetadata},
mutators::*,
state::{HasMetadata, HasRand},
utils::Rand,
Error,
};

View File

@ -1,10 +1,7 @@
pub mod mutational;
pub use mutational::StdMutationalStage;
use crate::{
bolts::tuples::TupleList, corpus::Corpus, events::EventManager, executors::Executor,
inputs::Input, Error,
};
use crate::{bolts::tuples::TupleList, corpus::Corpus, Error};
/// A stage is one step in the fuzzing process.
/// Multiple stages will be scheduled one by one for each input.

View File

@ -1,14 +1,14 @@
use core::marker::PhantomData;
use crate::{
corpus::Corpus,
events::EventManager,
executors::Executor,
executors::{Executor, HasObservers},
inputs::Input,
mutators::Mutator,
stages::Corpus,
observers::ObserversTuple,
stages::Stage,
state::HasRand,
state::{Evaluator, HasCorpus},
state::{Evaluator, HasCorpus, HasRand},
utils::Rand,
Error,
};
@ -18,10 +18,15 @@ use crate::{
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
/// Mutational stages will usually have a range of mutations that are
/// being applied to the input one by one, between executions.
pub trait MutationalStage<I, M>: Stage<I>
pub trait MutationalStage<C, E, EM, F, I, M, OT, S>: Stage<E, EM, F, S>
where
M: Mutator<I>,
M: Mutator<F, I, S>,
I: Input,
S: HasCorpus<C, I> + Evaluator<I>,
C: Corpus<I>,
EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
{
/// The mutator registered for this stage
fn mutator(&self) -> &M;
@ -30,23 +35,17 @@ where
fn mutator_mut(&mut self) -> &mut M;
/// Gets the number of iterations this mutator should run for.
fn iterations<S>(&mut self, state: &mut S) -> usize;
fn iterations(&mut self, state: &mut S) -> usize;
/// Runs this (mutational) stage for the given testcase
fn perform_mutational<C, E, EM, F, S>(
fn perform_mutational(
&self,
fuzzer: &F,
state: &mut S,
executor: &mut E,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), Error>
where
EM: EventManager<I>,
E: Executor<I>,
S: HasCorpus<C, I> + Evaluator<I>,
C: Corpus<I>,
{
) -> Result<(), Error> {
let num = self.iterations(state);
for i in 0..num {
let mut input_mut = state
@ -71,19 +70,32 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
/// The default mutational stage
#[derive(Clone, Debug)]
pub struct StdMutationalStage<I, M>
pub struct StdMutationalStage<C, E, EM, F, I, M, OT, R, S>
where
M: Mutator<I>,
M: Mutator<F, I, S>,
I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>,
EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
R: Rand,
{
mutator: M,
phantom: PhantomData<I>,
phantom: PhantomData<(C, E, EM, F, I, OT, R, S)>,
}
impl<I, M> MutationalStage<I, M> for StdMutationalStage<I, M>
impl<C, E, EM, F, I, M, OT, R, S> MutationalStage<C, E, EM, F, I, M, OT, S>
for StdMutationalStage<C, E, EM, F, I, M, OT, R, S>
where
M: Mutator<I>,
M: Mutator<F, I, S>,
I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>,
EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
R: Rand,
{
/// The mutator, added to this stage
#[inline]
@ -98,43 +110,46 @@ where
}
/// Gets the number of iterations as a random number
fn iterations<R, S>(&mut self, state: &mut S) -> usize
where
S: HasRand<R>,
R: Rand,
{
fn iterations(&mut self, state: &mut S) -> usize {
1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize
}
}
impl<I, M> Stage<I> for StdMutationalStage<I, M>
impl<C, E, EM, F, I, M, OT, R, S> Stage<E, EM, F, S>
for StdMutationalStage<C, E, EM, F, I, M, OT, R, S>
where
M: Mutator<I>,
M: Mutator<F, I, S>,
I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>,
EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
R: Rand,
{
#[inline]
fn perform<C, E, EM, F, S>(
fn perform(
&self,
fuzzer: &F,
state: &mut S,
executor: &mut E,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), Error>
where
EM: EventManager<I>,
E: Executor<I>,
S: HasCorpus<C, I> + Evaluator<I>,
C: Corpus<I>,
{
) -> Result<(), Error> {
self.perform_mutational(fuzzer, state, executor, manager, corpus_idx)
}
}
impl<I, M> StdMutationalStage<I, M>
impl<C, E, EM, F, I, M, OT, R, S> StdMutationalStage<C, E, EM, F, I, M, OT, R, S>
where
M: Mutator<I>,
M: Mutator<F, I, S>,
I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>,
EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
R: Rand,
{
/// Creates a new default mutational stage
pub fn new(mutator: M) -> Self {

View File

@ -159,20 +159,21 @@ where
}
/// Evaluate an input modyfing the state of the fuzzer and returning a fitness
pub trait Evaluator<I>
pub trait Evaluator<I>: Sized
where
I: Input,
{
/// Runs the input and triggers observers and feedback
fn evaluate_input<E, EM>(
fn evaluate_input<E, EM, OT>(
&mut self,
input: I,
executor: &mut E,
event_mgr: &mut EM,
) -> Result<u32, Error>
where
E: Executor<I>,
EM: EventManager<I>;
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
EM: EventManager<I, Self>;
}
/// The state a fuzz run.
@ -442,7 +443,7 @@ where
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
C: Corpus<I>,
EM: EventManager<I>,
EM: EventManager<I, Self>,
{
let (fitness, is_solution) = self.execute_input(&input, executor, manager)?;
let observers = executor.observers();
@ -490,7 +491,7 @@ where
C: Corpus<BytesInput>,
E: Executor<BytesInput> + HasObservers<OT>,
OT: ObserversTuple,
EM: EventManager<BytesInput>,
EM: EventManager<BytesInput, Self>,
{
for entry in fs::read_dir(in_dir)? {
let entry = entry?;
@ -532,7 +533,7 @@ where
C: Corpus<BytesInput>,
E: Executor<BytesInput> + HasObservers<OT>,
OT: ObserversTuple,
EM: EventManager<BytesInput>,
EM: EventManager<BytesInput, Self>,
{
for in_dir in in_dirs {
self.load_from_directory(executor, manager, in_dir)?;
@ -570,7 +571,7 @@ where
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
C: Corpus<I>,
EM: EventManager<I>,
EM: EventManager<I, Self>,
{
executor.pre_exec_observers()?;
@ -606,7 +607,7 @@ where
C: Corpus<I>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
EM: EventManager<I>,
EM: EventManager<I, Self>,
{
let mut added = 0;
for _ in 0..num {

View File

@ -1,7 +1,7 @@
//! Utility functions for AFL
use core::{cell::RefCell, debug_assert, fmt::Debug, time};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use xxhash_rust::xxh3::xxh3_64_with_seed;
#[cfg(feature = "std")]