Mutational Push Stage (#356)
* initial commit for push stage * cleanup, no_std, clippy * clippy * fuzzes * readme * fmt
This commit is contained in:
parent
e914cc9c14
commit
3e85cf22de
1
fuzzers/push_stage_harness/.gitignore
vendored
Normal file
1
fuzzers/push_stage_harness/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
libpng-*
|
22
fuzzers/push_stage_harness/Cargo.toml
Normal file
22
fuzzers/push_stage_harness/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[package]
|
||||||
|
name = "push_stage_harness"
|
||||||
|
version = "0.5.0"
|
||||||
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = []
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
opt-level = 3
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libafl = { path = "../../libafl/" }
|
4
fuzzers/push_stage_harness/README.md
Normal file
4
fuzzers/push_stage_harness/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Push Stage Harness
|
||||||
|
|
||||||
|
This is a minimalistic example create a fuzzer that pulls data out of LibAFL, instead of being called by it repeatedly.
|
||||||
|
In contrast to Kloroutines, this should be reasonably sound and fast.
|
128
fuzzers/push_stage_harness/src/main.rs
Normal file
128
fuzzers/push_stage_harness/src/main.rs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
//! A fuzzer that uses a `PushStage`, generating input to be subsequently executed,
|
||||||
|
//! instead of executing input iteslf in a loop.
|
||||||
|
//! Using this method, we can add LibAFL, for example, into an emulation loop
|
||||||
|
//! or use its mutations for another fuzzer.
|
||||||
|
//! This is a less hacky alternative to the `KloRoutines` based fuzzer, that will also work on non-`Unix`.
|
||||||
|
|
||||||
|
use core::cell::{Cell, RefCell};
|
||||||
|
use std::{path::PathBuf, rc::Rc};
|
||||||
|
|
||||||
|
use libafl::{
|
||||||
|
bolts::{current_nanos, rands::StdRand, tuples::tuple_list},
|
||||||
|
corpus::{
|
||||||
|
Corpus, CorpusScheduler, InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler, Testcase,
|
||||||
|
},
|
||||||
|
events::SimpleEventManager,
|
||||||
|
executors::ExitKind,
|
||||||
|
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback},
|
||||||
|
fuzzer::StdFuzzer,
|
||||||
|
inputs::{BytesInput, HasTargetBytes},
|
||||||
|
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||||
|
observers::StdMapObserver,
|
||||||
|
stages::push::StdMutationalPushStage,
|
||||||
|
state::{HasCorpus, StdState},
|
||||||
|
stats::SimpleStats,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Coverage map with explicit assignments due to the lack of instrumentation
|
||||||
|
static mut SIGNALS: [u8; 16] = [0; 16];
|
||||||
|
|
||||||
|
/// Assign a signal to the signals map
|
||||||
|
fn signals_set(idx: usize) {
|
||||||
|
unsafe { SIGNALS[idx] = 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::similar_names)]
|
||||||
|
pub fn main() {
|
||||||
|
// Create an observation channel using the signals map
|
||||||
|
let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS });
|
||||||
|
|
||||||
|
// The state of the edges feedback.
|
||||||
|
let feedback_state = MapFeedbackState::with_observer(&observer);
|
||||||
|
|
||||||
|
// Feedback to rate the interestingness of an input
|
||||||
|
let feedback = MaxMapFeedback::<_, BytesInput, _, _, _>::new(&feedback_state, &observer);
|
||||||
|
|
||||||
|
// A feedback to choose if an input is a solution or not
|
||||||
|
let objective = CrashFeedback::new();
|
||||||
|
|
||||||
|
// create a State from scratch
|
||||||
|
let mut state = StdState::new(
|
||||||
|
// RNG
|
||||||
|
StdRand::with_seed(current_nanos()),
|
||||||
|
// Corpus that will be evolved, we keep it in memory for performance
|
||||||
|
InMemoryCorpus::new(),
|
||||||
|
// Corpus in which we store solutions (crashes in this example),
|
||||||
|
// on disk so the user can get them after stopping the fuzzer
|
||||||
|
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
|
||||||
|
// States of the feedbacks.
|
||||||
|
// They are the data related to the feedbacks that you want to persist in the State.
|
||||||
|
tuple_list!(feedback_state),
|
||||||
|
);
|
||||||
|
|
||||||
|
// The Stats trait define how the fuzzer stats are reported to the user
|
||||||
|
let stats = SimpleStats::new(|s| println!("{}", s));
|
||||||
|
|
||||||
|
// The event manager handle the various events generated during the fuzzing loop
|
||||||
|
// such as the notification of the addition of a new item to the corpus
|
||||||
|
let mgr = SimpleEventManager::new(stats);
|
||||||
|
|
||||||
|
// A queue policy to get testcasess from the corpus
|
||||||
|
let scheduler = QueueCorpusScheduler::new();
|
||||||
|
|
||||||
|
// Create the executor for an in-process function with just one observer
|
||||||
|
//let mut executor = InProcessExecutor::new(&mut harness, &mut fuzzer, &mut state, &mut mgr)
|
||||||
|
// .expect("Failed to create the Executor");
|
||||||
|
|
||||||
|
let testcase = Testcase::new(BytesInput::new(b"aaaa".to_vec()));
|
||||||
|
//self.feedback_mut().append_metadata(state, &mut testcase)?;
|
||||||
|
let idx = state.corpus_mut().add(testcase).unwrap();
|
||||||
|
scheduler.on_add(&mut state, idx).unwrap();
|
||||||
|
|
||||||
|
// A fuzzer with feedbacks and a corpus scheduler
|
||||||
|
let fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||||
|
|
||||||
|
// Generate 8 initial inputs
|
||||||
|
//state.generate_initial_inputs(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8);
|
||||||
|
// .expect("Failed to generate the initial corpus");
|
||||||
|
|
||||||
|
// Setup a mutational stage with a basic bytes mutator
|
||||||
|
let mutator = StdScheduledMutator::new(havoc_mutations());
|
||||||
|
|
||||||
|
let exit_kind = Rc::new(Cell::new(None));
|
||||||
|
|
||||||
|
let stage_idx = 0;
|
||||||
|
|
||||||
|
let observers = tuple_list!(observer);
|
||||||
|
|
||||||
|
// All fuzzer elements are hidden behind Rc<RefCell>>, so we can reuse them for multiple stages.
|
||||||
|
let push_stage = StdMutationalPushStage::new(
|
||||||
|
mutator,
|
||||||
|
Rc::new(RefCell::new(fuzzer)),
|
||||||
|
Rc::new(RefCell::new(state)),
|
||||||
|
Rc::new(RefCell::new(mgr)),
|
||||||
|
Rc::new(RefCell::new(observers)),
|
||||||
|
exit_kind.clone(),
|
||||||
|
stage_idx,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Loop, the input, getting a new entry from the push stage each iteration.
|
||||||
|
for input in push_stage {
|
||||||
|
let input = input.unwrap();
|
||||||
|
let target = input.target_bytes();
|
||||||
|
let buf = target.as_slice();
|
||||||
|
signals_set(0);
|
||||||
|
if !buf.is_empty() && buf[0] == b'a' {
|
||||||
|
signals_set(1);
|
||||||
|
if buf.len() > 1 && buf[1] == b'b' {
|
||||||
|
signals_set(2);
|
||||||
|
if buf.len() > 2 && buf[2] == b'c' {
|
||||||
|
panic!("=)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*exit_kind).replace(Some(ExitKind::Ok));
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("One iteration done.");
|
||||||
|
}
|
@ -40,7 +40,7 @@ use crate::{
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// How an execution finished.
|
/// How an execution finished.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub enum ExitKind {
|
pub enum ExitKind {
|
||||||
/// The run exited normally.
|
/// The run exited normally.
|
||||||
Ok,
|
Ok,
|
||||||
|
@ -385,7 +385,7 @@ where
|
|||||||
Event::NewTestcase {
|
Event::NewTestcase {
|
||||||
input,
|
input,
|
||||||
observers_buf,
|
observers_buf,
|
||||||
exit_kind: exit_kind.clone(),
|
exit_kind: *exit_kind,
|
||||||
corpus_size: state.corpus().count(),
|
corpus_size: state.corpus().count(),
|
||||||
client_config: manager.configuration(),
|
client_config: manager.configuration(),
|
||||||
time: current_time(),
|
time: current_time(),
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
//! This module contains the `concolic` stages, which can trace a target using symbolic execution
|
||||||
|
//! and use the results for fuzzer input and mutations.
|
||||||
|
//!
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -8,6 +8,8 @@ Other stages may enrich [`crate::corpus::Testcase`]s with metadata.
|
|||||||
pub mod mutational;
|
pub mod mutational;
|
||||||
pub use mutational::{MutationalStage, StdMutationalStage};
|
pub use mutational::{MutationalStage, StdMutationalStage};
|
||||||
|
|
||||||
|
pub mod push;
|
||||||
|
|
||||||
pub mod tracing;
|
pub mod tracing;
|
||||||
pub use tracing::{ShadowTracingStage, TracingStage};
|
pub use tracing::{ShadowTracingStage, TracingStage};
|
||||||
|
|
||||||
@ -15,7 +17,6 @@ pub mod calibrate;
|
|||||||
pub use calibrate::{CalibrationStage, PowerScheduleMetadata};
|
pub use calibrate::{CalibrationStage, PowerScheduleMetadata};
|
||||||
|
|
||||||
pub mod power;
|
pub mod power;
|
||||||
use crate::Error;
|
|
||||||
pub use power::PowerMutationalStage;
|
pub use power::PowerMutationalStage;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -25,6 +26,7 @@ pub use concolic::ConcolicTracingStage;
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use concolic::SimpleConcolicMutationalStage;
|
pub use concolic::SimpleConcolicMutationalStage;
|
||||||
|
|
||||||
|
use crate::Error;
|
||||||
/// 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<E, EM, S, Z> {
|
pub trait Stage<E, EM, S, Z> {
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
//| The [`MutationalStage`] is the default stage used during fuzzing.
|
||||||
|
//! For the current input, it will perform a range of random mutations, and then run them in the executor.
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
12
libafl/src/stages/push/mod.rs
Normal file
12
libafl/src/stages/push/mod.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
//! While normal stages call the executor over and over again, push stages turn this concept upside down:
|
||||||
|
//! A push stage instead returns an iterator that generates a new result for each time it gets called.
|
||||||
|
//! With the new testcase, you will have to take care about testcase execution, manually.
|
||||||
|
//! The push stage relies on internal muttability of the supplied `Observers`.
|
||||||
|
//!
|
||||||
|
|
||||||
|
/// Mutational stage is the normal fuzzing stage,
|
||||||
|
pub mod mutational;
|
||||||
|
pub use mutational::StdMutationalPushStage;
|
||||||
|
|
||||||
|
/// A push stage is a generator that returns a single testcase for each call.
|
||||||
|
pub trait PushStage<E, EM, S, Z>: Iterator {}
|
280
libafl/src/stages/push/mutational.rs
Normal file
280
libafl/src/stages/push/mutational.rs
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
//| The [`MutationalStage`] is the default stage used during fuzzing.
|
||||||
|
//! For the current input, it will perform a range of random mutations, and then run them in the executor.
|
||||||
|
|
||||||
|
use alloc::rc::Rc;
|
||||||
|
use core::{
|
||||||
|
borrow::BorrowMut,
|
||||||
|
cell::{Cell, RefCell},
|
||||||
|
marker::PhantomData,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bolts::{current_time, rands::Rand},
|
||||||
|
corpus::{Corpus, CorpusScheduler},
|
||||||
|
events::EventManager,
|
||||||
|
executors::ExitKind,
|
||||||
|
inputs::Input,
|
||||||
|
mark_feature_time,
|
||||||
|
mutators::Mutator,
|
||||||
|
observers::ObserversTuple,
|
||||||
|
start_timer,
|
||||||
|
state::{HasClientPerfStats, HasCorpus, HasRand},
|
||||||
|
Error, EvaluatorObservers, ExecutionProcessor, Fuzzer, HasCorpusScheduler,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "introspection")]
|
||||||
|
use crate::stats::PerfFeature;
|
||||||
|
|
||||||
|
/// Send a stats update all 15 (or more) seconds
|
||||||
|
const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
|
||||||
|
|
||||||
|
pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
|
||||||
|
|
||||||
|
/// A Mutational push stage is the stage in a fuzzing run that mutates inputs.
|
||||||
|
/// Mutational push stages will usually have a range of mutations that are
|
||||||
|
/// being applied to the input one by one, between executions.
|
||||||
|
/// The push version, in contrast to the normal stage, will return each testcase, instead of executing it.
|
||||||
|
///
|
||||||
|
/// Default value, how many iterations each stage gets, as an upper bound
|
||||||
|
/// It may randomly continue earlier.
|
||||||
|
///
|
||||||
|
/// The default mutational push stage
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct StdMutationalPushStage<C, CS, EM, I, M, OT, R, S, Z>
|
||||||
|
where
|
||||||
|
C: Corpus<I>,
|
||||||
|
CS: CorpusScheduler<I, S>,
|
||||||
|
EM: EventManager<(), I, S, Z>,
|
||||||
|
I: Input,
|
||||||
|
M: Mutator<I, S>,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
R: Rand,
|
||||||
|
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
|
||||||
|
Z: ExecutionProcessor<I, OT, S>
|
||||||
|
+ EvaluatorObservers<I, OT, S>
|
||||||
|
+ Fuzzer<(), EM, I, S, ()>
|
||||||
|
+ HasCorpusScheduler<CS, I, S>,
|
||||||
|
{
|
||||||
|
initialized: bool,
|
||||||
|
state: Rc<RefCell<S>>,
|
||||||
|
current_iter: Option<usize>,
|
||||||
|
current_corpus_idx: Option<usize>,
|
||||||
|
testcases_to_do: usize,
|
||||||
|
testcases_done: usize,
|
||||||
|
|
||||||
|
fuzzer: Rc<RefCell<Z>>,
|
||||||
|
event_mgr: Rc<RefCell<EM>>,
|
||||||
|
|
||||||
|
current_input: Option<I>, // Todo: Get rid of copy
|
||||||
|
|
||||||
|
stage_idx: i32,
|
||||||
|
|
||||||
|
mutator: M,
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
phantom: PhantomData<(C, CS, (), EM, I, R, OT, S, Z)>,
|
||||||
|
last_stats_time: Duration,
|
||||||
|
observers: Rc<RefCell<OT>>,
|
||||||
|
exit_kind: Rc<Cell<Option<ExitKind>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, CS, EM, I, M, OT, R, S, Z> StdMutationalPushStage<C, CS, EM, I, M, OT, R, S, Z>
|
||||||
|
where
|
||||||
|
C: Corpus<I>,
|
||||||
|
CS: CorpusScheduler<I, S>,
|
||||||
|
EM: EventManager<(), I, S, Z>,
|
||||||
|
I: Input,
|
||||||
|
M: Mutator<I, S>,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
R: Rand,
|
||||||
|
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
|
||||||
|
Z: ExecutionProcessor<I, OT, S>
|
||||||
|
+ EvaluatorObservers<I, OT, S>
|
||||||
|
+ Fuzzer<(), EM, I, S, ()>
|
||||||
|
+ HasCorpusScheduler<CS, I, S>,
|
||||||
|
{
|
||||||
|
/// Gets the number of iterations as a random number
|
||||||
|
#[allow(clippy::unused_self, clippy::unnecessary_wraps)] // TODO: we should put this function into a trait later
|
||||||
|
fn iterations(&self, state: &mut S, _corpus_idx: usize) -> Result<usize, Error> {
|
||||||
|
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_current_corpus_idx(&mut self, current_corpus_idx: usize) {
|
||||||
|
self.current_corpus_idx = Some(current_corpus_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new default mutational stage
|
||||||
|
fn init(&mut self) -> Result<(), Error> {
|
||||||
|
let state: &mut S = &mut (*self.state).borrow_mut();
|
||||||
|
|
||||||
|
// Find a testcase to work on, unless someone already set it
|
||||||
|
self.current_corpus_idx = Some(if let Some(corpus_idx) = self.current_corpus_idx {
|
||||||
|
corpus_idx
|
||||||
|
} else {
|
||||||
|
let fuzzer: &mut Z = &mut (*self.fuzzer).borrow_mut();
|
||||||
|
fuzzer.scheduler().next(state)?
|
||||||
|
});
|
||||||
|
|
||||||
|
self.testcases_to_do = self.iterations(state, self.current_corpus_idx.unwrap())?;
|
||||||
|
self.testcases_done = 0;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pre_exec(&mut self) -> Option<Result<I, Error>> {
|
||||||
|
let state: &mut S = &mut (*self.state).borrow_mut();
|
||||||
|
|
||||||
|
if self.testcases_done >= self.testcases_to_do {
|
||||||
|
// finished with this cicle.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
start_timer!(state);
|
||||||
|
let mut input = state
|
||||||
|
.corpus()
|
||||||
|
.get(self.current_corpus_idx.unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.borrow_mut()
|
||||||
|
.load_input()
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||||
|
|
||||||
|
start_timer!(state);
|
||||||
|
self.mutator
|
||||||
|
.mutate(state, &mut input, self.stage_idx as i32)
|
||||||
|
.unwrap();
|
||||||
|
mark_feature_time!(state, PerfFeature::Mutate);
|
||||||
|
|
||||||
|
self.current_input = Some(input.clone()); // TODO: Get rid of this
|
||||||
|
|
||||||
|
Some(Ok(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_exec(&mut self) -> Result<(), Error> {
|
||||||
|
// todo: isintersting, etc.
|
||||||
|
|
||||||
|
let state: &mut S = &mut (*self.state).borrow_mut();
|
||||||
|
|
||||||
|
let fuzzer: &mut Z = &mut (*self.fuzzer).borrow_mut();
|
||||||
|
let event_mgr: &mut EM = &mut (*self.event_mgr).borrow_mut();
|
||||||
|
let observers_refcell: &RefCell<OT> = self.observers.borrow_mut();
|
||||||
|
let observers: &mut OT = &mut observers_refcell.borrow_mut();
|
||||||
|
|
||||||
|
fuzzer.process_execution(
|
||||||
|
state,
|
||||||
|
event_mgr,
|
||||||
|
self.current_input.take().unwrap(),
|
||||||
|
observers,
|
||||||
|
&self.exit_kind.get().unwrap(),
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
start_timer!(state);
|
||||||
|
self.mutator
|
||||||
|
.post_exec(state, self.stage_idx as i32, Some(self.testcases_done))?;
|
||||||
|
mark_feature_time!(state, PerfFeature::MutatePostExec);
|
||||||
|
self.testcases_done += 1;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, CS, EM, I, M, OT, R, S, Z> Iterator for StdMutationalPushStage<C, CS, EM, I, M, OT, R, S, Z>
|
||||||
|
where
|
||||||
|
C: Corpus<I>,
|
||||||
|
CS: CorpusScheduler<I, S>,
|
||||||
|
EM: EventManager<(), I, S, Z>,
|
||||||
|
I: Input,
|
||||||
|
M: Mutator<I, S>,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
R: Rand,
|
||||||
|
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
|
||||||
|
Z: ExecutionProcessor<I, OT, S>
|
||||||
|
+ EvaluatorObservers<I, OT, S>
|
||||||
|
+ Fuzzer<(), EM, I, S, ()>
|
||||||
|
+ HasCorpusScheduler<CS, I, S>,
|
||||||
|
{
|
||||||
|
type Item = Result<I, Error>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Result<I, Error>> {
|
||||||
|
let step_success = if self.initialized {
|
||||||
|
// We already ran once
|
||||||
|
self.post_exec()
|
||||||
|
} else {
|
||||||
|
self.init() // TODO: Corpus idx
|
||||||
|
};
|
||||||
|
if let Err(err) = step_success {
|
||||||
|
//let errored = true;
|
||||||
|
return Some(Err(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
//for i in 0..num {
|
||||||
|
let ret = self.pre_exec();
|
||||||
|
if ret.is_none() {
|
||||||
|
// We're done.
|
||||||
|
self.initialized = false;
|
||||||
|
self.current_corpus_idx = None;
|
||||||
|
|
||||||
|
let state: &mut S = &mut (*self.state).borrow_mut();
|
||||||
|
//let fuzzer: &mut Z = &mut (*self.fuzzer).borrow_mut();
|
||||||
|
let event_mgr: &mut EM = &mut (*self.event_mgr).borrow_mut();
|
||||||
|
|
||||||
|
self.last_stats_time = Z::maybe_report_stats(
|
||||||
|
state,
|
||||||
|
event_mgr,
|
||||||
|
self.last_stats_time,
|
||||||
|
STATS_TIMEOUT_DEFAULT,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
//self.fuzzer.maybe_report_stats();
|
||||||
|
} else {
|
||||||
|
self.exit_kind.replace(None);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, CS, EM, I, M, OT, R, S, Z> StdMutationalPushStage<C, CS, EM, I, M, OT, R, S, Z>
|
||||||
|
where
|
||||||
|
C: Corpus<I>,
|
||||||
|
CS: CorpusScheduler<I, S>,
|
||||||
|
EM: EventManager<(), I, S, Z>,
|
||||||
|
I: Input,
|
||||||
|
M: Mutator<I, S>,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
R: Rand,
|
||||||
|
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
|
||||||
|
Z: ExecutionProcessor<I, OT, S>
|
||||||
|
+ EvaluatorObservers<I, OT, S>
|
||||||
|
+ Fuzzer<(), EM, I, S, ()>
|
||||||
|
+ HasCorpusScheduler<CS, I, S>,
|
||||||
|
{
|
||||||
|
/// Creates a new default mutational stage
|
||||||
|
pub fn new(
|
||||||
|
mutator: M,
|
||||||
|
fuzzer: Rc<RefCell<Z>>,
|
||||||
|
state: Rc<RefCell<S>>,
|
||||||
|
event_mgr: Rc<RefCell<EM>>,
|
||||||
|
observers: Rc<RefCell<OT>>,
|
||||||
|
exit_kind: Rc<Cell<Option<ExitKind>>>,
|
||||||
|
stage_idx: i32,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
mutator,
|
||||||
|
phantom: PhantomData,
|
||||||
|
initialized: false,
|
||||||
|
state,
|
||||||
|
current_iter: None,
|
||||||
|
current_corpus_idx: None, // todo
|
||||||
|
testcases_to_do: 0,
|
||||||
|
testcases_done: 0,
|
||||||
|
current_input: None,
|
||||||
|
stage_idx,
|
||||||
|
fuzzer,
|
||||||
|
event_mgr,
|
||||||
|
observers,
|
||||||
|
exit_kind,
|
||||||
|
last_stats_time: current_time(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
use core::{marker::PhantomData, mem::drop};
|
//! The tracing stage can trace the target and enrich a testcase with metadata, for example for `CmpLog`.
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus,
|
corpus::Corpus,
|
||||||
@ -63,10 +65,9 @@ where
|
|||||||
mark_feature_time!(state, PerfFeature::PreExecObservers);
|
mark_feature_time!(state, PerfFeature::PreExecObservers);
|
||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
drop(
|
let _ = self
|
||||||
self.tracer_executor
|
.tracer_executor
|
||||||
.run_target(fuzzer, state, manager, &input)?,
|
.run_target(fuzzer, state, manager, &input)?;
|
||||||
);
|
|
||||||
mark_feature_time!(state, PerfFeature::TargetExecution);
|
mark_feature_time!(state, PerfFeature::TargetExecution);
|
||||||
|
|
||||||
*state.executions_mut() += 1;
|
*state.executions_mut() += 1;
|
||||||
@ -145,7 +146,7 @@ where
|
|||||||
mark_feature_time!(state, PerfFeature::PreExecObservers);
|
mark_feature_time!(state, PerfFeature::PreExecObservers);
|
||||||
|
|
||||||
start_timer!(state);
|
start_timer!(state);
|
||||||
drop(executor.run_target(fuzzer, state, manager, &input)?);
|
let _ = executor.run_target(fuzzer, state, manager, &input)?;
|
||||||
mark_feature_time!(state, PerfFeature::TargetExecution);
|
mark_feature_time!(state, PerfFeature::TargetExecution);
|
||||||
|
|
||||||
*state.executions_mut() += 1;
|
*state.executions_mut() += 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user