Associated types for Corpus, State (#767)

* Associated types for Corpus, State

* cleanup

* fix no_std

* drop unused clauses

* Corpus

* cleanup

* adding things

* fixed fuzzer

* remove phantom data

* python

* progress?

* more more

* oof

* wow it builds?

* python fixes, tests

* fix python fun

* black fmt for python

* clippy, added Nop things

* fixes

* fix merge

* make it compile (#836)

* doc-test fixes, prelude-b-gone for cargo-hack compat

* fixes for windows, concolic

* really fix windows, maybe

* imagine using windows

* ...

* elide I generic when used with S: State

* Elide many, many generics, but at what cost?

* progress on push

* Constraint HasCorpus, HasSolutions at trait definition

* remove unused feature

* remove unstable usage since we constrained HasCorpus at definition

* compiled, but still no type inference for MaxMapFeedback

* cleanup inprocess

* resolve some std conflicts

* simplify map

* undo unnecessary cfg specification

* fix breaking test case for CI on no-std

* fix concolic build failures

* fix macos build

* fixes for windows build

* timeout fixes for windows build

* fix pybindings issues

* fixup qemu

* fix outstanding local build issues

* maybe fix windows inprocess

* doc fixes

* unbridled fury

* de-associate State from Feedback, replace with generic as AT inference is not sufficient to derive specialisation for MapFeedback

* merge update

* refactor + speed up fuzzer builds by sharing build work

* cleanup lingering compiler errors

* lol missed one

* revert QEMU-Nyx change, not sure how I did that

* move HasInput to inputs

* HasInput => KnowsInput

* update bounds to enforce via associated types

* disentangle observers with fuzzer

* revert --target; update some fuzzers to match new API

* resolve outstanding fuzzer build blockers (that I can run on my system)

* fixes for non-linux unixes

* fix for windows

* Knows => Uses, final fixes for windows

* <guttural screaming>

* fixes for concolic

* loosen bound for frida executor so windows builds correctly

* cleanup generics for eventmanager/eventprocessor to drop observers requirement

* improve inference over fuzz_one and friends

* update migration notes

* fixes for python bindings

* fixes for generic counts in event managers

* finish migration notes

* post-merge fix

Co-authored-by: Addison Crump <addison.crump@cispa.de>
This commit is contained in:
Dominik Maier 2022-10-24 03:22:26 +02:00 committed by GitHub
parent 9695ce0029
commit 663a33168e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 4079 additions and 3135 deletions

View File

@ -2,8 +2,7 @@ use libafl;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use libafl_qemu; use libafl_qemu;
use libafl_sugar; use libafl_sugar;
use pyo3::prelude::*; use pyo3::{prelude::*, types::PyDict};
use pyo3::types::PyDict;
const LIBAFL_CODE: &str = r#" const LIBAFL_CODE: &str = r#"
class BaseObserver: class BaseObserver:

View File

@ -1,30 +1,38 @@
from pylibafl.libafl import * from pylibafl.libafl import *
import ctypes import ctypes
class FooObserver(BaseObserver): class FooObserver(BaseObserver):
def __init__(self): def __init__(self):
self.n = 0 self.n = 0
def name(self): def name(self):
return "Foo" return "Foo"
def pre_exec(self, state, input): def pre_exec(self, state, input):
if self.n % 10000 == 0: if self.n % 10000 == 0:
print("FOO!", self.n, input) print("FOO!", self.n, input)
self.n += 1 self.n += 1
class FooFeedback(BaseFeedback): class FooFeedback(BaseFeedback):
def is_interesting(self, state, mgr, input, observers, exit_kind): def is_interesting(self, state, mgr, input, observers, exit_kind):
ob = observers.match_name("Foo").unwrap_py() ob = observers.match_name("Foo").unwrap_py()
return ob.n % 10000 == 0 return ob.n % 10000 == 0
class FooExecutor(BaseExecutor): class FooExecutor(BaseExecutor):
def __init__(self, harness, observers: ObserversTuple): def __init__(self, harness, observers: ObserversTuple):
self.h = harness self.h = harness
self.o = observers self.o = observers
def observers(self): def observers(self):
return self.o return self.o
def run_target(self, fuzzer, state, mgr, input) -> ExitKind: def run_target(self, fuzzer, state, mgr, input) -> ExitKind:
return (self.h)(input) return (self.h)(input)
libc = ctypes.cdll.LoadLibrary("libc.so.6") libc = ctypes.cdll.LoadLibrary("libc.so.6")
area_ptr = libc.calloc(1, 4096) area_ptr = libc.calloc(1, 4096)
@ -33,34 +41,46 @@ observer = StdMapObserverI8("mymap", area_ptr, 4096)
m = observer.as_map_observer() m = observer.as_map_observer()
observers = ObserversTuple([observer.as_map_observer().as_observer(), FooObserver().as_observer()]) observers = ObserversTuple(
[observer.as_map_observer().as_observer(), FooObserver().as_observer()]
)
feedback = feedback_or(MaxMapFeedbackI8(m).as_feedback(), FooFeedback().as_feedback()) feedback = feedback_or(MaxMapFeedbackI8(m).as_feedback(), FooFeedback().as_feedback())
objective = feedback_and_fast(CrashFeedback().as_feedback(), MaxMapFeedbackI8(m).as_feedback()) objective = feedback_and_fast(
CrashFeedback().as_feedback(), MaxMapFeedbackI8(m).as_feedback()
)
fuzzer = StdFuzzer(feedback, objective) fuzzer = StdFuzzer(feedback, objective)
rand = StdRand.with_current_nanos() rand = StdRand.with_current_nanos()
state = StdState(rand.as_rand(), InMemoryCorpus().as_corpus(), InMemoryCorpus().as_corpus(), feedback, objective) state = StdState(
rand.as_rand(),
InMemoryCorpus().as_corpus(),
InMemoryCorpus().as_corpus(),
feedback,
objective,
)
monitor = SimpleMonitor(lambda s: print(s)) monitor = SimpleMonitor(lambda s: print(s))
mgr = SimpleEventManager(monitor.as_monitor()) mgr = SimpleEventManager(monitor.as_monitor())
def harness(buf) -> ExitKind: def harness(buf) -> ExitKind:
#print(buf) # print(buf)
m[0] = 1 m[0] = 1
if len(buf) > 0 and buf[0] == ord('a'): if len(buf) > 0 and buf[0] == ord("a"):
m[1] = 1 m[1] = 1
if len(buf) > 1 and buf[1] == ord('b'): if len(buf) > 1 and buf[1] == ord("b"):
m[2] = 1 m[2] = 1
if len(buf) > 2 and buf[2] == ord('c'): if len(buf) > 2 and buf[2] == ord("c"):
m[3] = 1 m[3] = 1
return ExitKind.crash() return ExitKind.crash()
return ExitKind.ok() return ExitKind.ok()
# executor = InProcessExecutor(harness, observers, fuzzer, state, mgr.as_manager()) # executor = InProcessExecutor(harness, observers, fuzzer, state, mgr.as_manager())
executor = FooExecutor(harness, observers) executor = FooExecutor(harness, observers)
@ -69,6 +89,6 @@ stage = StdMutationalStage(StdHavocMutator().as_mutator())
stage_tuple_list = StagesTuple([stage.as_stage()]) stage_tuple_list = StagesTuple([stage.as_stage()])
fuzzer.add_input(state, executor.as_executor(), mgr.as_manager(), b'\0\0') fuzzer.add_input(state, executor.as_executor(), mgr.as_manager(), b"\0\0")
fuzzer.fuzz_loop(executor.as_executor(), state, mgr.as_manager(), stage_tuple_list) fuzzer.fuzz_loop(executor.as_executor(), state, mgr.as_manager(), stage_tuple_list)

View File

@ -0,0 +1,161 @@
# Migrating from libafl <0.9 to 0.9
Internal APIs of libafl have changed in version 0.9 to prefer associated types in cases where components were "fixed" to
particular versions of other components. As a result, many existing custom components will not be compatible between
versions prior to 0.9 and version 0.9.
## Reasons for this change
When implementing a trait with a generic, it is possible to have more than one instantiation of that generic trait. As a
result, everywhere where consistency across generic types was required to implement a trait, it needed to be properly
and explicitly constrained at every point. This led to `impl`s which were at best difficult to debug and, at worst,
incorrect and caused confusing bugs for users.
For example, consider the MapCorpusMinimizer implementation (from <0.9) below:
```rust
impl<E, I, O, S, TS> CorpusMinimizer<I, S> for MapCorpusMinimizer<E, I, O, S, TS>
where
E: Copy + Hash + Eq,
I: Input,
for<'a> O: MapObserver<Entry = E> + AsIter<'a, Item = E>,
S: HasMetadata + HasCorpus<I>,
TS: TestcaseScore<I, S>,
{
fn minimize<CS, EX, EM, OT, Z>(
&self,
fuzzer: &mut Z,
executor: &mut EX,
manager: &mut EM,
state: &mut S,
) -> Result<(), Error>
where
CS: Scheduler<I, S>,
EX: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
EM: EventManager<EX, I, S, Z>,
OT: ObserversTuple<S>,
Z: Evaluator<EX, EM, I, S> + HasScheduler<CS, I, S>,
{
// --- SNIP ---
}
}
```
It was previously necessary to constrain every generic using a slew of other generics; above, it is necessary to
constrain the input type (`I`) for every generic, despite the fact that this was already made clear by the state (`S`)
and that the input will necessarily be the same over every implementation for that type.
Below is the same code, but with the associated types changes (note that some generic names have changed):
```rust
impl<E, O, T, TS> CorpusMinimizer<E> for MapCorpusMinimizer<E, O, T, TS>
where
E: UsesState,
for<'a> O: MapObserver<Entry = T> + AsIter<'a, Item = T>,
E::State: HasMetadata + HasCorpus,
T: Copy + Hash + Eq,
TS: TestcaseScore<E::State>,
{
fn minimize<CS, EM, Z>(
&self,
fuzzer: &mut Z,
executor: &mut E,
manager: &mut EM,
state: &mut E::State,
) -> Result<(), Error>
where
E: Executor<EM, Z> + HasObservers,
CS: Scheduler<State=E::State>,
EM: UsesState<State=E::State>,
Z: HasScheduler<CS, State=E::State>,
{
// --- SNIP ---
}
}
```
The executor is constrained to `EM` and `Z`, with each of their respective states being constrained to `E`'s state. It
is no longer necessary to explicitly defined a generic for the input type, the state type, or the generic type, as these
are all present as associated types for `E`. Additionally, we don't even need to specify any details about the observers
(`OT` in the previous version) as the type does not need to be constrained and is not shared by other types.
## Scope
You are affected by this change if:
- You specified explicit generics for a type (e.g., `MaxMapFeedback::<_, (), _>::new(...)`)
- You implemented a custom component (e.g., `Mutator`, `Executor`, `State`, `Fuzzer`, `Feedback`, `Observer`, etc.)
If you did neither of these, congrats! You are likely unaffected by these changes.
### Migrating explicit generics
Migrating specific generics should be a quite simple process; you should review the API documentation for details on the
order of generics and replace them accordingly. Generally speaking, it should no longer be necessary to specify these
generics.
See `fuzzers/` for examples of these changes.
### Migrating component types
If you implemented a Mutator, Executor, State, or another kind of component, you must update your implementation. The
main changes to the API are in the use of "Uses*" for associated types.
In many scenarios, Input, Observers, and State generics have been moved into traits with associated types (namely,
"UsesInput", "UsesObservers", and "UsesState". These traits are required for many existing traits now and are very
straightforward to implement. In a majority of cases, you will have generics on your custom implementation or a fixed
type to implement this with. Thankfully, Rust will let you know when you need to implement this type.
As an example, InMemoryCorpus before 0.9 looked like this:
```rust
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct InMemoryCorpus<I>
where
I: Input,
{
entries: Vec<RefCell<Testcase<I>>>,
current: Option<usize>,
}
impl<I> Corpus<I> for InMemoryCorpus<I>
where
I: Input,
{
// --- SNIP ---
}
```
After 0.9, all `Corpus` implementations are required to implement `UsesInput` and `Corpus` no longer has a generic for
the input type (as it is now provided by the UsesInput impl). The migrated implementation is shown below:
```rust
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct InMemoryCorpus<I>
where
I: Input,
{
entries: Vec<RefCell<Testcase<I>>>,
current: Option<usize>,
}
impl<I> UsesInput for InMemoryCorpus<I>
where
I: Input,
{
type Input = I;
}
impl<I> Corpus for InMemoryCorpus<I>
where
I: Input,
{
// --- SNIP ---
}
```
Now, `Corpus` cannot be accidentally implemented for another type other than that specified by `InMemoryCorpus`, as it
is fixed to the associated type for `UsesInput`.
A more complex example of migration can be found in the "Reasons for this change" section of this document.

View File

@ -1,6 +1,6 @@
# Backtrace baby fuzzers # Backtrace baby fuzzers
The projects contained in this directory are simple fuzzers derived from the original baby_fuzzer examples, whose perpose is to show how to use a `BacktraceObserver` or an `ASANObserver` to dedupe crashes and other necessary component for this feature. The projects contained in this directory are simple fuzzers derived from the original baby_fuzzer examples, whose purpose is to show how to use a `BacktraceObserver` or an `ASANObserver` to dedupe crashes and other necessary components for this feature.
The examples cover: The examples cover:

View File

@ -58,10 +58,7 @@ pub fn main() {
let mut feedback = MaxMapFeedback::new(&observer); let mut feedback = MaxMapFeedback::new(&observer);
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let mut objective = feedback_and!( let mut objective = feedback_and!(CrashFeedback::new(), NewHashFeedback::new(&bt_observer));
CrashFeedback::new(),
NewHashFeedback::<BacktraceObserver>::new(&bt_observer)
);
// create a State from scratch // create a State from scratch
let mut state = StdState::new( let mut state = StdState::new(

View File

@ -48,10 +48,7 @@ pub fn main() {
let mut feedback = MaxMapFeedback::new(&observer); let mut feedback = MaxMapFeedback::new(&observer);
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let mut objective = feedback_and!( let mut objective = feedback_and!(CrashFeedback::new(), NewHashFeedback::new(&bt_observer));
CrashFeedback::new(),
NewHashFeedback::<BacktraceObserver>::new(&bt_observer)
);
// create a State from scratch // create a State from scratch
let mut state = StdState::new( let mut state = StdState::new(

View File

@ -3,7 +3,7 @@ use std::env;
fn main() { fn main() {
let cwd = env::current_dir().unwrap().to_string_lossy().to_string(); let cwd = env::current_dir().unwrap().to_string_lossy().to_string();
let mut cmd = cc::Build::new().get_compiler().to_command(); let mut cmd = cc::Build::new().get_compiler().to_command();
cmd.args(&["src/test_command.c", "-o"]) cmd.args(["src/test_command.c", "-o"])
.arg(&format!("{}/test_command", &cwd)) .arg(&format!("{}/test_command", &cwd))
.arg("-fsanitize=address") .arg("-fsanitize=address")
.status() .status()

View File

@ -46,10 +46,7 @@ pub fn main() {
let mut feedback = MaxMapFeedback::new(&observer); let mut feedback = MaxMapFeedback::new(&observer);
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let mut objective = feedback_and!( let mut objective = feedback_and!(CrashFeedback::new(), NewHashFeedback::new(&bt_observer));
CrashFeedback::new(),
NewHashFeedback::<AsanBacktraceObserver>::new(&bt_observer)
);
// let mut objective = CrashFeedback::new(); // let mut objective = CrashFeedback::new();
// create a State from scratch // create a State from scratch
@ -93,7 +90,7 @@ pub fn main() {
let mut command = Command::new("./test_command"); let mut command = Command::new("./test_command");
let command = command let command = command
.args(&[self.shmem_id.as_str()]) .args([self.shmem_id.as_str()])
.env("ASAN_OPTIONS", get_asan_runtime_flags()); .env("ASAN_OPTIONS", get_asan_runtime_flags());
command command

View File

@ -32,13 +32,13 @@ fn main() {
if !afl_gcc_path.is_file() { if !afl_gcc_path.is_file() {
Command::new("make") Command::new("make")
.arg("all") .arg("all")
.current_dir(&afl_path) .current_dir(afl_path)
.status() .status()
.unwrap(); .unwrap();
} }
Command::new(afl_gcc_path) Command::new(afl_gcc_path)
.args(&["src/program.c", "-o"]) .args(["src/program.c", "-o"])
.arg(&format!("{}/target/release/program", &cwd)) .arg(&format!("{}/target/release/program", &cwd))
.arg("-fsanitize=address") .arg("-fsanitize=address")
.status() .status()

View File

@ -77,10 +77,7 @@ pub fn main() {
let mut feedback = MaxMapFeedback::new(&observer); let mut feedback = MaxMapFeedback::new(&observer);
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let mut objective = feedback_and!( let mut objective = feedback_and!(CrashFeedback::new(), NewHashFeedback::new(&bt_observer));
CrashFeedback::new(),
NewHashFeedback::<BacktraceObserver>::new(&bt_observer)
);
// create a State from scratch // create a State from scratch
let mut state = StdState::new( let mut state = StdState::new(

View File

@ -71,10 +71,7 @@ pub fn main() {
let mut feedback = MaxMapFeedback::new(&observer); let mut feedback = MaxMapFeedback::new(&observer);
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let mut objective = feedback_and!( let mut objective = feedback_and!(CrashFeedback::new(), NewHashFeedback::new(&bt_observer));
CrashFeedback::new(),
NewHashFeedback::<BacktraceObserver>::new(&bt_observer)
);
// create a State from scratch // create a State from scratch
let mut state = StdState::new( let mut state = StdState::new(

View File

@ -117,7 +117,7 @@ pub fn main() {
// Must be a crash // Must be a crash
CrashFeedback::new(), CrashFeedback::new(),
// Take it onlt if trigger new coverage over crashes // Take it onlt if trigger new coverage over crashes
MaxMapFeedback::<_, _, _, u8>::new(&edges_observer) MaxMapFeedback::new(&edges_observer)
); );
// create a State from scratch // create a State from scratch

View File

@ -75,9 +75,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> {
let shmem_provider = StdShMemProvider::new()?; let shmem_provider = StdShMemProvider::new()?;
let mut run_client = |state: Option<_>, let mut run_client = |state: Option<_>, mgr: LlmpRestartingEventManager<_, _>, core_id| {
mgr: LlmpRestartingEventManager<_, _, _, _>,
core_id| {
// The restarting state will spawn the same process again as child, then restarted it each time it crashes. // The restarting state will spawn the same process again as child, then restarted it each time it crashes.
// println!("{:?}", mgr.mgr_id()); // println!("{:?}", mgr.mgr_id());
@ -95,7 +93,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> {
}; };
if options.asan && options.asan_cores.contains(core_id) { if options.asan && options.asan_cores.contains(core_id) {
(|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| {
let gum = Gum::obtain(); let gum = Gum::obtain();
let coverage = CoverageRuntime::new(); let coverage = CoverageRuntime::new();
@ -220,7 +218,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> {
Ok(()) Ok(())
})(state, mgr, core_id) })(state, mgr, core_id)
} else if options.cmplog && options.cmplog_cores.contains(core_id) { } else if options.cmplog && options.cmplog_cores.contains(core_id) {
(|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| {
let gum = Gum::obtain(); let gum = Gum::obtain();
let coverage = CoverageRuntime::new(); let coverage = CoverageRuntime::new();
@ -354,7 +352,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> {
Ok(()) Ok(())
})(state, mgr, core_id) })(state, mgr, core_id)
} else { } else {
(|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| {
let gum = Gum::obtain(); let gum = Gum::obtain();
let coverage = CoverageRuntime::new(); let coverage = CoverageRuntime::new();

View File

@ -69,9 +69,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> {
let shmem_provider = StdShMemProvider::new()?; let shmem_provider = StdShMemProvider::new()?;
let mut run_client = |state: Option<_>, let mut run_client = |state: Option<_>, mgr: LlmpRestartingEventManager<_, _>, core_id| {
mgr: LlmpRestartingEventManager<_, _, _, _>,
core_id| {
// The restarting state will spawn the same process again as child, then restarted it each time it crashes. // The restarting state will spawn the same process again as child, then restarted it each time it crashes.
// println!("{:?}", mgr.mgr_id()); // println!("{:?}", mgr.mgr_id());
@ -89,7 +87,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> {
}; };
if options.asan && options.asan_cores.contains(core_id) { if options.asan && options.asan_cores.contains(core_id) {
(|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| {
let gum = Gum::obtain(); let gum = Gum::obtain();
let coverage = CoverageRuntime::new(); let coverage = CoverageRuntime::new();
@ -214,7 +212,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> {
Ok(()) Ok(())
})(state, mgr, core_id) })(state, mgr, core_id)
} else if options.cmplog && options.cmplog_cores.contains(core_id) { } else if options.cmplog && options.cmplog_cores.contains(core_id) {
(|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| {
let gum = Gum::obtain(); let gum = Gum::obtain();
let coverage = CoverageRuntime::new(); let coverage = CoverageRuntime::new();
@ -348,7 +346,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> {
Ok(()) Ok(())
})(state, mgr, core_id) })(state, mgr, core_id)
} else { } else {
(|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| {
let gum = Gum::obtain(); let gum = Gum::obtain();
let coverage = CoverageRuntime::new(); let coverage = CoverageRuntime::new();

View File

@ -4,13 +4,13 @@ use mimalloc::MiMalloc;
#[global_allocator] #[global_allocator]
static GLOBAL: MiMalloc = MiMalloc; static GLOBAL: MiMalloc = MiMalloc;
use clap::{self, Parser};
use std::{ use std::{
env, env,
path::PathBuf, path::PathBuf,
process::{Child, Command, Stdio}, process::{Child, Command, Stdio},
}; };
use clap::{self, Parser};
use libafl::{ use libafl::{
bolts::{ bolts::{
current_nanos, current_nanos,
@ -48,7 +48,6 @@ use libafl::{
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
Error, Error,
}; };
use libafl_targets::{ use libafl_targets::{
libfuzzer_initialize, libfuzzer_test_one_input, CmpLogObserver, CMPLOG_MAP, EDGES_MAP, libfuzzer_initialize, libfuzzer_test_one_input, CmpLogObserver, CMPLOG_MAP, EDGES_MAP,
MAX_EDGES_NUM, MAX_EDGES_NUM,
@ -116,7 +115,6 @@ fn fuzz(
let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog = unsafe { &mut CMPLOG_MAP };
let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true);
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
@ -144,7 +142,8 @@ fn fuzz(
&mut feedback, &mut feedback,
// Same for objective feedbacks // Same for objective feedbacks
&mut objective, &mut objective,
).unwrap() )
.unwrap()
}); });
println!("We're a client, let's fuzz :)"); println!("We're a client, let's fuzz :)");

View File

@ -60,7 +60,7 @@ fn main() {
corpus corpus
.add(Testcase::new(input)) .add(Testcase::new(input))
.expect("error in adding corpus"); .expect("error in adding corpus");
let solutions = OnDiskCorpus::<BytesInput>::new(PathBuf::from("./crashes")).unwrap(); let solutions = OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap();
// libafl stuff // libafl stuff
let mut feedback = MaxMapFeedback::new(&observer); let mut feedback = MaxMapFeedback::new(&observer);

View File

@ -48,7 +48,7 @@ fn main() {
// let monitor = SimpleMonitor::new(|x|-> () {println!("{}",x)}); // let monitor = SimpleMonitor::new(|x|-> () {println!("{}",x)});
let monitor = TuiMonitor::new("test_fuzz".to_string(), true); let monitor = TuiMonitor::new("test_fuzz".to_string(), true);
let mut mgr: SimpleEventManager<BytesInput, _, _> = SimpleEventManager::new(monitor); let mut mgr = SimpleEventManager::new(monitor);
let mut executor = NyxExecutor::new(&mut helper, tuple_list!(observer)).unwrap(); let mut executor = NyxExecutor::new(&mut helper, tuple_list!(observer)).unwrap();
let mutator = StdScheduledMutator::new(havoc_mutations()); let mutator = StdScheduledMutator::new(havoc_mutations());
let mut stages = tuple_list!(StdMutationalStage::new(mutator)); let mut stages = tuple_list!(StdMutationalStage::new(mutator));

View File

@ -37,7 +37,7 @@ pub fn main() {
let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS });
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
let mut feedback = MaxMapFeedback::<BytesInput, _, _, _>::new(&observer); let mut feedback = MaxMapFeedback::new(&observer);
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let mut objective = CrashFeedback::new(); let mut objective = CrashFeedback::new();
@ -47,7 +47,7 @@ pub fn main() {
// RNG // RNG
StdRand::with_seed(current_nanos()), StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance // Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(), InMemoryCorpus::<BytesInput>::new(),
// Corpus in which we store solutions (crashes in this example), // Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer // on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),

View File

@ -4,6 +4,7 @@ use libafl::{
events::EventFirer, events::EventFirer,
executors::ExitKind, executors::ExitKind,
feedbacks::{Feedback, MapIndexesMetadata}, feedbacks::{Feedback, MapIndexesMetadata},
inputs::UsesInput,
observers::ObserversTuple, observers::ObserversTuple,
schedulers::{MinimizerScheduler, TestcaseScore}, schedulers::{MinimizerScheduler, TestcaseScore},
state::{HasClientPerfMonitor, HasCorpus, HasMetadata}, state::{HasClientPerfMonitor, HasCorpus, HasMetadata},
@ -20,9 +21,9 @@ pub struct PacketLenMetadata {
pub struct PacketLenTestcaseScore {} pub struct PacketLenTestcaseScore {}
impl<S> TestcaseScore<PacketData, S> for PacketLenTestcaseScore impl<S> TestcaseScore<S> for PacketLenTestcaseScore
where where
S: HasCorpus<PacketData> + HasMetadata, S: HasCorpus<Input = PacketData> + HasMetadata,
{ {
fn compute(entry: &mut Testcase<PacketData>, _state: &S) -> Result<f64, Error> { fn compute(entry: &mut Testcase<PacketData>, _state: &S) -> Result<f64, Error> {
Ok(entry Ok(entry
@ -32,17 +33,17 @@ where
} }
} }
pub type PacketLenMinimizerScheduler<CS, S> = pub type PacketLenMinimizerScheduler<CS> =
MinimizerScheduler<CS, PacketLenTestcaseScore, PacketData, MapIndexesMetadata, S>; MinimizerScheduler<CS, PacketLenTestcaseScore, MapIndexesMetadata>;
#[derive(Serialize, Deserialize, Default, Clone, Debug)] #[derive(Serialize, Deserialize, Default, Clone, Debug)]
pub struct PacketLenFeedback { pub struct PacketLenFeedback {
len: u64, len: u64,
} }
impl<S> Feedback<PacketData, S> for PacketLenFeedback impl<S> Feedback<S> for PacketLenFeedback
where where
S: HasClientPerfMonitor, S: UsesInput<Input = PacketData> + HasClientPerfMonitor,
{ {
#[inline] #[inline]
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
@ -54,8 +55,8 @@ where
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<PacketData>, EM: EventFirer<State = S>,
OT: ObserversTuple<PacketData, S>, OT: ObserversTuple<S>,
{ {
self.len = input.length; self.len = input.length;
Ok(false) Ok(false)

View File

@ -4,6 +4,7 @@ use libafl::{
rands::{Rand, StdRand}, rands::{Rand, StdRand},
tuples::Named, tuples::Named,
}, },
inputs::UsesInput,
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
state::HasRand, state::HasRand,
Error, Error,
@ -15,7 +16,10 @@ pub struct LainMutator {
inner: lain::mutator::Mutator<StdRand>, inner: lain::mutator::Mutator<StdRand>,
} }
impl<S: HasRand> Mutator<PacketData, S> for LainMutator { impl<S> Mutator<S> for LainMutator
where
S: UsesInput<Input = PacketData> + HasRand,
{
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,

View File

@ -33,13 +33,13 @@ use crate::bolts::core_affinity::CoreId;
use crate::bolts::os::startable_self; use crate::bolts::os::startable_self;
#[cfg(all(unix, feature = "std", feature = "fork"))] #[cfg(all(unix, feature = "std", feature = "fork"))]
use crate::bolts::os::{dup2, fork, ForkResult}; use crate::bolts::os::{dup2, fork, ForkResult};
use crate::inputs::UsesInput;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::{ use crate::{
bolts::{core_affinity::Cores, shmem::ShMemProvider}, bolts::{core_affinity::Cores, shmem::ShMemProvider},
events::{EventConfig, LlmpRestartingEventManager, ManagerKind, RestartingMgr}, events::{EventConfig, LlmpRestartingEventManager, ManagerKind, RestartingMgr},
inputs::Input,
monitors::Monitor, monitors::Monitor,
observers::ObserversTuple, state::{HasClientPerfMonitor, HasExecutions},
Error, Error,
}; };
@ -49,14 +49,13 @@ const _AFL_LAUNCHER_CLIENT: &str = "AFL_LAUNCHER_CLIENT";
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[derive(TypedBuilder)] #[derive(TypedBuilder)]
#[allow(clippy::type_complexity, missing_debug_implementations)] #[allow(clippy::type_complexity, missing_debug_implementations)]
pub struct Launcher<'a, CF, I, MT, OT, S, SP> pub struct Launcher<'a, CF, MT, S, SP>
where where
CF: FnOnce(Option<S>, LlmpRestartingEventManager<I, OT, S, SP>, usize) -> Result<(), Error>, CF: FnOnce(Option<S>, LlmpRestartingEventManager<S, SP>, usize) -> Result<(), Error>,
I: Input + 'a, S::Input: 'a,
MT: Monitor, MT: Monitor,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
OT: ObserversTuple<I, S> + 'a, S: DeserializeOwned + UsesInput + 'a,
S: DeserializeOwned + 'a,
{ {
/// The ShmemProvider to use /// The ShmemProvider to use
shmem_provider: SP, shmem_provider: SP,
@ -86,17 +85,15 @@ where
#[builder(default = true)] #[builder(default = true)]
spawn_broker: bool, spawn_broker: bool,
#[builder(setter(skip), default = PhantomData)] #[builder(setter(skip), default = PhantomData)]
phantom_data: PhantomData<(&'a I, &'a OT, &'a S, &'a SP)>, phantom_data: PhantomData<(&'a S, &'a SP)>,
} }
impl<CF, I, MT, OT, S, SP> Debug for Launcher<'_, CF, I, MT, OT, S, SP> impl<CF, MT, S, SP> Debug for Launcher<'_, CF, MT, S, SP>
where where
CF: FnOnce(Option<S>, LlmpRestartingEventManager<I, OT, S, SP>, usize) -> Result<(), Error>, CF: FnOnce(Option<S>, LlmpRestartingEventManager<S, SP>, usize) -> Result<(), Error>,
I: Input,
OT: ObserversTuple<I, S> + DeserializeOwned,
MT: Monitor + Clone, MT: Monitor + Clone,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
S: DeserializeOwned, S: DeserializeOwned + UsesInput,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Launcher") f.debug_struct("Launcher")
@ -111,14 +108,12 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<'a, CF, I, MT, OT, S, SP> Launcher<'a, CF, I, MT, OT, S, SP> impl<'a, CF, MT, S, SP> Launcher<'a, CF, MT, S, SP>
where where
CF: FnOnce(Option<S>, LlmpRestartingEventManager<I, OT, S, SP>, usize) -> Result<(), Error>, CF: FnOnce(Option<S>, LlmpRestartingEventManager<S, SP>, usize) -> Result<(), Error>,
I: Input,
OT: ObserversTuple<I, S> + DeserializeOwned,
MT: Monitor + Clone, MT: Monitor + Clone,
S: DeserializeOwned + UsesInput + HasExecutions + HasClientPerfMonitor,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
S: DeserializeOwned,
{ {
/// Launch the broker and the clients and fuzz /// Launch the broker and the clients and fuzz
#[cfg(all(unix, feature = "std", feature = "fork"))] #[cfg(all(unix, feature = "std", feature = "fork"))]
@ -175,7 +170,7 @@ where
} }
// Fuzzer client. keeps retrying the connection to broker till the broker starts // Fuzzer client. keeps retrying the connection to broker till the broker starts
let (state, mgr) = RestartingMgr::<I, MT, OT, S, SP>::builder() let (state, mgr) = RestartingMgr::<MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone()) .shmem_provider(self.shmem_provider.clone())
.broker_port(self.broker_port) .broker_port(self.broker_port)
.kind(ManagerKind::Client { .kind(ManagerKind::Client {
@ -198,7 +193,7 @@ where
println!("I am broker!!."); println!("I am broker!!.");
// TODO we don't want always a broker here, think about using different laucher process to spawn different configurations // TODO we don't want always a broker here, think about using different laucher process to spawn different configurations
RestartingMgr::<I, MT, OT, S, SP>::builder() RestartingMgr::<MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone()) .shmem_provider(self.shmem_provider.clone())
.monitor(Some(self.monitor.clone())) .monitor(Some(self.monitor.clone()))
.broker_port(self.broker_port) .broker_port(self.broker_port)
@ -245,7 +240,7 @@ where
//todo: silence stdout and stderr for clients //todo: silence stdout and stderr for clients
// the actual client. do the fuzzing // the actual client. do the fuzzing
let (state, mgr) = RestartingMgr::<I, MT, OT, S, SP>::builder() let (state, mgr) = RestartingMgr::<MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone()) .shmem_provider(self.shmem_provider.clone())
.broker_port(self.broker_port) .broker_port(self.broker_port)
.kind(ManagerKind::Client { .kind(ManagerKind::Client {
@ -299,7 +294,7 @@ where
#[cfg(feature = "std")] #[cfg(feature = "std")]
println!("I am broker!!."); println!("I am broker!!.");
RestartingMgr::<I, MT, OT, S, SP>::builder() RestartingMgr::<MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone()) .shmem_provider(self.shmem_provider.clone())
.monitor(Some(self.monitor.clone())) .monitor(Some(self.monitor.clone()))
.broker_port(self.broker_port) .broker_port(self.broker_port)

View File

@ -153,6 +153,7 @@ pub fn format_duration_hms(duration: &time::Duration) -> String {
} }
/// The purpose of this module is to alleviate imports of the bolts by adding a glob import. /// The purpose of this module is to alleviate imports of the bolts by adding a glob import.
#[cfg(feature = "prelude")]
pub mod bolts_prelude { pub mod bolts_prelude {
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use super::build_id::*; pub use super::build_id::*;

View File

@ -11,7 +11,7 @@ use crate::{
ondisk::{OnDiskCorpus, OnDiskMetadataFormat}, ondisk::{OnDiskCorpus, OnDiskMetadataFormat},
Corpus, Testcase, Corpus, Testcase,
}, },
inputs::Input, inputs::{Input, UsesInput},
Error, Error,
}; };
@ -28,7 +28,14 @@ where
cache_max_len: usize, cache_max_len: usize,
} }
impl<I> Corpus<I> for CachedOnDiskCorpus<I> impl<I> UsesInput for CachedOnDiskCorpus<I>
where
I: Input,
{
type Input = I;
}
impl<I> Corpus for CachedOnDiskCorpus<I>
where where
I: Input, I: Input,
{ {

View File

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
corpus::{Corpus, Testcase}, corpus::{Corpus, Testcase},
inputs::Input, inputs::{Input, UsesInput},
Error, Error,
}; };
@ -22,7 +22,14 @@ where
current: Option<usize>, current: Option<usize>,
} }
impl<I> Corpus<I> for InMemoryCorpus<I> impl<I> UsesInput for InMemoryCorpus<I>
where
I: Input,
{
type Input = I;
}
impl<I> Corpus for InMemoryCorpus<I>
where where
I: Input, I: Input,
{ {

View File

@ -12,71 +12,70 @@ use num_traits::ToPrimitive;
use z3::{ast::Bool, Config, Context, Optimize}; use z3::{ast::Bool, Config, Context, Optimize};
use crate::{ use crate::{
bolts::AsIter, bolts::{
tuples::{MatchName, Named},
AsIter,
},
corpus::Corpus, corpus::Corpus,
events::EventManager,
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
inputs::Input,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
schedulers::{LenTimeMulTestcaseScore, Scheduler, TestcaseScore}, schedulers::{LenTimeMulTestcaseScore, Scheduler, TestcaseScore},
state::{HasCorpus, HasMetadata}, state::{HasCorpus, HasMetadata, UsesState},
Error, Evaluator, HasScheduler, Error, HasScheduler,
}; };
/// `CorpusMinimizers` minimize corpora according to internal logic. See various implementations for /// `CorpusMinimizers` minimize corpora according to internal logic. See various implementations for
/// details. /// details.
pub trait CorpusMinimizer<I, S> pub trait CorpusMinimizer<E>
where where
I: Input, E: UsesState,
S: HasCorpus<I>, E::State: HasCorpus,
{ {
/// Minimize the corpus of the provided state. /// Minimize the corpus of the provided state.
fn minimize<CS, EX, EM, OT, Z>( fn minimize<CS, EM, Z>(
&self, &self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut EX, executor: &mut E,
manager: &mut EM, manager: &mut EM,
state: &mut S, state: &mut E::State,
) -> Result<(), Error> ) -> Result<(), Error>
where where
CS: Scheduler<I, S>, E: Executor<EM, Z> + HasObservers,
EX: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, CS: Scheduler<State = E::State>,
EM: EventManager<EX, I, S, Z>, EM: UsesState<State = E::State>,
OT: ObserversTuple<I, S>, Z: HasScheduler<CS, State = E::State>;
Z: Evaluator<EX, EM, I, S> + HasScheduler<CS, I, S>;
} }
/// Minimizes a corpus according to coverage maps, weighting by the specified `TestcaseScore`. /// Minimizes a corpus according to coverage maps, weighting by the specified `TestcaseScore`.
/// ///
/// Algorithm based on WMOPT: <https://hexhive.epfl.ch/publications/files/21ISSTA2.pdf> /// Algorithm based on WMOPT: <https://hexhive.epfl.ch/publications/files/21ISSTA2.pdf>
#[derive(Debug)] #[derive(Debug)]
pub struct MapCorpusMinimizer<E, I, O, S, TS> pub struct MapCorpusMinimizer<E, O, T, TS>
where where
E: Copy + Hash + Eq, E: UsesState,
I: Input, E::State: HasCorpus + HasMetadata,
for<'a> O: MapObserver<Entry = E> + AsIter<'a, Item = E>, TS: TestcaseScore<E::State>,
S: HasMetadata + HasCorpus<I>,
TS: TestcaseScore<I, S>,
{ {
obs_name: String, obs_name: String,
phantom: PhantomData<(E, I, O, S, TS)>, phantom: PhantomData<(E, O, T, TS)>,
} }
/// Standard corpus minimizer, which weights inputs by length and time. /// Standard corpus minimizer, which weights inputs by length and time.
pub type StdCorpusMinimizer<E, I, O, S> = pub type StdCorpusMinimizer<E, O, T> =
MapCorpusMinimizer<E, I, O, S, LenTimeMulTestcaseScore<I, S>>; MapCorpusMinimizer<E, O, T, LenTimeMulTestcaseScore<<E as UsesState>::State>>;
impl<E, I, O, S, TS> MapCorpusMinimizer<E, I, O, S, TS> impl<E, O, T, TS> MapCorpusMinimizer<E, O, T, TS>
where where
E: Copy + Hash + Eq, E: UsesState,
I: Input, E::State: HasCorpus + HasMetadata,
for<'a> O: MapObserver<Entry = E> + AsIter<'a, Item = E>, TS: TestcaseScore<E::State>,
S: HasMetadata + HasCorpus<I>,
TS: TestcaseScore<I, S>,
{ {
/// Constructs a new `MapCorpusMinimizer` from a provided observer. This observer will be used /// Constructs a new `MapCorpusMinimizer` from a provided observer. This observer will be used
/// in the future to get observed maps from an executed input. /// in the future to get observed maps from an executed input.
pub fn new(obs: &O) -> Self { pub fn new(obs: &O) -> Self
where
O: Named,
{
Self { Self {
obs_name: obs.name().to_string(), obs_name: obs.name().to_string(),
phantom: PhantomData, phantom: PhantomData,
@ -84,27 +83,26 @@ where
} }
} }
impl<E, I, O, S, TS> CorpusMinimizer<I, S> for MapCorpusMinimizer<E, I, O, S, TS> impl<E, O, T, TS> CorpusMinimizer<E> for MapCorpusMinimizer<E, O, T, TS>
where where
E: Copy + Hash + Eq, E: UsesState,
I: Input, for<'a> O: MapObserver<Entry = T> + AsIter<'a, Item = T>,
for<'a> O: MapObserver<Entry = E> + AsIter<'a, Item = E>, E::State: HasMetadata + HasCorpus,
S: HasMetadata + HasCorpus<I>, T: Copy + Hash + Eq,
TS: TestcaseScore<I, S>, TS: TestcaseScore<E::State>,
{ {
fn minimize<CS, EX, EM, OT, Z>( fn minimize<CS, EM, Z>(
&self, &self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut EX, executor: &mut E,
manager: &mut EM, manager: &mut EM,
state: &mut S, state: &mut E::State,
) -> Result<(), Error> ) -> Result<(), Error>
where where
CS: Scheduler<I, S>, E: Executor<EM, Z> + HasObservers,
EX: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, CS: Scheduler<State = E::State>,
EM: EventManager<EX, I, S, Z>, EM: UsesState<State = E::State>,
OT: ObserversTuple<I, S>, Z: HasScheduler<CS, State = E::State>,
Z: Evaluator<EX, EM, I, S> + HasScheduler<CS, I, S>,
{ {
let cfg = Config::default(); let cfg = Config::default();
let ctx = Context::new(&cfg); let ctx = Context::new(&cfg);

View File

@ -23,13 +23,10 @@ use core::cell::RefCell;
#[cfg(feature = "cmin")] #[cfg(feature = "cmin")]
pub use minimizer::*; pub use minimizer::*;
use crate::{inputs::Input, Error}; use crate::{inputs::UsesInput, Error};
/// Corpus with all current testcases /// Corpus with all current testcases
pub trait Corpus<I>: serde::Serialize + for<'de> serde::Deserialize<'de> pub trait Corpus: UsesInput + serde::Serialize + for<'de> serde::Deserialize<'de> {
where
I: Input,
{
/// Returns the number of elements /// Returns the number of elements
fn count(&self) -> usize; fn count(&self) -> usize;
@ -39,16 +36,20 @@ where
} }
/// Add an entry to the corpus and return its index /// Add an entry to the corpus and return its index
fn add(&mut self, testcase: Testcase<I>) -> Result<usize, Error>; fn add(&mut self, testcase: Testcase<Self::Input>) -> Result<usize, Error>;
/// Replaces the testcase at the given idx, returning the existing. /// Replaces the testcase at the given idx, returning the existing.
fn replace(&mut self, idx: usize, testcase: Testcase<I>) -> Result<Testcase<I>, Error>; fn replace(
&mut self,
idx: usize,
testcase: Testcase<Self::Input>,
) -> Result<Testcase<Self::Input>, Error>;
/// Removes an entry from the corpus, returning it if it was present. /// Removes an entry from the corpus, returning it if it was present.
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<I>>, Error>; fn remove(&mut self, idx: usize) -> Result<Option<Testcase<Self::Input>>, Error>;
/// Get by id /// Get by id
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error>; fn get(&self, idx: usize) -> Result<&RefCell<Testcase<Self::Input>>, Error>;
/// Current testcase scheduled /// Current testcase scheduled
fn current(&self) -> &Option<usize>; fn current(&self) -> &Option<usize>;
@ -72,7 +73,7 @@ pub mod pybind {
ondisk::pybind::PythonOnDiskCorpus, testcase::pybind::PythonTestcaseWrapper, Corpus, ondisk::pybind::PythonOnDiskCorpus, testcase::pybind::PythonTestcaseWrapper, Corpus,
Testcase, Testcase,
}, },
inputs::BytesInput, inputs::{BytesInput, UsesInput},
Error, Error,
}; };
@ -170,7 +171,11 @@ pub mod pybind {
} }
} }
impl Corpus<BytesInput> for PythonCorpus { impl UsesInput for PythonCorpus {
type Input = BytesInput;
}
impl Corpus for PythonCorpus {
#[inline] #[inline]
fn count(&self) -> usize { fn count(&self) -> usize {
unwrap_me!(self.wrapper, c, { c.count() }) unwrap_me!(self.wrapper, c, { c.count() })

View File

@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::serdeany::SerdeAnyMap, bolts::serdeany::SerdeAnyMap,
corpus::{Corpus, Testcase}, corpus::{Corpus, Testcase},
inputs::Input, inputs::{Input, UsesInput},
state::HasMetadata, state::HasMetadata,
Error, Error,
}; };
@ -54,7 +54,14 @@ where
meta_format: Option<OnDiskMetadataFormat>, meta_format: Option<OnDiskMetadataFormat>,
} }
impl<I> Corpus<I> for OnDiskCorpus<I> impl<I> UsesInput for OnDiskCorpus<I>
where
I: Input,
{
type Input = I;
}
impl<I> Corpus for OnDiskCorpus<I>
where where
I: Input, I: Input,
{ {

View File

@ -2,7 +2,7 @@
//! It will contain a respective input, and metadata. //! It will contain a respective input, and metadata.
use alloc::string::String; use alloc::string::String;
use core::{convert::Into, default::Default, option::Option, time::Duration}; use core::{default::Default, option::Option, time::Duration};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -181,14 +181,11 @@ where
self.fuzzed = fuzzed; self.fuzzed = fuzzed;
} }
/// Create a new Testcase instace given an input /// Create a new Testcase instance given an input
#[inline] #[inline]
pub fn new<T>(input: T) -> Self pub fn new(input: I) -> Self {
where
T: Into<I>,
{
let mut slf = Testcase { let mut slf = Testcase {
input: Some(input.into()), input: Some(input),
..Testcase::default() ..Testcase::default()
}; };
slf.input.as_mut().unwrap().wrapped_as_testcase(); slf.input.as_mut().unwrap().wrapped_as_testcase();

View File

@ -11,9 +11,9 @@ use core::{marker::PhantomData, time::Duration};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::net::{SocketAddr, ToSocketAddrs}; use std::net::{SocketAddr, ToSocketAddrs};
use serde::de::DeserializeOwned; use serde::Deserialize;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use serde::Serialize; use serde::{de::DeserializeOwned, Serialize};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
@ -42,9 +42,9 @@ use crate::{
}, },
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
fuzzer::{EvaluatorObservers, ExecutionProcessor}, fuzzer::{EvaluatorObservers, ExecutionProcessor},
inputs::Input, inputs::{Input, UsesInput},
monitors::Monitor, monitors::Monitor,
observers::ObserversTuple, state::{HasClientPerfMonitor, HasExecutions, HasMetadata, UsesState},
Error, Error,
}; };
@ -244,12 +244,10 @@ where
/// An [`EventManager`] that forwards all events to other attached fuzzers on shared maps or via tcp, /// An [`EventManager`] that forwards all events to other attached fuzzers on shared maps or via tcp,
/// using low-level message passing, [`crate::bolts::llmp`]. /// using low-level message passing, [`crate::bolts::llmp`].
pub struct LlmpEventManager<I, OT, S, SP> pub struct LlmpEventManager<S, SP>
where where
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
//CE: CustomEvent<I>,
{ {
llmp: LlmpClient<SP>, llmp: LlmpClient<SP>,
/// The custom buf handler /// The custom buf handler
@ -257,14 +255,13 @@ where
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor, compressor: GzipCompressor,
configuration: EventConfig, configuration: EventConfig,
phantom: PhantomData<(I, OT, S)>, phantom: PhantomData<S>,
} }
impl<I, OT, S, SP> core::fmt::Debug for LlmpEventManager<I, OT, S, SP> impl<S, SP> core::fmt::Debug for LlmpEventManager<S, SP>
where where
I: Input,
OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
S: UsesInput,
{ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut debug_struct = f.debug_struct("LlmpEventManager"); let mut debug_struct = f.debug_struct("LlmpEventManager");
@ -279,11 +276,10 @@ where
} }
} }
impl<I, OT, S, SP> Drop for LlmpEventManager<I, OT, S, SP> impl<S, SP> Drop for LlmpEventManager<S, SP>
where where
I: Input,
OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
S: UsesInput,
{ {
/// LLMP clients will have to wait until their pages are mapped by somebody. /// LLMP clients will have to wait until their pages are mapped by somebody.
fn drop(&mut self) { fn drop(&mut self) {
@ -291,10 +287,9 @@ where
} }
} }
impl<I, OT, S, SP> LlmpEventManager<I, OT, S, SP> impl<S, SP> LlmpEventManager<S, SP>
where where
I: Input, S: UsesInput + HasExecutions + HasClientPerfMonitor,
OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
{ {
/// Create a manager from a raw llmp client /// Create a manager from a raw llmp client
@ -319,7 +314,7 @@ where
configuration: EventConfig, configuration: EventConfig,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Ok(Self { Ok(Self {
llmp: llmp::LlmpClient::create_attach_to_tcp(shmem_provider, port)?, llmp: LlmpClient::create_attach_to_tcp(shmem_provider, port)?,
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration, configuration,
@ -357,7 +352,7 @@ where
configuration: EventConfig, configuration: EventConfig,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Ok(Self { Ok(Self {
llmp: llmp::LlmpClient::existing_client_from_description(shmem_provider, description)?, llmp: LlmpClient::existing_client_from_description(shmem_provider, description)?,
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration, configuration,
@ -380,12 +375,12 @@ where
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut S,
_client_id: u32, _client_id: u32,
event: Event<I>, event: Event<S::Input>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
OT: ObserversTuple<I, S> + DeserializeOwned, E: Executor<Self, Z> + HasObservers<State = S>,
E: Executor<Self, I, S, Z> + HasObservers<I, OT, S>, for<'a> E::Observers: Deserialize<'a>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S>, Z: ExecutionProcessor<E::Observers, State = S> + EvaluatorObservers<E::Observers>,
{ {
match event { match event {
Event::NewTestcase { Event::NewTestcase {
@ -406,10 +401,13 @@ where
let _res = if client_config.match_with(&self.configuration) let _res = if client_config.match_with(&self.configuration)
&& observers_buf.is_some() && observers_buf.is_some()
{ {
let observers: OT = postcard::from_bytes(observers_buf.as_ref().unwrap())?; let observers: E::Observers =
postcard::from_bytes(observers_buf.as_ref().unwrap())?;
fuzzer.process_execution(state, self, input, &observers, &exit_kind, false)? fuzzer.process_execution(state, self, input, &observers, &exit_kind, false)?
} else { } else {
fuzzer.evaluate_input_with_observers(state, executor, self, input, false)? fuzzer.evaluate_input_with_observers::<E, Self>(
state, executor, self, input, false,
)?
}; };
#[cfg(feature = "std")] #[cfg(feature = "std")]
if let Some(item) = _res.1 { if let Some(item) = _res.1 {
@ -433,15 +431,25 @@ where
} }
} }
impl<I, OT, S, SP> EventFirer<I> for LlmpEventManager<I, OT, S, SP> impl<S, SP> UsesState for LlmpEventManager<S, SP>
where where
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>, SP: ShMemProvider,
{
type State = S;
}
impl<S, SP> EventFirer for LlmpEventManager<S, SP>
where
S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
//CE: CustomEvent<I>,
{ {
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
fn fire<S2>(&mut self, _state: &mut S2, event: Event<I>) -> Result<(), Error> { fn fire(
&mut self,
_state: &mut Self::State,
event: Event<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
let serialized = postcard::to_allocvec(&event)?; let serialized = postcard::to_allocvec(&event)?;
let flags: Flags = LLMP_FLAG_INITIALIZED; let flags: Flags = LLMP_FLAG_INITIALIZED;
@ -461,7 +469,11 @@ where
} }
#[cfg(not(feature = "llmp_compression"))] #[cfg(not(feature = "llmp_compression"))]
fn fire<S2>(&mut self, _state: &mut S2, event: Event<I>) -> Result<(), Error> { fn fire(
&mut self,
_state: &mut Self::State,
event: Event<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
let serialized = postcard::to_allocvec(&event)?; let serialized = postcard::to_allocvec(&event)?;
self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?;
Ok(()) Ok(())
@ -472,12 +484,10 @@ where
} }
} }
impl<I, OT, S, SP> EventRestarter<S> for LlmpEventManager<I, OT, S, SP> impl<S, SP> EventRestarter for LlmpEventManager<S, SP>
where where
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>,
SP: ShMemProvider, SP: ShMemProvider,
//CE: CustomEvent<I>,
{ {
/// The llmp client needs to wait until a broker mapped all pages, before shutting down. /// The llmp client needs to wait until a broker mapped all pages, before shutting down.
/// Otherwise, the OS may already have removed the shared maps, /// Otherwise, the OS may already have removed the shared maps,
@ -487,15 +497,20 @@ where
} }
} }
impl<E, I, OT, S, SP, Z> EventProcessor<E, I, S, Z> for LlmpEventManager<I, OT, S, SP> impl<E, S, SP, Z> EventProcessor<E, Z> for LlmpEventManager<S, SP>
where where
S: UsesInput + HasClientPerfMonitor + HasExecutions,
SP: ShMemProvider, SP: ShMemProvider,
E: Executor<Self, I, S, Z> + HasObservers<I, OT, S>, E: HasObservers<State = S> + Executor<Self, Z>,
I: Input, for<'a> E::Observers: Deserialize<'a>,
OT: ObserversTuple<I, S> + DeserializeOwned, Z: EvaluatorObservers<E::Observers, State = S> + ExecutionProcessor<E::Observers, State = S>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S>, //CE: CustomEvent<I>,
{ {
fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error> { fn process(
&mut self,
fuzzer: &mut Z,
state: &mut Self::State,
executor: &mut E,
) -> Result<usize, Error> {
// TODO: Get around local event copy by moving handle_in_client // TODO: Get around local event copy by moving handle_in_client
let self_id = self.llmp.sender.id; let self_id = self.llmp.sender.id;
let mut count = 0; let mut count = 0;
@ -519,7 +534,7 @@ where
} else { } else {
msg msg
}; };
let event: Event<I> = postcard::from_bytes(event_bytes)?; let event: Event<S::Input> = postcard::from_bytes(event_bytes)?;
self.handle_in_client(fuzzer, executor, state, client_id, event)?; self.handle_in_client(fuzzer, executor, state, client_id, event)?;
count += 1; count += 1;
} }
@ -527,20 +542,19 @@ where
} }
} }
impl<E, I, OT, S, SP, Z> EventManager<E, I, S, Z> for LlmpEventManager<I, OT, S, SP> impl<E, S, SP, Z> EventManager<E, Z> for LlmpEventManager<S, SP>
where where
E: Executor<Self, I, S, Z> + HasObservers<I, OT, S>, E: HasObservers<State = S> + Executor<Self, Z>,
I: Input, for<'a> E::Observers: Deserialize<'a>,
OT: ObserversTuple<I, S> + DeserializeOwned, S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata,
SP: ShMemProvider, SP: ShMemProvider,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S>, //CE: CustomEvent<I>, Z: EvaluatorObservers<E::Observers, State = S> + ExecutionProcessor<E::Observers, State = S>,
{ {
} }
impl<I, OT, S, SP> HasCustomBufHandlers<S> for LlmpEventManager<I, OT, S, SP> impl<S, SP> HasCustomBufHandlers<S> for LlmpEventManager<S, SP>
where where
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>,
SP: ShMemProvider, SP: ShMemProvider,
{ {
fn add_custom_buf_handler( fn add_custom_buf_handler(
@ -551,18 +565,16 @@ where
} }
} }
impl<I, OT, S, SP> ProgressReporter<I> for LlmpEventManager<I, OT, S, SP> impl<S, SP> ProgressReporter for LlmpEventManager<S, SP>
where where
I: Input, S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata,
OT: ObserversTuple<I, S> + DeserializeOwned,
SP: ShMemProvider, SP: ShMemProvider,
{ {
} }
impl<I, OT, S, SP> HasEventManagerId for LlmpEventManager<I, OT, S, SP> impl<S, SP> HasEventManagerId for LlmpEventManager<S, SP>
where where
I: Input, S: UsesInput,
OT: ObserversTuple<I, S> + DeserializeOwned,
SP: ShMemProvider, SP: ShMemProvider,
{ {
/// Gets the id assigned to this staterestorer. /// Gets the id assigned to this staterestorer.
@ -576,38 +588,47 @@ where
/// A manager that can restart on the fly, storing states in-between (in `on_restart`) /// A manager that can restart on the fly, storing states in-between (in `on_restart`)
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[derive(Debug)] #[derive(Debug)]
pub struct LlmpRestartingEventManager<I, OT, S, SP> pub struct LlmpRestartingEventManager<S, SP>
where where
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
/// The embedded llmp event manager /// The embedded llmp event manager
llmp_mgr: LlmpEventManager<I, OT, S, SP>, llmp_mgr: LlmpEventManager<S, SP>,
/// The staterestorer to serialize the state for the next runner /// The staterestorer to serialize the state for the next runner
staterestorer: StateRestorer<SP>, staterestorer: StateRestorer<SP>,
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, OT, S, SP> ProgressReporter<I> for LlmpRestartingEventManager<I, OT, S, SP> impl<S, SP> UsesState for LlmpRestartingEventManager<S, SP>
where where
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>, SP: ShMemProvider + 'static,
S: Serialize, {
type State = S;
}
#[cfg(feature = "std")]
impl<S, SP> ProgressReporter for LlmpRestartingEventManager<S, SP>
where
S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata + Serialize,
SP: ShMemProvider, SP: ShMemProvider,
{ {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, OT, S, SP> EventFirer<I> for LlmpRestartingEventManager<I, OT, S, SP> impl<S, SP> EventFirer for LlmpRestartingEventManager<S, SP>
where where
I: Input,
OT: ObserversTuple<I, S>,
SP: ShMemProvider, SP: ShMemProvider,
S: UsesInput,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
fn fire<S2>(&mut self, state: &mut S2, event: Event<I>) -> Result<(), Error> { fn fire(
&mut self,
state: &mut Self::State,
event: Event<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
// Check if we are going to crash in the event, in which case we store our current state for the next runner // 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) self.llmp_mgr.fire(state, event)
} }
@ -618,11 +639,9 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, OT, S, SP> EventRestarter<S> for LlmpRestartingEventManager<I, OT, S, SP> impl<S, SP> EventRestarter for LlmpRestartingEventManager<S, SP>
where where
I: Input, S: UsesInput + HasExecutions + HasClientPerfMonitor + Serialize,
OT: ObserversTuple<I, S>,
S: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
@ -643,14 +662,13 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<E, I, OT, S, SP, Z> EventProcessor<E, I, S, Z> for LlmpRestartingEventManager<I, OT, S, SP> impl<E, S, SP, Z> EventProcessor<E, Z> for LlmpRestartingEventManager<S, SP>
where where
E: Executor<LlmpEventManager<I, OT, S, SP>, I, S, Z> + HasObservers<I, OT, S>, E: HasObservers<State = S> + Executor<LlmpEventManager<S, SP>, Z>,
I: Input, for<'a> E::Observers: Deserialize<'a>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S>, S: UsesInput + HasExecutions + HasClientPerfMonitor,
OT: ObserversTuple<I, S> + DeserializeOwned,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
//CE: CustomEvent<I>, Z: EvaluatorObservers<E::Observers, State = S> + ExecutionProcessor<E::Observers>, //CE: CustomEvent<I>,
{ {
fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error> { fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error> {
self.llmp_mgr.process(fuzzer, state, executor) self.llmp_mgr.process(fuzzer, state, executor)
@ -658,24 +676,20 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<E, I, OT, S, SP, Z> EventManager<E, I, S, Z> for LlmpRestartingEventManager<I, OT, S, SP> impl<E, S, SP, Z> EventManager<E, Z> for LlmpRestartingEventManager<S, SP>
where where
E: Executor<LlmpEventManager<I, OT, S, SP>, I, S, Z> + HasObservers<I, OT, S>, E: HasObservers<State = S> + Executor<LlmpEventManager<S, SP>, Z>,
I: Input, for<'a> E::Observers: Deserialize<'a>,
S: Serialize, S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata + Serialize,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S>,
OT: ObserversTuple<I, S> + DeserializeOwned,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
//CE: CustomEvent<I>, Z: EvaluatorObservers<E::Observers, State = S> + ExecutionProcessor<E::Observers>, //CE: CustomEvent<I>,
{ {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, OT, S, SP> HasEventManagerId for LlmpRestartingEventManager<I, OT, S, SP> impl<S, SP> HasEventManagerId for LlmpRestartingEventManager<S, SP>
where where
I: Input, S: UsesInput + Serialize,
OT: ObserversTuple<I, S> + DeserializeOwned,
S: Serialize,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
{ {
fn mgr_id(&self) -> EventManagerId { fn mgr_id(&self) -> EventManagerId {
@ -690,15 +704,14 @@ const _ENV_FUZZER_RECEIVER: &str = "_AFL_ENV_FUZZER_RECEIVER";
const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT"; const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT";
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, OT, S, SP> LlmpRestartingEventManager<I, OT, S, SP> impl<S, SP> LlmpRestartingEventManager<S, SP>
where where
I: Input, S: UsesInput,
OT: ObserversTuple<I, S> + DeserializeOwned,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
/// Create a new runner, the executed child doing the actual fuzzing. /// Create a new runner, the executed child doing the actual fuzzing.
pub fn new(llmp_mgr: LlmpEventManager<I, OT, S, SP>, staterestorer: StateRestorer<SP>) -> Self { pub fn new(llmp_mgr: LlmpEventManager<S, SP>, staterestorer: StateRestorer<SP>) -> Self {
Self { Self {
llmp_mgr, llmp_mgr,
staterestorer, staterestorer,
@ -736,22 +749,14 @@ pub enum ManagerKind {
/// The restarter will spawn a new process each time the child crashes or timeouts. /// The restarter will spawn a new process each time the child crashes or timeouts.
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn setup_restarting_mgr_std<I, MT, OT, S>( pub fn setup_restarting_mgr_std<MT, S>(
monitor: MT, monitor: MT,
broker_port: u16, broker_port: u16,
configuration: EventConfig, configuration: EventConfig,
) -> Result< ) -> Result<(Option<S>, LlmpRestartingEventManager<S, StdShMemProvider>), Error>
(
Option<S>,
LlmpRestartingEventManager<I, OT, S, StdShMemProvider>,
),
Error,
>
where where
I: Input,
MT: Monitor + Clone, MT: Monitor + Clone,
OT: ObserversTuple<I, S> + DeserializeOwned, S: DeserializeOwned + UsesInput + HasClientPerfMonitor + HasExecutions,
S: DeserializeOwned,
{ {
RestartingMgr::builder() RestartingMgr::builder()
.shmem_provider(StdShMemProvider::new()?) .shmem_provider(StdShMemProvider::new()?)
@ -768,11 +773,9 @@ where
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[allow(clippy::default_trait_access)] #[allow(clippy::default_trait_access)]
#[derive(TypedBuilder, Debug)] #[derive(TypedBuilder, Debug)]
pub struct RestartingMgr<I, MT, OT, S, SP> pub struct RestartingMgr<MT, S, SP>
where where
I: Input, S: UsesInput + DeserializeOwned,
OT: ObserversTuple<I, S> + DeserializeOwned,
S: DeserializeOwned,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
MT: Monitor, MT: Monitor,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
@ -795,28 +798,25 @@ where
#[builder(default = ManagerKind::Any)] #[builder(default = ManagerKind::Any)]
kind: ManagerKind, kind: ManagerKind,
#[builder(setter(skip), default = PhantomData)] #[builder(setter(skip), default = PhantomData)]
phantom_data: PhantomData<(I, OT, S)>, phantom_data: PhantomData<S>,
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[allow(clippy::type_complexity, clippy::too_many_lines)] #[allow(clippy::type_complexity, clippy::too_many_lines)]
impl<I, MT, OT, S, SP> RestartingMgr<I, MT, OT, S, SP> impl<MT, S, SP> RestartingMgr<MT, S, SP>
where where
I: Input,
OT: ObserversTuple<I, S> + DeserializeOwned,
S: DeserializeOwned,
SP: ShMemProvider, SP: ShMemProvider,
S: UsesInput + HasExecutions + HasClientPerfMonitor + DeserializeOwned,
MT: Monitor + Clone, MT: Monitor + Clone,
{ {
/// Launch the restarting manager /// Launch the restarting manager
pub fn launch( pub fn launch(&mut self) -> Result<(Option<S>, LlmpRestartingEventManager<S, SP>), Error> {
&mut self,
) -> Result<(Option<S>, LlmpRestartingEventManager<I, OT, S, SP>), Error> {
// We start ourself as child process to actually fuzz // We start ourself as child process to actually fuzz
let (staterestorer, new_shmem_provider, core_id) = if std::env::var(_ENV_FUZZER_SENDER) let (staterestorer, new_shmem_provider, core_id) = if std::env::var(_ENV_FUZZER_SENDER)
.is_err() .is_err()
{ {
let broker_things = |mut broker: LlmpEventBroker<I, MT, SP>, remote_broker_addr| { let broker_things = |mut broker: LlmpEventBroker<S::Input, MT, SP>,
remote_broker_addr| {
if let Some(remote_broker_addr) = remote_broker_addr { if let Some(remote_broker_addr) = remote_broker_addr {
println!("B2b: Connecting to {:?}", &remote_broker_addr); println!("B2b: Connecting to {:?}", &remote_broker_addr);
broker.connect_b2b(remote_broker_addr)?; broker.connect_b2b(remote_broker_addr)?;
@ -832,7 +832,7 @@ where
LlmpConnection::on_port(self.shmem_provider.clone(), self.broker_port)?; LlmpConnection::on_port(self.shmem_provider.clone(), self.broker_port)?;
match connection { match connection {
LlmpConnection::IsBroker { broker } => { LlmpConnection::IsBroker { broker } => {
let event_broker = LlmpEventBroker::<I, MT, SP>::new( let event_broker = LlmpEventBroker::<S::Input, MT, SP>::new(
broker, broker,
self.monitor.take().unwrap(), self.monitor.take().unwrap(),
)?; )?;
@ -847,14 +847,13 @@ where
return Err(Error::shutting_down()); return Err(Error::shutting_down());
} }
LlmpConnection::IsClient { client } => { LlmpConnection::IsClient { client } => {
let mgr = let mgr = LlmpEventManager::<S, SP>::new(client, self.configuration)?;
LlmpEventManager::<I, OT, S, SP>::new(client, self.configuration)?;
(mgr, None) (mgr, None)
} }
} }
} }
ManagerKind::Broker => { ManagerKind::Broker => {
let event_broker = LlmpEventBroker::<I, MT, SP>::new_on_port( let event_broker = LlmpEventBroker::<S::Input, MT, SP>::new_on_port(
self.shmem_provider.clone(), self.shmem_provider.clone(),
self.monitor.take().unwrap(), self.monitor.take().unwrap(),
self.broker_port, self.broker_port,
@ -866,7 +865,7 @@ where
} }
ManagerKind::Client { cpu_core } => { ManagerKind::Client { cpu_core } => {
// We are a client // We are a client
let mgr = LlmpEventManager::<I, OT, S, SP>::new_on_port( let mgr = LlmpEventManager::<S, SP>::new_on_port(
self.shmem_provider.clone(), self.shmem_provider.clone(),
self.broker_port, self.broker_port,
self.configuration, self.configuration,
@ -967,7 +966,7 @@ where
} else { } else {
println!("First run. Let's set it all up"); println!("First run. Let's set it all up");
// Mgr to send and receive msgs from/to all other fuzzer instances // Mgr to send and receive msgs from/to all other fuzzer instances
let mgr = LlmpEventManager::<I, OT, S, SP>::existing_client_from_env( let mgr = LlmpEventManager::<S, SP>::existing_client_from_env(
new_shmem_provider, new_shmem_provider,
_ENV_FUZZER_BROKER_CLIENT_INITIAL, _ENV_FUZZER_BROKER_CLIENT_INITIAL,
self.configuration, self.configuration,
@ -1006,12 +1005,14 @@ mod tests {
corpus::{Corpus, InMemoryCorpus, Testcase}, corpus::{Corpus, InMemoryCorpus, Testcase},
events::{llmp::_ENV_FUZZER_SENDER, LlmpEventManager}, events::{llmp::_ENV_FUZZER_SENDER, LlmpEventManager},
executors::{ExitKind, InProcessExecutor}, executors::{ExitKind, InProcessExecutor},
feedbacks::ConstFeedback,
fuzzer::Fuzzer,
inputs::BytesInput, inputs::BytesInput,
mutators::BitFlipMutator, mutators::BitFlipMutator,
schedulers::RandScheduler, schedulers::RandScheduler,
stages::StdMutationalStage, stages::StdMutationalStage,
state::StdState, state::StdState,
Fuzzer, StdFuzzer, StdFuzzer,
}; };
#[test] #[test]
@ -1020,12 +1021,16 @@ mod tests {
let rand = StdRand::with_seed(0); let rand = StdRand::with_seed(0);
let mut corpus = InMemoryCorpus::<BytesInput>::new(); let mut corpus = InMemoryCorpus::<BytesInput>::new();
let testcase = Testcase::new(vec![0; 4]); let testcase = Testcase::new(vec![0; 4].into());
corpus.add(testcase).unwrap(); corpus.add(testcase).unwrap();
let solutions = InMemoryCorpus::<BytesInput>::new(); let solutions = InMemoryCorpus::<BytesInput>::new();
let mut state = StdState::new(rand, corpus, solutions, &mut (), &mut ()).unwrap(); let mut feedback = ConstFeedback::new(false);
let mut objective = ConstFeedback::new(false);
let mut state =
StdState::new(rand, corpus, solutions, &mut feedback, &mut objective).unwrap();
let mut shmem_provider = StdShMemProvider::new().unwrap(); let mut shmem_provider = StdShMemProvider::new().unwrap();
@ -1041,12 +1046,14 @@ mod tests {
llmp_client.mark_safe_to_unmap(); llmp_client.mark_safe_to_unmap();
} }
let mut llmp_mgr = let mut llmp_mgr = LlmpEventManager::new(llmp_client, "fuzzer".into()).unwrap();
LlmpEventManager::<BytesInput, (), _, _>::new(llmp_client, "fuzzer".into()).unwrap();
let scheduler = RandScheduler::new(); let scheduler = RandScheduler::new();
let mut fuzzer = StdFuzzer::new(scheduler, (), ()); let feedback = ConstFeedback::new(true);
let objective = ConstFeedback::new(false);
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
let mut harness = |_buf: &BytesInput| ExitKind::Ok; let mut harness = |_buf: &BytesInput| ExitKind::Ok;
let mut executor = InProcessExecutor::new( let mut executor = InProcessExecutor::new(

View File

@ -37,6 +37,7 @@ pub struct EventManagerId {
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
use crate::monitors::ClientPerfMonitor; use crate::monitors::ClientPerfMonitor;
use crate::{inputs::UsesInput, state::UsesState};
/// The log event severity /// The log event severity
#[derive(Serialize, Deserialize, Debug, Clone, Copy)] #[derive(Serialize, Deserialize, Debug, Clone, Copy)]
@ -300,10 +301,7 @@ where
} }
/// [`EventFirer`] fire an event. /// [`EventFirer`] fire an event.
pub trait EventFirer<I> pub trait EventFirer: UsesState {
where
I: Input,
{
/// Send off an [`Event`] to the broker /// Send off an [`Event`] to the broker
/// ///
/// For multi-processed managers, such as [`llmp::LlmpEventManager`], /// For multi-processed managers, such as [`llmp::LlmpEventManager`],
@ -312,13 +310,17 @@ where
/// (for example for each [`Input`], on multiple cores) /// (for example for each [`Input`], on multiple cores)
/// the [`llmp`] shared map may fill up and the client will eventually OOM or [`panic`]. /// the [`llmp`] shared map may fill up and the client will eventually OOM or [`panic`].
/// This should not happen for a normal use-case. /// This should not happen for a normal use-case.
fn fire<S>(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error>; fn fire(
&mut self,
state: &mut Self::State,
event: Event<<Self::State as UsesInput>::Input>,
) -> Result<(), Error>;
/// Send off an [`Event::Log`] event to the broker. /// Send off an [`Event::Log`] event to the broker.
/// This is a shortcut for [`EventFirer::fire`] with [`Event::Log`] as argument. /// This is a shortcut for [`EventFirer::fire`] with [`Event::Log`] as argument.
fn log<S>( fn log(
&mut self, &mut self,
state: &mut S, state: &mut Self::State,
severity_level: LogSeverity, severity_level: LogSeverity,
message: String, message: String,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -333,9 +335,9 @@ where
} }
/// Serialize all observers for this type and manager /// Serialize all observers for this type and manager
fn serialize_observers<OT, S>(&mut self, observers: &OT) -> Result<Vec<u8>, Error> fn serialize_observers<OT>(&mut self, observers: &OT) -> Result<Vec<u8>, Error>
where where
OT: ObserversTuple<I, S> + Serialize, OT: ObserversTuple<Self::State> + Serialize,
{ {
Ok(postcard::to_allocvec(observers)?) Ok(postcard::to_allocvec(observers)?)
} }
@ -347,22 +349,19 @@ where
} }
/// [`ProgressReporter`] report progress to the broker. /// [`ProgressReporter`] report progress to the broker.
pub trait ProgressReporter<I>: EventFirer<I> pub trait ProgressReporter: EventFirer
where where
I: Input, Self::State: HasClientPerfMonitor + HasMetadata + HasExecutions,
{ {
/// Given the last time, if `monitor_timeout` seconds passed, send off an info/monitor/heartbeat message to the broker. /// Given the last time, if `monitor_timeout` seconds passed, send off an info/monitor/heartbeat message to the broker.
/// Returns the new `last` time (so the old one, unless `monitor_timeout` time has passed and monitor have been sent) /// Returns the new `last` time (so the old one, unless `monitor_timeout` time has passed and monitor have been sent)
/// Will return an [`crate::Error`], if the stats could not be sent. /// Will return an [`crate::Error`], if the stats could not be sent.
fn maybe_report_progress<S>( fn maybe_report_progress(
&mut self, &mut self,
state: &mut S, state: &mut Self::State,
last_report_time: Duration, last_report_time: Duration,
monitor_timeout: Duration, monitor_timeout: Duration,
) -> Result<Duration, Error> ) -> Result<Duration, Error> {
where
S: HasExecutions + HasClientPerfMonitor + HasMetadata,
{
let executions = *state.executions(); let executions = *state.executions();
let cur = current_time(); let cur = current_time();
// default to 0 here to avoid crashes on clock skew // default to 0 here to avoid crashes on clock skew
@ -421,10 +420,10 @@ where
} }
/// Restartable trait /// Restartable trait
pub trait EventRestarter<S> { pub trait EventRestarter: UsesState {
/// For restarting event managers, implement a way to forward state to their next peers. /// For restarting event managers, implement a way to forward state to their next peers.
#[inline] #[inline]
fn on_restart(&mut self, _state: &mut S) -> Result<(), Error> { fn on_restart(&mut self, _state: &mut Self::State) -> Result<(), Error> {
Ok(()) Ok(())
} }
@ -434,18 +433,15 @@ pub trait EventRestarter<S> {
} }
/// [`EventProcessor`] process all the incoming messages /// [`EventProcessor`] process all the incoming messages
pub trait EventProcessor<E, I, S, Z> { pub trait EventProcessor<E, Z>: UsesState {
/// 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, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error>; fn process(
&mut self,
/// Deserialize all observers for this type and manager fuzzer: &mut Z,
fn deserialize_observers<OT>(&mut self, observers_buf: &[u8]) -> Result<OT, Error> state: &mut Self::State,
where executor: &mut E,
OT: ObserversTuple<I, S> + serde::de::DeserializeOwned, ) -> Result<usize, Error>;
{
Ok(postcard::from_bytes(observers_buf)?)
}
} }
/// The id of this [`EventManager`]. /// The id of this [`EventManager`].
/// For multi processed [`EventManager`]s, /// For multi processed [`EventManager`]s,
@ -458,14 +454,10 @@ pub trait HasEventManagerId {
/// [`EventManager`] is the main communications hub. /// [`EventManager`] is the main communications hub.
/// For the "normal" multi-processed mode, you may want to look into [`LlmpRestartingEventManager`] /// For the "normal" multi-processed mode, you may want to look into [`LlmpRestartingEventManager`]
pub trait EventManager<E, I, S, Z>: pub trait EventManager<E, Z>:
EventFirer<I> EventFirer + EventProcessor<E, Z> + EventRestarter + HasEventManagerId + ProgressReporter
+ EventProcessor<E, I, S, Z>
+ EventRestarter<S>
+ HasEventManagerId
+ ProgressReporter<I>
where where
I: Input, Self::State: HasClientPerfMonitor + HasMetadata + HasExecutions,
{ {
} }
@ -480,34 +472,63 @@ pub trait HasCustomBufHandlers<S> {
} }
/// An eventmgr for tests, and as placeholder if you really don't need an event manager. /// An eventmgr for tests, and as placeholder if you really don't need an event manager.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug, Default)]
pub struct NopEventManager {} pub struct NopEventManager<S> {
phantom: PhantomData<S>,
}
impl<I> EventFirer<I> for NopEventManager impl<S> NopEventManager<S> {
/// Creates a new [`NopEventManager`]
#[must_use]
pub fn new() -> Self {
NopEventManager {
phantom: PhantomData,
}
}
}
impl<S> UsesState for NopEventManager<S>
where where
I: Input, S: UsesInput,
{ {
fn fire<S>(&mut self, _state: &mut S, _event: Event<I>) -> Result<(), Error> { type State = S;
}
impl<S> EventFirer for NopEventManager<S>
where
S: UsesInput,
{
fn fire(
&mut self,
_state: &mut Self::State,
_event: Event<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
Ok(()) Ok(())
} }
} }
impl<S> EventRestarter<S> for NopEventManager {} impl<S> EventRestarter for NopEventManager<S> where S: UsesInput {}
impl<E, I, S, Z> EventProcessor<E, I, S, Z> for NopEventManager { impl<E, S, Z> EventProcessor<E, Z> for NopEventManager<S>
where
S: UsesInput + HasClientPerfMonitor + HasExecutions,
{
fn process( fn process(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut S, _state: &mut Self::State,
_executor: &mut E, _executor: &mut E,
) -> Result<usize, Error> { ) -> Result<usize, Error> {
Ok(0) Ok(0)
} }
} }
impl<E, I, S, Z> EventManager<E, I, S, Z> for NopEventManager where I: Input {} impl<E, S, Z> EventManager<E, Z> for NopEventManager<S> where
S: UsesInput + HasClientPerfMonitor + HasExecutions + HasMetadata
{
}
impl<S> HasCustomBufHandlers<S> for NopEventManager { impl<S> HasCustomBufHandlers<S> for NopEventManager<S> {
fn add_custom_buf_handler( fn add_custom_buf_handler(
&mut self, &mut self,
_handler: Box<dyn FnMut(&mut S, &String, &[u8]) -> Result<CustomBufEventResult, Error>>, _handler: Box<dyn FnMut(&mut S, &String, &[u8]) -> Result<CustomBufEventResult, Error>>,
@ -515,9 +536,12 @@ impl<S> HasCustomBufHandlers<S> for NopEventManager {
} }
} }
impl<I> ProgressReporter<I> for NopEventManager where I: Input {} impl<S> ProgressReporter for NopEventManager<S> where
S: UsesInput + HasClientPerfMonitor + HasExecutions + HasMetadata
{
}
impl HasEventManagerId for NopEventManager { impl<S> HasEventManagerId for NopEventManager<S> {
fn mgr_id(&self) -> EventManagerId { fn mgr_id(&self) -> EventManagerId {
EventManagerId { id: 0 } EventManagerId { id: 0 }
} }
@ -594,7 +618,7 @@ pub mod pybind {
executors::pybind::PythonExecutor, executors::pybind::PythonExecutor,
fuzzer::pybind::PythonStdFuzzer, fuzzer::pybind::PythonStdFuzzer,
inputs::BytesInput, inputs::BytesInput,
state::pybind::PythonStdState, state::{pybind::PythonStdState, UsesState},
Error, Error,
}; };
@ -637,17 +661,19 @@ pub mod pybind {
} }
} }
impl EventFirer<BytesInput> for PythonEventManager { impl UsesState for PythonEventManager {
fn fire<S>(&mut self, state: &mut S, event: Event<BytesInput>) -> Result<(), Error> { type State = PythonStdState;
}
impl EventFirer for PythonEventManager {
fn fire(&mut self, state: &mut Self::State, event: Event<BytesInput>) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, e, { e.fire(state, event) }) unwrap_me_mut!(self.wrapper, e, { e.fire(state, event) })
} }
} }
impl<S> EventRestarter<S> for PythonEventManager {} impl EventRestarter for PythonEventManager {}
impl EventProcessor<PythonExecutor, BytesInput, PythonStdState, PythonStdFuzzer> impl EventProcessor<PythonExecutor, PythonStdFuzzer> for PythonEventManager {
for PythonEventManager
{
fn process( fn process(
&mut self, &mut self,
fuzzer: &mut PythonStdFuzzer, fuzzer: &mut PythonStdFuzzer,
@ -658,7 +684,7 @@ pub mod pybind {
} }
} }
impl ProgressReporter<BytesInput> for PythonEventManager {} impl ProgressReporter for PythonEventManager {}
impl HasEventManagerId for PythonEventManager { impl HasEventManagerId for PythonEventManager {
fn mgr_id(&self) -> EventManagerId { fn mgr_id(&self) -> EventManagerId {
@ -666,10 +692,7 @@ pub mod pybind {
} }
} }
impl EventManager<PythonExecutor, BytesInput, PythonStdState, PythonStdFuzzer> impl EventManager<PythonExecutor, PythonStdFuzzer> for PythonEventManager {}
for PythonEventManager
{
}
/// Register the classes to the python module /// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {

View File

@ -21,7 +21,7 @@ use crate::bolts::os::{fork, ForkResult};
use crate::{ use crate::{
bolts::{shmem::ShMemProvider, staterestore::StateRestorer}, bolts::{shmem::ShMemProvider, staterestore::StateRestorer},
corpus::Corpus, corpus::Corpus,
executors::Executor, monitors::SimplePrintingMonitor,
state::{HasCorpus, HasSolutions}, state::{HasCorpus, HasSolutions},
}; };
use crate::{ use crate::{
@ -29,8 +29,9 @@ use crate::{
BrokerEventResult, Event, EventFirer, EventManager, EventManagerId, EventProcessor, BrokerEventResult, Event, EventFirer, EventManager, EventManagerId, EventProcessor,
EventRestarter, HasEventManagerId, EventRestarter, HasEventManagerId,
}, },
inputs::Input, inputs::UsesInput,
monitors::Monitor, monitors::Monitor,
state::{HasClientPerfMonitor, HasExecutions, HasMetadata, UsesState},
Error, Error,
}; };
@ -41,24 +42,23 @@ const _ENV_FUZZER_RECEIVER: &str = "_AFL_ENV_FUZZER_RECEIVER";
const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT"; const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT";
/// A simple, single-threaded event manager that just logs /// A simple, single-threaded event manager that just logs
pub struct SimpleEventManager<I, MT, S> pub struct SimpleEventManager<MT, S>
where where
I: Input, S: UsesInput,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
/// The monitor /// The monitor
monitor: MT, monitor: MT,
/// The events that happened since the last handle_in_broker /// The events that happened since the last handle_in_broker
events: Vec<Event<I>>, events: Vec<Event<S::Input>>,
/// The custom buf handler /// The custom buf handler
custom_buf_handlers: Vec<Box<CustomBufHandlerFn<S>>>, custom_buf_handlers: Vec<Box<CustomBufHandlerFn<S>>>,
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
impl<I, MT, S> Debug for SimpleEventManager<I, MT, S> impl<MT, S> Debug for SimpleEventManager<MT, S>
where where
I: Input, MT: Debug,
MT: Monitor + Debug, S: UsesInput,
{ {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SimpleEventManager") f.debug_struct("SimpleEventManager")
@ -69,12 +69,23 @@ where
} }
} }
impl<I, MT, S> EventFirer<I> for SimpleEventManager<I, MT, S> impl<MT, S> UsesState for SimpleEventManager<MT, S>
where where
I: Input, S: UsesInput,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
fn fire<S2>(&mut self, _state: &mut S2, event: Event<I>) -> Result<(), Error> { type State = S;
}
impl<MT, S> EventFirer for SimpleEventManager<MT, S>
where
MT: Monitor,
S: UsesInput,
{
fn fire(
&mut self,
_state: &mut Self::State,
event: Event<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
match Self::handle_in_broker(&mut self.monitor, &event)? { match Self::handle_in_broker(&mut self.monitor, &event)? {
BrokerEventResult::Forward => self.events.push(event), BrokerEventResult::Forward => self.events.push(event),
BrokerEventResult::Handled => (), BrokerEventResult::Handled => (),
@ -83,17 +94,17 @@ where
} }
} }
impl<I, MT, S> EventRestarter<S> for SimpleEventManager<I, MT, S> impl<MT, S> EventRestarter for SimpleEventManager<MT, S>
where where
I: Input, MT: Monitor,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>, S: UsesInput,
{ {
} }
impl<E, I, MT, S, Z> EventProcessor<E, I, S, Z> for SimpleEventManager<I, MT, S> impl<E, MT, S, Z> EventProcessor<E, Z> for SimpleEventManager<MT, S>
where where
I: Input, MT: Monitor,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>, S: UsesInput,
{ {
fn process( fn process(
&mut self, &mut self,
@ -110,17 +121,17 @@ where
} }
} }
impl<E, I, MT, S, Z> EventManager<E, I, S, Z> for SimpleEventManager<I, MT, S> impl<E, MT, S, Z> EventManager<E, Z> for SimpleEventManager<MT, S>
where where
I: Input, MT: Monitor,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>, S: UsesInput + HasClientPerfMonitor + HasExecutions + HasMetadata,
{ {
} }
impl<I, MT, S> HasCustomBufHandlers<S> for SimpleEventManager<I, MT, S> impl<MT, S> HasCustomBufHandlers<S> for SimpleEventManager<MT, S>
where where
I: Input, MT: Monitor, //CE: CustomEvent<I, OT>,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>, S: UsesInput,
{ {
/// Adds a custom buffer handler that will run for each incoming `CustomBuf` event. /// Adds a custom buffer handler that will run for each incoming `CustomBuf` event.
fn add_custom_buf_handler( fn add_custom_buf_handler(
@ -131,27 +142,39 @@ where
} }
} }
impl<I, MT, S> ProgressReporter<I> for SimpleEventManager<I, MT, S> impl<MT, S> ProgressReporter for SimpleEventManager<MT, S>
where where
I: Input, MT: Monitor,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>, S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata,
{ {
} }
impl<I, MT, S> HasEventManagerId for SimpleEventManager<I, MT, S> impl<MT, S> HasEventManagerId for SimpleEventManager<MT, S>
where where
I: Input, MT: Monitor,
MT: Monitor + Debug, S: UsesInput,
{ {
fn mgr_id(&self) -> EventManagerId { fn mgr_id(&self) -> EventManagerId {
EventManagerId { id: 0 } EventManagerId { id: 0 }
} }
} }
impl<I, MT, S> SimpleEventManager<I, MT, S> #[cfg(feature = "std")]
impl<S> SimpleEventManager<SimplePrintingMonitor, S>
where where
I: Input, S: UsesInput,
MT: Monitor + Debug, //TODO CE: CustomEvent, {
/// Creates a [`SimpleEventManager`] that just prints to `stdout`.
#[must_use]
pub fn printing() -> Self {
Self::new(SimplePrintingMonitor::new())
}
}
impl<MT, S> SimpleEventManager<MT, S>
where
MT: Monitor, //TODO CE: CustomEvent,
S: UsesInput,
{ {
/// Creates a new [`SimpleEventManager`]. /// Creates a new [`SimpleEventManager`].
pub fn new(monitor: MT) -> Self { pub fn new(monitor: MT) -> Self {
@ -165,7 +188,10 @@ where
/// Handle arriving events in the broker /// Handle arriving events in the broker
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn handle_in_broker(monitor: &mut MT, event: &Event<I>) -> Result<BrokerEventResult, Error> { fn handle_in_broker(
monitor: &mut MT,
event: &Event<S::Input>,
) -> Result<BrokerEventResult, Error> {
match event { match event {
Event::NewTestcase { Event::NewTestcase {
input: _, input: _,
@ -247,7 +273,7 @@ where
// Handle arriving events in the client // Handle arriving events in the client
#[allow(clippy::needless_pass_by_value, clippy::unused_self)] #[allow(clippy::needless_pass_by_value, clippy::unused_self)]
fn handle_in_client(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error> { fn handle_in_client(&mut self, state: &mut S, event: Event<S::Input>) -> Result<(), Error> {
if let Event::CustomBuf { tag, buf } = &event { if let Event::CustomBuf { tag, buf } = &event {
for handler in &mut self.custom_buf_handlers { for handler in &mut self.custom_buf_handlers {
handler(state, tag, buf)?; handler(state, tag, buf)?;
@ -268,37 +294,47 @@ where
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[allow(clippy::default_trait_access)] #[allow(clippy::default_trait_access)]
#[derive(Debug)] #[derive(Debug)]
pub struct SimpleRestartingEventManager<I, MT, S, SP> pub struct SimpleRestartingEventManager<MT, S, SP>
where where
I: Input, S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider, //CE: CustomEvent<I, OT>,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
/// The actual simple event mgr /// The actual simple event mgr
simple_event_mgr: SimpleEventManager<I, MT, S>, simple_event_mgr: SimpleEventManager<MT, S>,
/// [`StateRestorer`] for restarts /// [`StateRestorer`] for restarts
staterestorer: StateRestorer<SP>, staterestorer: StateRestorer<SP>,
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, MT, S, SP> EventFirer<I> for SimpleRestartingEventManager<I, MT, S, SP> impl<MT, S, SP> UsesState for SimpleRestartingEventManager<MT, S, SP>
where where
I: Input, S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
fn fire<S2>(&mut self, _state: &mut S2, event: Event<I>) -> Result<(), Error> { type State = S;
}
#[cfg(feature = "std")]
impl<MT, S, SP> EventFirer for SimpleRestartingEventManager<MT, S, SP>
where
MT: Monitor,
S: UsesInput,
SP: ShMemProvider,
{
fn fire(
&mut self,
_state: &mut Self::State,
event: Event<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
self.simple_event_mgr.fire(_state, event) self.simple_event_mgr.fire(_state, event)
} }
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, MT, S, SP> EventRestarter<S> for SimpleRestartingEventManager<I, MT, S, SP> impl<MT, S, SP> EventRestarter for SimpleRestartingEventManager<MT, S, SP>
where where
I: Input, S: UsesInput + Serialize,
S: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
/// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner. /// 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(&mut self, state: &mut S) -> Result<(), Error> { fn on_restart(&mut self, state: &mut S) -> Result<(), Error> {
@ -309,35 +345,37 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<E, I, S, SP, MT, Z> EventProcessor<E, I, S, Z> for SimpleRestartingEventManager<I, MT, S, SP> impl<E, MT, S, SP, Z> EventProcessor<E, Z> for SimpleRestartingEventManager<MT, S, SP>
where where
I: Input, MT: Monitor,
S: Serialize, S: UsesInput + HasClientPerfMonitor + HasExecutions + Serialize,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error> { fn process(
&mut self,
fuzzer: &mut Z,
state: &mut Self::State,
executor: &mut E,
) -> Result<usize, Error> {
self.simple_event_mgr.process(fuzzer, state, executor) self.simple_event_mgr.process(fuzzer, state, executor)
} }
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<E, I, S, SP, MT, Z> EventManager<E, I, S, Z> for SimpleRestartingEventManager<I, MT, S, SP> impl<E, MT, S, SP, Z> EventManager<E, Z> for SimpleRestartingEventManager<MT, S, SP>
where where
E: Executor<Self, I, S, Z>, MT: Monitor,
I: Input, S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata + Serialize,
S: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, MT, S, SP> HasCustomBufHandlers<S> for SimpleRestartingEventManager<I, MT, S, SP> impl<MT, S, SP> HasCustomBufHandlers<S> for SimpleRestartingEventManager<MT, S, SP>
where where
I: Input, MT: Monitor,
S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
fn add_custom_buf_handler( fn add_custom_buf_handler(
&mut self, &mut self,
@ -348,20 +386,20 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, MT, S, SP> ProgressReporter<I> for SimpleRestartingEventManager<I, MT, S, SP> impl<MT, S, SP> ProgressReporter for SimpleRestartingEventManager<MT, S, SP>
where where
I: Input, MT: Monitor,
S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, MT, S, SP> HasEventManagerId for SimpleRestartingEventManager<I, MT, S, SP> impl<MT, S, SP> HasEventManagerId for SimpleRestartingEventManager<MT, S, SP>
where where
I: Input, MT: Monitor,
S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor + Debug,
{ {
fn mgr_id(&self) -> EventManagerId { fn mgr_id(&self) -> EventManagerId {
self.simple_event_mgr.mgr_id() self.simple_event_mgr.mgr_id()
@ -370,11 +408,11 @@ where
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[allow(clippy::type_complexity, clippy::too_many_lines)] #[allow(clippy::type_complexity, clippy::too_many_lines)]
impl<I, MT, S, SP> SimpleRestartingEventManager<I, MT, S, SP> impl<MT, S, SP> SimpleRestartingEventManager<MT, S, SP>
where where
I: Input, S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor + Debug, //TODO CE: CustomEvent, MT: Monitor, //TODO CE: CustomEvent,
{ {
/// Creates a new [`SimpleEventManager`]. /// Creates a new [`SimpleEventManager`].
fn new_launched(monitor: MT, staterestorer: StateRestorer<SP>) -> Self { fn new_launched(monitor: MT, staterestorer: StateRestorer<SP>) -> Self {
@ -390,7 +428,7 @@ where
#[allow(clippy::similar_names)] #[allow(clippy::similar_names)]
pub fn launch(mut monitor: MT, shmem_provider: &mut SP) -> Result<(Option<S>, Self), Error> pub fn launch(mut monitor: MT, shmem_provider: &mut SP) -> Result<(Option<S>, Self), Error>
where where
S: DeserializeOwned + Serialize + HasCorpus<I> + HasSolutions<I>, S: DeserializeOwned + Serialize + HasCorpus + HasSolutions,
MT: Debug, MT: Debug,
{ {
// We start ourself as child process to actually fuzz // We start ourself as child process to actually fuzz
@ -498,7 +536,6 @@ pub mod pybind {
use crate::{ use crate::{
events::{pybind::PythonEventManager, SimpleEventManager}, events::{pybind::PythonEventManager, SimpleEventManager},
inputs::BytesInput,
monitors::pybind::PythonMonitor, monitors::pybind::PythonMonitor,
state::pybind::PythonStdState, state::pybind::PythonStdState,
}; };
@ -508,7 +545,7 @@ pub mod pybind {
/// Python class for SimpleEventManager /// Python class for SimpleEventManager
pub struct PythonSimpleEventManager { pub struct PythonSimpleEventManager {
/// Rust wrapped SimpleEventManager object /// Rust wrapped SimpleEventManager object
pub inner: SimpleEventManager<BytesInput, PythonMonitor, PythonStdState>, pub inner: SimpleEventManager<PythonMonitor, PythonStdState>,
} }
#[pymethods] #[pymethods]

View File

@ -5,25 +5,26 @@ use core::fmt::Debug;
use crate::{ use crate::{
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
inputs::Input, observers::UsesObservers,
observers::ObserversTuple, state::UsesState,
Error, Error,
}; };
/// A [`CombinedExecutor`] wraps a primary executor, forwarding its methods, and a secondary one /// A [`CombinedExecutor`] wraps a primary executor, forwarding its methods, and a secondary one
#[derive(Debug)] #[derive(Debug)]
pub struct CombinedExecutor<A: Debug, B: Debug> { pub struct CombinedExecutor<A, B> {
primary: A, primary: A,
secondary: B, secondary: B,
} }
impl<A: Debug, B: Debug> CombinedExecutor<A, B> { impl<A, B> CombinedExecutor<A, B> {
/// Create a new `CombinedExecutor`, wrapping the given `executor`s. /// Create a new `CombinedExecutor`, wrapping the given `executor`s.
pub fn new<EM, I, S, Z>(primary: A, secondary: B) -> Self pub fn new<EM, Z>(primary: A, secondary: B) -> Self
where where
A: Executor<EM, I, S, Z>, A: Executor<EM, Z>,
B: Executor<EM, I, S, Z>, B: Executor<EM, Z, State = A::State>,
I: Input, EM: UsesState<State = A::State>,
Z: UsesState<State = A::State>,
{ {
Self { primary, secondary } Self { primary, secondary }
} }
@ -39,18 +40,19 @@ impl<A: Debug, B: Debug> CombinedExecutor<A, B> {
} }
} }
impl<A, B, EM, I, S, Z> Executor<EM, I, S, Z> for CombinedExecutor<A, B> impl<A, B, EM, Z> Executor<EM, Z> for CombinedExecutor<A, B>
where where
A: Executor<EM, I, S, Z>, A: Executor<EM, Z>,
B: Executor<EM, I, S, Z>, B: Executor<EM, Z, State = A::State>,
I: Input, EM: UsesState<State = A::State>,
Z: UsesState<State = A::State>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
let ret = self.primary.run_target(fuzzer, state, mgr, input); let ret = self.primary.run_target(fuzzer, state, mgr, input);
self.primary.post_run_reset(); self.primary.post_run_reset();
@ -59,19 +61,31 @@ where
} }
} }
impl<A, B, I, OT, S> HasObservers<I, OT, S> for CombinedExecutor<A, B> impl<A, B> UsesState for CombinedExecutor<A, B>
where where
A: HasObservers<I, OT, S>, A: UsesState,
B: Debug, {
OT: ObserversTuple<I, S>, type State = A::State;
}
impl<A, B> UsesObservers for CombinedExecutor<A, B>
where
A: UsesObservers,
{
type Observers = A::Observers;
}
impl<A, B> HasObservers for CombinedExecutor<A, B>
where
A: HasObservers,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &Self::Observers {
self.primary.observers() self.primary.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> &mut Self::Observers {
self.primary.observers_mut() self.primary.observers_mut()
} }
} }

View File

@ -26,8 +26,9 @@ use crate::{
tuples::MatchName, tuples::MatchName,
AsSlice, AsSlice,
}, },
inputs::HasTargetBytes, inputs::{HasTargetBytes, UsesInput},
observers::ObserversTuple, observers::{ObserversTuple, UsesObservers},
state::UsesState,
std::borrow::ToOwned, std::borrow::ToOwned,
}; };
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -149,20 +150,16 @@ impl CommandConfigurator for StdCommandConfigurator {
/// A `CommandExecutor` is a wrapper around [`std::process::Command`] to execute a target as a child process. /// A `CommandExecutor` is a wrapper around [`std::process::Command`] to execute a target as a child process.
/// Construct a `CommandExecutor` by implementing [`CommandConfigurator`] for a type of your choice and calling [`CommandConfigurator::into_executor`] on it. /// Construct a `CommandExecutor` by implementing [`CommandConfigurator`] for a type of your choice and calling [`CommandConfigurator::into_executor`] on it.
/// Instead, you can also use [`CommandExecutor::builder()`] to construct a [`CommandExecutor`] backed by a [`StdCommandConfigurator`]. /// Instead, you can use [`CommandExecutor::builder()`] to construct a [`CommandExecutor`] backed by a [`StdCommandConfigurator`].
pub struct CommandExecutor<EM, I, OT, S, T, Z> pub struct CommandExecutor<EM, OT, S, T, Z> {
where /// The wrapped comand configurer
T: Debug,
OT: Debug,
{
/// The wrapped command configurer
configurer: T, configurer: T,
/// The obsevers used by this executor /// The observers used by this executor
observers: OT, observers: OT,
phantom: PhantomData<(EM, I, S, Z)>, phantom: PhantomData<(EM, S, Z)>,
} }
impl CommandExecutor<(), (), (), (), (), ()> { impl CommandExecutor<(), (), (), (), ()> {
/// Creates a builder for a new [`CommandExecutor`], /// Creates a builder for a new [`CommandExecutor`],
/// backed by a [`StdCommandConfigurator`] /// backed by a [`StdCommandConfigurator`]
/// This is usually the easiest way to construct a [`CommandExecutor`]. /// This is usually the easiest way to construct a [`CommandExecutor`].
@ -181,7 +178,7 @@ impl CommandExecutor<(), (), (), (), (), ()> {
} }
} }
impl<EM, I, OT, S, T, Z> Debug for CommandExecutor<EM, I, OT, S, T, Z> impl<EM, OT, S, T, Z> Debug for CommandExecutor<EM, OT, S, T, Z>
where where
T: Debug, T: Debug,
OT: Debug, OT: Debug,
@ -194,7 +191,7 @@ where
} }
} }
impl<EM, I, OT, S, T, Z> CommandExecutor<EM, I, OT, S, T, Z> impl<EM, OT, S, T, Z> CommandExecutor<EM, OT, S, T, Z>
where where
T: Debug, T: Debug,
OT: Debug, OT: Debug,
@ -205,9 +202,10 @@ where
} }
} }
impl<EM, I, OT, S, Z> CommandExecutor<EM, I, OT, S, StdCommandConfigurator, Z> impl<EM, OT, S, Z> CommandExecutor<EM, OT, S, StdCommandConfigurator, Z>
where where
OT: MatchName + Debug + ObserversTuple<I, S>, OT: MatchName + Debug + ObserversTuple<S>,
S: UsesInput,
{ {
/// Creates a new `CommandExecutor`. /// Creates a new `CommandExecutor`.
/// Instead of parsing the Command for `@@`, it will /// Instead of parsing the Command for `@@`, it will
@ -295,19 +293,21 @@ where
// this only works on unix because of the reliance on checking the process signal for detecting OOM // this only works on unix because of the reliance on checking the process signal for detecting OOM
#[cfg(all(feature = "std", unix))] #[cfg(all(feature = "std", unix))]
impl<EM, I, OT, S, T, Z> Executor<EM, I, S, Z> for CommandExecutor<EM, I, OT, S, T, Z> impl<EM, OT, S, T, Z> Executor<EM, Z> for CommandExecutor<EM, OT, S, T, Z>
where where
I: Input + HasTargetBytes, EM: UsesState<State = S>,
T: CommandConfigurator, S: UsesInput,
OT: Debug + MatchName + ObserversTuple<I, S>, S::Input: HasTargetBytes,
T: Debug, T: CommandConfigurator + Debug,
OT: Debug + MatchName + ObserversTuple<S>,
Z: UsesState<State = S>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut S, _state: &mut Self::State,
_mgr: &mut EM, _mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
use std::os::unix::prelude::ExitStatusExt; use std::os::unix::prelude::ExitStatusExt;
@ -357,8 +357,26 @@ where
} }
} }
impl<EM, I, OT: ObserversTuple<I, S>, S, T: Debug, Z> HasObservers<I, OT, S> impl<EM, OT, S, T, Z> UsesState for CommandExecutor<EM, OT, S, T, Z>
for CommandExecutor<EM, I, OT, S, T, Z> where
S: UsesInput,
{
type State = S;
}
impl<EM, OT, S, T, Z> UsesObservers for CommandExecutor<EM, OT, S, T, Z>
where
OT: ObserversTuple<S>,
S: UsesInput,
{
type Observers = OT;
}
impl<EM, OT, S, T, Z> HasObservers for CommandExecutor<EM, OT, S, T, Z>
where
S: UsesInput,
T: Debug,
OT: ObserversTuple<S>,
{ {
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
&self.observers &self.observers
@ -508,13 +526,14 @@ impl CommandExecutorBuilder {
self self
} }
/// Builds the `CommandExecutor`. /// Builds the `ComandExecutor`
pub fn build<EM, I, OT, S, Z>( pub fn build<EM, OT, S, Z>(
&self, &self,
mut observers: OT, mut observers: OT,
) -> Result<CommandExecutor<EM, I, OT, S, StdCommandConfigurator, Z>, Error> ) -> Result<CommandExecutor<EM, OT, S, StdCommandConfigurator, Z>, Error>
where where
OT: Debug + MatchName + ObserversTuple<I, S>, OT: Debug + MatchName + ObserversTuple<S>,
S: UsesInput,
{ {
let program = if let Some(program) = &self.program { let program = if let Some(program) = &self.program {
program program
@ -560,7 +579,7 @@ impl CommandExecutorBuilder {
input_location: self.input_location.clone(), input_location: self.input_location.clone(),
command, command,
}; };
Ok(configurator.into_executor::<EM, I, OT, S, Z>(observers)) Ok(configurator.into_executor::<EM, OT, S, Z>(observers))
} }
} }
@ -569,7 +588,7 @@ impl CommandExecutorBuilder {
#[cfg_attr(all(feature = "std", unix), doc = " ```")] #[cfg_attr(all(feature = "std", unix), doc = " ```")]
#[cfg_attr(not(all(feature = "std", unix)), doc = " ```ignore")] #[cfg_attr(not(all(feature = "std", unix)), doc = " ```ignore")]
/// use std::{io::Write, process::{Stdio, Command, Child}}; /// use std::{io::Write, process::{Stdio, Command, Child}};
/// use libafl::{Error, bolts::AsSlice, inputs::{Input, HasTargetBytes}, executors::{Executor, command::CommandConfigurator}}; /// use libafl::{Error, bolts::AsSlice, inputs::{HasTargetBytes, Input, UsesInput}, executors::{Executor, command::CommandConfigurator}, state::UsesState};
/// #[derive(Debug)] /// #[derive(Debug)]
/// struct MyExecutor; /// struct MyExecutor;
/// ///
@ -591,8 +610,14 @@ impl CommandExecutorBuilder {
/// } /// }
/// } /// }
/// ///
/// fn make_executor<EM, I: Input + HasTargetBytes, S, Z>() -> impl Executor<EM, I, S, Z> { /// fn make_executor<EM, Z>() -> impl Executor<EM, Z>
/// MyExecutor.into_executor(()) /// where
/// EM: UsesState,
/// Z: UsesState<State = EM::State>,
/// EM::State: UsesInput,
/// EM::Input: HasTargetBytes
/// {
/// MyExecutor.into_executor((), None, None, None)
/// } /// }
/// ``` /// ```
@ -604,8 +629,7 @@ pub trait CommandConfigurator: Sized + Debug {
I: Input + HasTargetBytes; I: Input + HasTargetBytes;
/// Create an `Executor` from this `CommandConfigurator`. /// Create an `Executor` from this `CommandConfigurator`.
/// It will observe the outputs with the respective given observer name. fn into_executor<EM, OT, S, Z>(self, observers: OT) -> CommandExecutor<EM, OT, S, Self, Z>
fn into_executor<EM, I, OT, S, Z>(self, observers: OT) -> CommandExecutor<EM, I, OT, S, Self, Z>
where where
OT: Debug + MatchName, OT: Debug + MatchName,
{ {
@ -627,12 +651,14 @@ mod tests {
}, },
inputs::BytesInput, inputs::BytesInput,
monitors::SimpleMonitor, monitors::SimpleMonitor,
state::NopState,
NopFuzzer,
}; };
#[test] #[test]
#[cfg(unix)] #[cfg(unix)]
fn test_builder() { fn test_builder() {
let mut mgr = SimpleEventManager::<BytesInput, _, ()>::new(SimpleMonitor::new(|status| { let mut mgr = SimpleEventManager::new(SimpleMonitor::new(|status| {
println!("{status}"); println!("{status}");
})); }));
@ -645,8 +671,8 @@ mod tests {
executor executor
.run_target( .run_target(
&mut (), &mut NopFuzzer::new(),
&mut (), &mut NopState::new(),
&mut mgr, &mut mgr,
&BytesInput::new(b"test".to_vec()), &BytesInput::new(b"test".to_vec()),
) )
@ -657,7 +683,8 @@ mod tests {
#[cfg(unix)] #[cfg(unix)]
fn test_parse_afl_cmdline() { fn test_parse_afl_cmdline() {
use alloc::string::ToString; use alloc::string::ToString;
let mut mgr = SimpleEventManager::<BytesInput, _, ()>::new(SimpleMonitor::new(|status| {
let mut mgr = SimpleEventManager::new(SimpleMonitor::new(|status| {
println!("{status}"); println!("{status}");
})); }));
@ -666,8 +693,8 @@ mod tests {
.unwrap(); .unwrap();
executor executor
.run_target( .run_target(
&mut (), &mut NopFuzzer::new(),
&mut (), &mut NopState::new(),
&mut mgr, &mut mgr,
&BytesInput::new(b"test".to_vec()), &BytesInput::new(b"test".to_vec()),
) )

View File

@ -1,5 +1,5 @@
//! Executor for differential fuzzing. //! Executor for differential fuzzing.
//! It wraps two exeutors that will be run after each other with the same input. //! It wraps two executors that will be run after each other with the same input.
//! In comparison to the [`crate::executors::CombinedExecutor`] it also runs the secondary executor in `run_target`. //! In comparison to the [`crate::executors::CombinedExecutor`] it also runs the secondary executor in `run_target`.
//! //!
use core::{cell::UnsafeCell, fmt::Debug}; use core::{cell::UnsafeCell, fmt::Debug};
@ -9,38 +9,28 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::{ownedref::OwnedPtrMut, tuples::MatchName}, bolts::{ownedref::OwnedPtrMut, tuples::MatchName},
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
inputs::Input, inputs::UsesInput,
observers::ObserversTuple, observers::{ObserversTuple, UsesObservers},
state::UsesState,
Error, Error,
}; };
/// A [`DiffExecutor`] wraps a primary executor, forwarding its methods, and a secondary one /// A [`DiffExecutor`] wraps a primary executor, forwarding its methods, and a secondary one
#[derive(Debug)] #[derive(Debug)]
pub struct DiffExecutor<A, B, OTA, OTB> pub struct DiffExecutor<A, B, OTA, OTB> {
where
A: Debug,
B: Debug,
OTA: Debug,
OTB: Debug,
{
primary: A, primary: A,
secondary: B, secondary: B,
observers: UnsafeCell<ProxyObserversTuple<OTA, OTB>>, observers: UnsafeCell<ProxyObserversTuple<OTA, OTB>>,
} }
impl<A, B, OTA, OTB> DiffExecutor<A, B, OTA, OTB> impl<A, B, OTA, OTB> DiffExecutor<A, B, OTA, OTB> {
where
A: Debug,
B: Debug,
OTA: Debug,
OTB: Debug,
{
/// Create a new `DiffExecutor`, wrapping the given `executor`s. /// Create a new `DiffExecutor`, wrapping the given `executor`s.
pub fn new<EM, I, S, Z>(primary: A, secondary: B) -> Self pub fn new<EM, Z>(primary: A, secondary: B) -> Self
where where
A: Executor<EM, I, S, Z>, A: Executor<EM, Z>,
B: Executor<EM, I, S, Z>, B: Executor<EM, Z, State = A::State>,
I: Input, EM: UsesState<State = A::State>,
Z: UsesState<State = A::State>,
{ {
Self { Self {
primary, primary,
@ -63,20 +53,21 @@ where
} }
} }
impl<A, B, EM, I, OTA, OTB, S, Z> Executor<EM, I, S, Z> for DiffExecutor<A, B, OTA, OTB> impl<A, B, EM, OTA, OTB, Z> Executor<EM, Z> for DiffExecutor<A, B, OTA, OTB>
where where
A: Executor<EM, I, S, Z>, A: Executor<EM, Z>,
B: Executor<EM, I, S, Z>, B: Executor<EM, Z, State = A::State>,
I: Input, EM: UsesState<State = A::State>,
OTA: Debug, OTA: Debug,
OTB: Debug, OTB: Debug,
Z: UsesState<State = A::State>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
let ret1 = self.primary.run_target(fuzzer, state, mgr, input)?; let ret1 = self.primary.run_target(fuzzer, state, mgr, input)?;
self.primary.post_run_reset(); self.primary.post_run_reset();
@ -104,12 +95,13 @@ pub struct ProxyObserversTuple<A, B> {
secondary: OwnedPtrMut<B>, secondary: OwnedPtrMut<B>,
} }
impl<A, B, I, S> ObserversTuple<I, S> for ProxyObserversTuple<A, B> impl<A, B, S> ObserversTuple<S> for ProxyObserversTuple<A, B>
where where
A: ObserversTuple<I, S>, A: ObserversTuple<S>,
B: ObserversTuple<I, S>, B: ObserversTuple<S>,
S: UsesInput,
{ {
fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> { fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.primary.as_mut().pre_exec_all(state, input)?; self.primary.as_mut().pre_exec_all(state, input)?;
self.secondary.as_mut().pre_exec_all(state, input) self.secondary.as_mut().pre_exec_all(state, input)
} }
@ -117,7 +109,7 @@ where
fn post_exec_all( fn post_exec_all(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &I, input: &S::Input,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.primary self.primary
@ -128,7 +120,7 @@ where
.post_exec_all(state, input, exit_kind) .post_exec_all(state, input, exit_kind)
} }
fn pre_exec_child_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> { fn pre_exec_child_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.primary.as_mut().pre_exec_child_all(state, input)?; self.primary.as_mut().pre_exec_child_all(state, input)?;
self.secondary.as_mut().pre_exec_child_all(state, input) self.secondary.as_mut().pre_exec_child_all(state, input)
} }
@ -136,7 +128,7 @@ where
fn post_exec_child_all( fn post_exec_child_all(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &I, input: &S::Input,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.primary self.primary
@ -197,13 +189,30 @@ impl<A, B> ProxyObserversTuple<A, B> {
} }
} }
impl<A, B, I, OTA, OTB, S> HasObservers<I, ProxyObserversTuple<OTA, OTB>, S> impl<A, B, OTA, OTB> UsesObservers for DiffExecutor<A, B, OTA, OTB>
for DiffExecutor<A, B, OTA, OTB>
where where
A: HasObservers<I, OTA, S>, A: HasObservers<Observers = OTA>,
B: HasObservers<I, OTB, S>, B: HasObservers<Observers = OTB, State = A::State>,
OTA: ObserversTuple<I, S>, OTA: ObserversTuple<A::State>,
OTB: ObserversTuple<I, S>, OTB: ObserversTuple<A::State>,
{
type Observers = ProxyObserversTuple<OTA, OTB>;
}
impl<A, B, OTA, OTB> UsesState for DiffExecutor<A, B, OTA, OTB>
where
A: UsesState,
B: UsesState<State = A::State>,
{
type State = A::State;
}
impl<A, B, OTA, OTB> HasObservers for DiffExecutor<A, B, OTA, OTB>
where
A: HasObservers<Observers = OTA>,
B: HasObservers<Observers = OTB, State = A::State>,
OTA: ObserversTuple<A::State>,
OTB: ObserversTuple<A::State>,
{ {
#[inline] #[inline]
fn observers(&self) -> &ProxyObserversTuple<OTA, OTB> { fn observers(&self) -> &ProxyObserversTuple<OTA, OTB> {

View File

@ -31,9 +31,12 @@ use crate::{
AsMutSlice, AsSlice, AsMutSlice, AsSlice,
}, },
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input, UsesInput},
mutators::Tokens, mutators::Tokens,
observers::{get_asan_runtime_flags_with_log_path, AsanBacktraceObserver, ObserversTuple}, observers::{
get_asan_runtime_flags_with_log_path, AsanBacktraceObserver, ObserversTuple, UsesObservers,
},
state::UsesState,
Error, Error,
}; };
@ -370,13 +373,13 @@ pub trait HasForkserver {
/// The timeout forkserver executor that wraps around the standard forkserver executor and sets a timeout before each run. /// The timeout forkserver executor that wraps around the standard forkserver executor and sets a timeout before each run.
#[derive(Debug)] #[derive(Debug)]
pub struct TimeoutForkserverExecutor<E: Debug> { pub struct TimeoutForkserverExecutor<E> {
executor: E, executor: E,
timeout: TimeSpec, timeout: TimeSpec,
signal: Signal, signal: Signal,
} }
impl<E: Debug> TimeoutForkserverExecutor<E> { impl<E> TimeoutForkserverExecutor<E> {
/// Create a new [`TimeoutForkserverExecutor`] /// Create a new [`TimeoutForkserverExecutor`]
pub fn new(executor: E, exec_tmout: Duration) -> Result<Self, Error> { pub fn new(executor: E, exec_tmout: Duration) -> Result<Self, Error> {
let signal = Signal::SIGKILL; let signal = Signal::SIGKILL;
@ -395,18 +398,20 @@ impl<E: Debug> TimeoutForkserverExecutor<E> {
} }
} }
impl<E: Debug, EM, I, S, Z> Executor<EM, I, S, Z> for TimeoutForkserverExecutor<E> impl<E, EM, Z> Executor<EM, Z> for TimeoutForkserverExecutor<E>
where where
I: Input + HasTargetBytes, E: Executor<EM, Z> + HasForkserver + Debug,
E: Executor<EM, I, S, Z> + HasForkserver, E::Input: HasTargetBytes,
EM: UsesState<State = E::State>,
Z: UsesState<State = E::State>,
{ {
#[inline] #[inline]
fn run_target( fn run_target(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut S, _state: &mut Self::State,
_mgr: &mut EM, _mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
let mut exit_kind = ExitKind::Ok; let mut exit_kind = ExitKind::Ok;
@ -491,9 +496,8 @@ where
/// This [`Executor`] can run binaries compiled for AFL/AFL++ that make use of a forkserver. /// This [`Executor`] can run binaries compiled for AFL/AFL++ that make use of a forkserver.
/// Shared memory feature is also available, but you have to set things up in your code. /// Shared memory feature is also available, but you have to set things up in your code.
/// Please refer to AFL++'s docs. <https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.persistent_mode.md> /// Please refer to AFL++'s docs. <https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.persistent_mode.md>
pub struct ForkserverExecutor<I, OT, S, SP> pub struct ForkserverExecutor<OT, S, SP>
where where
OT: Debug,
SP: ShMemProvider, SP: ShMemProvider,
{ {
target: OsString, target: OsString,
@ -502,12 +506,12 @@ where
forkserver: Forkserver, forkserver: Forkserver,
observers: OT, observers: OT,
map: Option<SP::ShMem>, map: Option<SP::ShMem>,
phantom: PhantomData<(I, S)>, phantom: PhantomData<S>,
/// Cache that indicates if we have a `ASan` observer registered. /// Cache that indicates if we have a `ASan` observer registered.
has_asan_observer: Option<bool>, has_asan_observer: Option<bool>,
} }
impl<I, OT, S, SP> Debug for ForkserverExecutor<I, OT, S, SP> impl<OT, S, SP> Debug for ForkserverExecutor<OT, S, SP>
where where
OT: Debug, OT: Debug,
SP: ShMemProvider, SP: ShMemProvider,
@ -524,7 +528,7 @@ where
} }
} }
impl ForkserverExecutor<(), (), (), StdShMemProvider> { impl ForkserverExecutor<(), (), StdShMemProvider> {
/// Builder for `ForkserverExecutor` /// Builder for `ForkserverExecutor`
#[must_use] #[must_use]
pub fn builder() -> ForkserverExecutorBuilder<'static, StdShMemProvider> { pub fn builder() -> ForkserverExecutorBuilder<'static, StdShMemProvider> {
@ -532,10 +536,10 @@ impl ForkserverExecutor<(), (), (), StdShMemProvider> {
} }
} }
impl<I, OT, S, SP> ForkserverExecutor<I, OT, S, SP> impl<OT, S, SP> ForkserverExecutor<OT, S, SP>
where where
I: Input + HasTargetBytes, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesState,
SP: ShMemProvider, SP: ShMemProvider,
{ {
/// The `target` binary that's going to run. /// The `target` binary that's going to run.
@ -578,13 +582,11 @@ pub struct ForkserverExecutorBuilder<'a, SP> {
impl<'a, SP> ForkserverExecutorBuilder<'a, SP> { impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
/// Builds `ForkserverExecutor`. /// Builds `ForkserverExecutor`.
#[allow(clippy::pedantic)] #[allow(clippy::pedantic)]
pub fn build<I, OT, S>( pub fn build<OT, S>(&mut self, observers: OT) -> Result<ForkserverExecutor<OT, S, SP>, Error>
&mut self,
observers: OT,
) -> Result<ForkserverExecutor<I, OT, S, SP>, Error>
where where
I: Input + HasTargetBytes, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
S::Input: Input + HasTargetBytes,
SP: ShMemProvider, SP: ShMemProvider,
{ {
let input_filename = match &self.input_filename { let input_filename = match &self.input_filename {
@ -895,19 +897,22 @@ impl<'a> Default for ForkserverExecutorBuilder<'a, StdShMemProvider> {
} }
} }
impl<EM, I, OT, S, SP, Z> Executor<EM, I, S, Z> for ForkserverExecutor<I, OT, S, SP> impl<EM, OT, S, SP, Z> Executor<EM, Z> for ForkserverExecutor<OT, S, SP>
where where
I: Input + HasTargetBytes, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>,
SP: ShMemProvider, SP: ShMemProvider,
S: UsesInput,
S::Input: HasTargetBytes,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
{ {
#[inline] #[inline]
fn run_target( fn run_target(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut S, _state: &mut Self::State,
_mgr: &mut EM, _mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
let mut exit_kind = ExitKind::Ok; let mut exit_kind = ExitKind::Ok;
@ -984,10 +989,27 @@ where
} }
} }
impl<I, OT, S, SP> HasObservers<I, OT, S> for ForkserverExecutor<I, OT, S, SP> impl<OT, S, SP> UsesState for ForkserverExecutor<OT, S, SP>
where where
I: Input + HasTargetBytes, S: UsesInput,
OT: ObserversTuple<I, S>, SP: ShMemProvider,
{
type State = S;
}
impl<OT, S, SP> UsesObservers for ForkserverExecutor<OT, S, SP>
where
OT: ObserversTuple<S>,
S: UsesInput,
SP: ShMemProvider,
{
type Observers = OT;
}
impl<OT, S, SP> HasObservers for ForkserverExecutor<OT, S, SP>
where
OT: ObserversTuple<S>,
S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
{ {
#[inline] #[inline]
@ -1001,10 +1023,11 @@ where
} }
} }
impl<I, OT, S, SP> HasForkserver for ForkserverExecutor<I, OT, S, SP> impl<OT, S, SP> HasForkserver for ForkserverExecutor<OT, S, SP>
where where
I: Input + HasTargetBytes, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
S::Input: Input + HasTargetBytes,
SP: ShMemProvider, SP: ShMemProvider,
{ {
type SP = SP; type SP = SP;
@ -1040,18 +1063,31 @@ where
} }
} }
impl<E, I, OT, S> HasObservers<I, OT, S> for TimeoutForkserverExecutor<E> impl<E> UsesState for TimeoutForkserverExecutor<E>
where where
E: HasObservers<I, OT, S>, E: UsesState,
OT: ObserversTuple<I, S>, {
type State = E::State;
}
impl<E> UsesObservers for TimeoutForkserverExecutor<E>
where
E: UsesObservers,
{
type Observers = E::Observers;
}
impl<E> HasObservers for TimeoutForkserverExecutor<E>
where
E: HasObservers,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &Self::Observers {
self.executor.observers() self.executor.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> &mut Self::Observers {
self.executor.observers_mut() self.executor.observers_mut()
} }
} }
@ -1069,10 +1105,10 @@ mod tests {
AsMutSlice, AsMutSlice,
}, },
executors::forkserver::ForkserverExecutorBuilder, executors::forkserver::ForkserverExecutorBuilder,
inputs::NopInput,
observers::{ConstMapObserver, HitcountsMapObserver}, observers::{ConstMapObserver, HitcountsMapObserver},
Error, Error,
}; };
#[test] #[test]
#[serial] #[serial]
fn test_forkserver() { fn test_forkserver() {
@ -1096,7 +1132,7 @@ mod tests {
.args(&args) .args(&args)
.debug_child(false) .debug_child(false)
.shmem_provider(&mut shmem_provider) .shmem_provider(&mut shmem_provider)
.build::<NopInput, _, ()>(tuple_list!(edges_observer)); .build::<_, ()>(tuple_list!(edges_observer));
// Since /usr/bin/echo is not a instrumented binary file, the test will just check if the forkserver has failed at the initial handshake // Since /usr/bin/echo is not a instrumented binary file, the test will just check if the forkserver has failed at the initial handshake
let result = match executor { let result = match executor {

View File

@ -46,27 +46,31 @@ use crate::{
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::Input, inputs::UsesInput,
observers::ObserversTuple, observers::{ObserversTuple, UsesObservers},
state::{HasClientPerfMonitor, HasSolutions}, state::{HasClientPerfMonitor, HasSolutions, UsesState},
Error, Error,
}; };
/// The process executor simply calls a target function, as mutable reference to a closure /// The process executor simply calls a target function, as mutable reference to a closure
pub type InProcessExecutor<'a, H, I, OT, S> = GenericInProcessExecutor<H, &'a mut H, I, OT, S>; pub type InProcessExecutor<'a, H, OT, S> = GenericInProcessExecutor<H, &'a mut H, OT, S>;
/// The process executor simply calls a target function, as boxed `FnMut` trait object /// The process executor simply calls a target function, as boxed `FnMut` trait object
pub type OwnedInProcessExecutor<I, OT, S> = pub type OwnedInProcessExecutor<OT, S> = GenericInProcessExecutor<
GenericInProcessExecutor<dyn FnMut(&I) -> ExitKind, Box<dyn FnMut(&I) -> ExitKind>, I, OT, S>; dyn FnMut(&<S as UsesInput>::Input) -> ExitKind,
Box<dyn FnMut(&<S as UsesInput>::Input) -> ExitKind>,
OT,
S,
>;
/// The inmem executor simply calls a target function, then returns afterwards. /// The inmem executor simply calls a target function, then returns afterwards.
#[allow(dead_code)] #[allow(dead_code)]
pub struct GenericInProcessExecutor<H, HB, I, OT, S> pub struct GenericInProcessExecutor<H, HB, OT, S>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: FnMut(&S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>, HB: BorrowMut<H>,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
{ {
/// The harness function, being executed for each fuzzing loop execution /// The harness function, being executed for each fuzzing loop execution
harness_fn: HB, harness_fn: HB,
@ -74,15 +78,15 @@ where
observers: OT, observers: OT,
// Crash and timeout hah // Crash and timeout hah
handlers: InProcessHandlers, handlers: InProcessHandlers,
phantom: PhantomData<(I, S, *const H)>, phantom: PhantomData<(S, *const H)>,
} }
impl<H, HB, I, OT, S> Debug for GenericInProcessExecutor<H, HB, I, OT, S> impl<H, HB, OT, S> Debug for GenericInProcessExecutor<H, HB, OT, S>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: FnMut(&S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>, HB: BorrowMut<H>,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("GenericInProcessExecutor") f.debug_struct("GenericInProcessExecutor")
@ -92,19 +96,41 @@ where
} }
} }
impl<EM, H, HB, I, OT, S, Z> Executor<EM, I, S, Z> for GenericInProcessExecutor<H, HB, I, OT, S> impl<H, HB, OT, S> UsesState for GenericInProcessExecutor<H, HB, OT, S>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: ?Sized + FnMut(&S::Input) -> ExitKind,
HB: BorrowMut<H>, HB: BorrowMut<H>,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
{
type State = S;
}
impl<H, HB, OT, S> UsesObservers for GenericInProcessExecutor<H, HB, OT, S>
where
H: ?Sized + FnMut(&S::Input) -> ExitKind,
HB: BorrowMut<H>,
OT: ObserversTuple<S>,
S: UsesInput,
{
type Observers = OT;
}
impl<EM, H, HB, OT, S, Z> Executor<EM, Z> for GenericInProcessExecutor<H, HB, OT, S>
where
H: FnMut(&S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
EM: UsesState<State = S>,
OT: ObserversTuple<S>,
S: UsesInput,
Z: UsesState<State = S>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
self.handlers self.handlers
.pre_run_target(self, fuzzer, state, mgr, input); .pre_run_target(self, fuzzer, state, mgr, input);
@ -116,12 +142,12 @@ where
} }
} }
impl<H, HB, I, OT, S> HasObservers<I, OT, S> for GenericInProcessExecutor<H, HB, I, OT, S> impl<H, HB, OT, S> HasObservers for GenericInProcessExecutor<H, HB, OT, S>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: FnMut(&S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>, HB: BorrowMut<H>,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
@ -134,12 +160,12 @@ where
} }
} }
impl<H, HB, I, OT, S> GenericInProcessExecutor<H, HB, I, OT, S> impl<H, HB, OT, S> GenericInProcessExecutor<H, HB, OT, S>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: FnMut(&<S as UsesInput>::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>, HB: BorrowMut<H>,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: HasSolutions + HasClientPerfMonitor,
{ {
/// Create a new in mem executor. /// Create a new in mem executor.
/// Caution: crash and restart in one of them will lead to odd behavior if multiple are used, /// Caution: crash and restart in one of them will lead to odd behavior if multiple are used,
@ -155,12 +181,12 @@ where
_event_mgr: &mut EM, _event_mgr: &mut EM,
) -> Result<Self, Error> ) -> Result<Self, Error>
where where
EM: EventFirer<I> + EventRestarter<S>, Self: Executor<EM, Z, State = S>,
OF: Feedback<I, S>, EM: EventFirer<State = S> + EventRestarter,
S: HasSolutions<I> + HasClientPerfMonitor, OF: Feedback<S>,
Z: HasObjective<I, OF, S>, Z: HasObjective<OF, State = S>,
{ {
let handlers = InProcessHandlers::new::<Self, EM, I, OF, OT, S, Z, H>()?; let handlers = InProcessHandlers::new::<Self, EM, OF, Z, H>()?;
#[cfg(windows)] #[cfg(windows)]
unsafe { unsafe {
/* /*
@ -217,11 +243,11 @@ pub trait HasInProcessHandlers {
} }
#[cfg(windows)] #[cfg(windows)]
impl<'a, H, I, OT, S> HasInProcessHandlers for InProcessExecutor<'a, H, I, OT, S> impl<'a, H, OT, S> HasInProcessHandlers for InProcessExecutor<'a, H, OT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
{ {
/// the timeout handler /// the timeout handler
#[inline] #[inline]
@ -310,28 +336,26 @@ impl InProcessHandlers {
} }
/// Create new [`InProcessHandlers`]. /// Create new [`InProcessHandlers`].
pub fn new<E, EM, I, OF, OT, S, Z, H>() -> Result<Self, Error> pub fn new<E, EM, OF, Z, H>() -> Result<Self, Error>
where where
I: Input, E: Executor<EM, Z> + HasObservers,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OT: ObserversTuple<I, S>, OF: Feedback<E::State>,
EM: EventFirer<I> + EventRestarter<S>, E::State: HasSolutions + HasClientPerfMonitor,
OF: Feedback<I, S>, Z: HasObjective<OF, State = E::State>,
S: HasSolutions<I> + HasClientPerfMonitor, H: FnMut(&<E::State as UsesInput>::Input) -> ExitKind + ?Sized,
Z: HasObjective<I, OF, S>,
H: FnMut(&I) -> ExitKind + ?Sized,
{ {
#[cfg(unix)] #[cfg(unix)]
unsafe { unsafe {
let data = &mut GLOBAL_STATE; let data = &mut GLOBAL_STATE;
#[cfg(feature = "std")] #[cfg(feature = "std")]
unix_signal_handler::setup_panic_hook::<E, EM, I, OF, OT, S, Z>(); unix_signal_handler::setup_panic_hook::<E, EM, OF, Z>();
setup_signal_handler(data)?; setup_signal_handler(data)?;
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
Ok(Self { Ok(Self {
crash_handler: unix_signal_handler::inproc_crash_handler::<E, EM, I, OF, OT, S, Z> crash_handler: unix_signal_handler::inproc_crash_handler::<E, EM, OF, Z>
as *const c_void, as *const c_void,
timeout_handler: unix_signal_handler::inproc_timeout_handler::<E, EM, I, OF, OT, S, Z> timeout_handler: unix_signal_handler::inproc_timeout_handler::<E, EM, OF, Z>
as *const _, as *const _,
}) })
} }
@ -339,29 +363,15 @@ impl InProcessHandlers {
unsafe { unsafe {
let data = &mut GLOBAL_STATE; let data = &mut GLOBAL_STATE;
#[cfg(feature = "std")] #[cfg(feature = "std")]
windows_exception_handler::setup_panic_hook::<E, EM, I, OF, OT, S, Z>(); windows_exception_handler::setup_panic_hook::<E, EM, OF, Z>();
setup_exception_handler(data)?; setup_exception_handler(data)?;
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
Ok(Self { Ok(Self {
crash_handler: windows_exception_handler::inproc_crash_handler::< crash_handler: windows_exception_handler::inproc_crash_handler::<E, EM, OF, Z>
E, as *const _,
EM, timeout_handler: windows_exception_handler::inproc_timeout_handler::<E, EM, OF, Z>
I, as *const c_void,
OF,
OT,
S,
Z,
> as *const _,
timeout_handler: windows_exception_handler::inproc_timeout_handler::<
E,
EM,
I,
OF,
OT,
S,
Z,
> as *const c_void,
}) })
} }
#[cfg(not(any(unix, feature = "std")))] #[cfg(not(any(unix, feature = "std")))]
@ -510,7 +520,7 @@ pub fn inprocess_get_executor<'a, E>() -> Option<&'a mut E> {
unsafe { (GLOBAL_STATE.executor_ptr as *mut E).as_mut() } unsafe { (GLOBAL_STATE.executor_ptr as *mut E).as_mut() }
} }
/// Gets the inprocess [`Input`] /// Gets the inprocess input
#[must_use] #[must_use]
pub fn inprocess_get_input<'a, I>() -> Option<&'a I> { pub fn inprocess_get_input<'a, I>() -> Option<&'a I> {
unsafe { (GLOBAL_STATE.current_input_ptr as *const I).as_ref() } unsafe { (GLOBAL_STATE.current_input_ptr as *const I).as_ref() }
@ -530,6 +540,8 @@ mod unix_signal_handler {
use libc::siginfo_t; use libc::siginfo_t;
#[cfg(feature = "std")]
use crate::inputs::Input;
use crate::{ use crate::{
bolts::os::unix_signals::{ucontext_t, Handler, Signal}, bolts::os::unix_signals::{ucontext_t, Handler, Signal},
corpus::{Corpus, Testcase}, corpus::{Corpus, Testcase},
@ -540,7 +552,7 @@ mod unix_signal_handler {
}, },
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::Input, inputs::UsesInput,
observers::ObserversTuple, observers::ObserversTuple,
state::{HasClientPerfMonitor, HasMetadata, HasSolutions}, state::{HasClientPerfMonitor, HasMetadata, HasSolutions},
}; };
@ -596,15 +608,13 @@ mod unix_signal_handler {
/// invokes the `post_exec` hook on all observer in case of panic /// invokes the `post_exec` hook on all observer in case of panic
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn setup_panic_hook<E, EM, I, OF, OT, S, Z>() pub fn setup_panic_hook<E, EM, OF, Z>()
where where
E: HasObservers<I, OT, S>, E: HasObservers,
EM: EventFirer<I> + EventRestarter<S>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OT: ObserversTuple<I, S>, OF: Feedback<E::State>,
OF: Feedback<I, S>, E::State: HasSolutions + HasClientPerfMonitor,
S: HasSolutions<I> + HasClientPerfMonitor, Z: HasObjective<OF, State = E::State>,
I: Input,
Z: HasObjective<I, OF, S>,
{ {
let old_hook = panic::take_hook(); let old_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| { panic::set_hook(Box::new(move |panic_info| {
@ -614,8 +624,8 @@ mod unix_signal_handler {
// We are fuzzing! // We are fuzzing!
let executor = data.executor_mut::<E>(); let executor = data.executor_mut::<E>();
let observers = executor.observers_mut(); let observers = executor.observers_mut();
let state = data.state_mut::<S>(); let state = data.state_mut::<E::State>();
let input = data.current_input::<I>(); let input = data.current_input::<<E::State as UsesInput>::Input>();
let fuzzer = data.fuzzer_mut::<Z>(); let fuzzer = data.fuzzer_mut::<Z>();
let event_mgr = data.event_mgr_mut::<EM>(); let event_mgr = data.event_mgr_mut::<EM>();
@ -667,19 +677,17 @@ mod unix_signal_handler {
} }
#[cfg(unix)] #[cfg(unix)]
pub(crate) unsafe fn inproc_timeout_handler<E, EM, I, OF, OT, S, Z>( pub(crate) unsafe fn inproc_timeout_handler<E, EM, OF, Z>(
_signal: Signal, _signal: Signal,
_info: siginfo_t, _info: siginfo_t,
_context: &mut ucontext_t, _context: &mut ucontext_t,
data: &mut InProcessExecutorHandlerData, data: &mut InProcessExecutorHandlerData,
) where ) where
E: HasObservers<I, OT, S>, E: HasObservers,
EM: EventFirer<I> + EventRestarter<S>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OT: ObserversTuple<I, S>, OF: Feedback<E::State>,
OF: Feedback<I, S>, E::State: HasSolutions + HasClientPerfMonitor,
S: HasSolutions<I> + HasClientPerfMonitor, Z: HasObjective<OF, State = E::State>,
I: Input,
Z: HasObjective<I, OF, S>,
{ {
if !data.is_valid() { if !data.is_valid() {
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -689,11 +697,11 @@ mod unix_signal_handler {
let executor = data.executor_mut::<E>(); let executor = data.executor_mut::<E>();
let observers = executor.observers_mut(); let observers = executor.observers_mut();
let state = data.state_mut::<S>(); let state = data.state_mut::<E::State>();
let fuzzer = data.fuzzer_mut::<Z>(); let fuzzer = data.fuzzer_mut::<Z>();
let event_mgr = data.event_mgr_mut::<EM>(); let event_mgr = data.event_mgr_mut::<EM>();
let input = data.take_current_input::<I>(); let input = data.take_current_input::<<E::State as UsesInput>::Input>();
#[cfg(feature = "std")] #[cfg(feature = "std")]
println!("Timeout in fuzz run."); println!("Timeout in fuzz run.");
@ -747,19 +755,17 @@ mod unix_signal_handler {
/// Will be used for signal handling. /// Will be used for signal handling.
/// It will store the current State to shmem, then exit. /// It will store the current State to shmem, then exit.
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
pub(crate) unsafe fn inproc_crash_handler<E, EM, I, OF, OT, S, Z>( pub(crate) unsafe fn inproc_crash_handler<E, EM, OF, Z>(
signal: Signal, signal: Signal,
_info: siginfo_t, _info: siginfo_t,
_context: &mut ucontext_t, _context: &mut ucontext_t,
data: &mut InProcessExecutorHandlerData, data: &mut InProcessExecutorHandlerData,
) where ) where
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<I> + EventRestarter<S>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OT: ObserversTuple<I, S>, OF: Feedback<E::State>,
OF: Feedback<I, S>, E::State: HasSolutions + HasClientPerfMonitor,
S: HasSolutions<I> + HasClientPerfMonitor, Z: HasObjective<OF, State = E::State>,
I: Input,
Z: HasObjective<I, OF, S>,
{ {
#[cfg(all(target_os = "android", target_arch = "aarch64"))] #[cfg(all(target_os = "android", target_arch = "aarch64"))]
let _context = &mut *(((_context as *mut _ as *mut libc::c_void as usize) + 128) let _context = &mut *(((_context as *mut _ as *mut libc::c_void as usize) + 128)
@ -772,11 +778,11 @@ mod unix_signal_handler {
// disarms timeout in case of TimeoutExecutor // disarms timeout in case of TimeoutExecutor
executor.post_run_reset(); executor.post_run_reset();
let observers = executor.observers_mut(); let observers = executor.observers_mut();
let state = data.state_mut::<S>(); let state = data.state_mut::<E::State>();
let fuzzer = data.fuzzer_mut::<Z>(); let fuzzer = data.fuzzer_mut::<Z>();
let event_mgr = data.event_mgr_mut::<EM>(); let event_mgr = data.event_mgr_mut::<EM>();
let input = data.take_current_input::<I>(); let input = data.take_current_input::<<E::State as UsesInput>::Input>();
observers observers
.post_exec_all(state, input, &ExitKind::Crash) .post_exec_all(state, input, &ExitKind::Crash)
@ -898,7 +904,6 @@ mod windows_exception_handler {
}, },
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
state::{HasClientPerfMonitor, HasMetadata, HasSolutions}, state::{HasClientPerfMonitor, HasMetadata, HasSolutions},
}; };
@ -934,17 +939,17 @@ mod windows_exception_handler {
EnterCriticalSection, LeaveCriticalSection, RTL_CRITICAL_SECTION, EnterCriticalSection, LeaveCriticalSection, RTL_CRITICAL_SECTION,
}; };
use crate::inputs::UsesInput;
/// invokes the `post_exec` hook on all observer in case of panic /// invokes the `post_exec` hook on all observer in case of panic
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn setup_panic_hook<E, EM, I, OF, OT, S, Z>() pub fn setup_panic_hook<E, EM, OF, Z>()
where where
E: HasObservers<I, OT, S>, E: HasObservers,
EM: EventFirer<I> + EventRestarter<S>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OT: ObserversTuple<I, S>, OF: Feedback<E::State>,
OF: Feedback<I, S>, E::State: HasSolutions + HasClientPerfMonitor,
S: HasSolutions<I> + HasClientPerfMonitor, Z: HasObjective<OF, State = E::State>,
I: Input,
Z: HasObjective<I, OF, S>,
{ {
let old_hook = panic::take_hook(); let old_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| { panic::set_hook(Box::new(move |panic_info| {
@ -971,11 +976,11 @@ mod windows_exception_handler {
// We are fuzzing! // We are fuzzing!
let executor = data.executor_mut::<E>(); let executor = data.executor_mut::<E>();
let observers = executor.observers_mut(); let observers = executor.observers_mut();
let state = data.state_mut::<S>(); let state = data.state_mut::<E::State>();
let fuzzer = data.fuzzer_mut::<Z>(); let fuzzer = data.fuzzer_mut::<Z>();
let event_mgr = data.event_mgr_mut::<EM>(); let event_mgr = data.event_mgr_mut::<EM>();
let input = data.take_current_input::<I>(); let input = data.take_current_input::<<E::State as UsesInput>::Input>();
observers observers
.post_exec_all(state, input, &ExitKind::Crash) .post_exec_all(state, input, &ExitKind::Crash)
@ -1025,18 +1030,16 @@ mod windows_exception_handler {
})); }));
} }
pub unsafe extern "system" fn inproc_timeout_handler<E, EM, I, OF, OT, S, Z>( pub unsafe extern "system" fn inproc_timeout_handler<E, EM, OF, Z>(
_p0: *mut u8, _p0: *mut u8,
global_state: *mut c_void, global_state: *mut c_void,
_p1: *mut u8, _p1: *mut u8,
) where ) where
E: HasObservers<I, OT, S>, E: HasObservers,
EM: EventFirer<I> + EventRestarter<S>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OT: ObserversTuple<I, S>, OF: Feedback<E::State>,
OF: Feedback<I, S>, E::State: HasSolutions + HasClientPerfMonitor,
S: HasSolutions<I> + HasClientPerfMonitor, Z: HasObjective<OF, State = E::State>,
I: Input,
Z: HasObjective<I, OF, S>,
{ {
let data: &mut InProcessExecutorHandlerData = let data: &mut InProcessExecutorHandlerData =
&mut *(global_state as *mut InProcessExecutorHandlerData); &mut *(global_state as *mut InProcessExecutorHandlerData);
@ -1050,7 +1053,7 @@ mod windows_exception_handler {
if data.in_target == 1 { if data.in_target == 1 {
let executor = data.executor_mut::<E>(); let executor = data.executor_mut::<E>();
let state = data.state_mut::<S>(); let state = data.state_mut::<E::State>();
let fuzzer = data.fuzzer_mut::<Z>(); let fuzzer = data.fuzzer_mut::<Z>();
let event_mgr = data.event_mgr_mut::<EM>(); let event_mgr = data.event_mgr_mut::<EM>();
let observers = executor.observers_mut(); let observers = executor.observers_mut();
@ -1064,7 +1067,9 @@ mod windows_exception_handler {
#[cfg(feature = "std")] #[cfg(feature = "std")]
let _res = stdout().flush(); let _res = stdout().flush();
let input = (data.timeout_input_ptr as *const I).as_ref().unwrap(); let input = (data.timeout_input_ptr as *const <E::State as UsesInput>::Input)
.as_ref()
.unwrap();
data.timeout_input_ptr = ptr::null_mut(); data.timeout_input_ptr = ptr::null_mut();
observers observers
@ -1122,17 +1127,15 @@ mod windows_exception_handler {
} }
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
pub(crate) unsafe fn inproc_crash_handler<E, EM, I, OF, OT, S, Z>( pub(crate) unsafe fn inproc_crash_handler<E, EM, OF, Z>(
exception_pointers: *mut EXCEPTION_POINTERS, exception_pointers: *mut EXCEPTION_POINTERS,
data: &mut InProcessExecutorHandlerData, data: &mut InProcessExecutorHandlerData,
) where ) where
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<I> + EventRestarter<S>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OT: ObserversTuple<I, S>, OF: Feedback<E::State>,
OF: Feedback<I, S>, E::State: HasSolutions + HasClientPerfMonitor,
S: HasSolutions<I> + HasClientPerfMonitor, Z: HasObjective<OF, State = E::State>,
I: Input,
Z: HasObjective<I, OF, S>,
{ {
// Have we set a timer_before? // Have we set a timer_before?
if !(data.tp_timer as *mut windows::Win32::System::Threading::TP_TIMER).is_null() { if !(data.tp_timer as *mut windows::Win32::System::Threading::TP_TIMER).is_null() {
@ -1199,7 +1202,7 @@ mod windows_exception_handler {
data.tp_timer = ptr::null_mut(); data.tp_timer = ptr::null_mut();
} }
let state = data.state_mut::<S>(); let state = data.state_mut::<E::State>();
let fuzzer = data.fuzzer_mut::<Z>(); let fuzzer = data.fuzzer_mut::<Z>();
let event_mgr = data.event_mgr_mut::<EM>(); let event_mgr = data.event_mgr_mut::<EM>();
let observers = executor.observers_mut(); let observers = executor.observers_mut();
@ -1210,7 +1213,7 @@ mod windows_exception_handler {
drop(stdout().flush()); drop(stdout().flush());
// Make sure we don't crash in the crash handler forever. // Make sure we don't crash in the crash handler forever.
let input = data.take_current_input::<I>(); let input = data.take_current_input::<<E::State as UsesInput>::Input>();
#[cfg(feature = "std")] #[cfg(feature = "std")]
eprintln!("Child crashed!"); eprintln!("Child crashed!");
@ -1297,11 +1300,9 @@ impl InChildProcessHandlers {
} }
/// Create new [`InChildProcessHandlers`]. /// Create new [`InChildProcessHandlers`].
pub fn new<E, I, OT, S>() -> Result<Self, Error> pub fn new<E>() -> Result<Self, Error>
where where
I: Input, E: HasObservers,
E: HasObservers<I, OT, S>,
OT: ObserversTuple<I, S>,
{ {
unsafe { unsafe {
let data = &mut FORK_EXECUTOR_GLOBAL_DATA; let data = &mut FORK_EXECUTOR_GLOBAL_DATA;
@ -1309,19 +1310,16 @@ impl InChildProcessHandlers {
setup_signal_handler(data)?; setup_signal_handler(data)?;
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
Ok(Self { Ok(Self {
crash_handler: child_signal_handlers::child_crash_handler::<E, I, OT, S> crash_handler: child_signal_handlers::child_crash_handler::<E> as *const c_void,
as *const c_void,
timeout_handler: ptr::null(), timeout_handler: ptr::null(),
}) })
} }
} }
/// Create new [`InChildProcessHandlers`]. /// Create new [`InChildProcessHandlers`].
pub fn with_timeout<E, I, OT, S>() -> Result<Self, Error> pub fn with_timeout<E>() -> Result<Self, Error>
where where
I: Input, E: HasObservers,
E: HasObservers<I, OT, S>,
OT: ObserversTuple<I, S>,
{ {
unsafe { unsafe {
let data = &mut FORK_EXECUTOR_GLOBAL_DATA; let data = &mut FORK_EXECUTOR_GLOBAL_DATA;
@ -1329,10 +1327,8 @@ impl InChildProcessHandlers {
setup_signal_handler(data)?; setup_signal_handler(data)?;
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
Ok(Self { Ok(Self {
crash_handler: child_signal_handlers::child_crash_handler::<E, I, OT, S> crash_handler: child_signal_handlers::child_crash_handler::<E> as *const c_void,
as *const c_void, timeout_handler: child_signal_handlers::child_timeout_handler::<E> as *const c_void,
timeout_handler: child_signal_handlers::child_timeout_handler::<E, I, OT, S>
as *const c_void,
}) })
} }
} }
@ -1442,27 +1438,27 @@ impl Handler for InProcessForkExecutorGlobalData {
/// [`InProcessForkExecutor`] is an executor that forks the current process before each execution. /// [`InProcessForkExecutor`] is an executor that forks the current process before each execution.
#[cfg(all(feature = "std", unix))] #[cfg(all(feature = "std", unix))]
pub struct InProcessForkExecutor<'a, H, I, OT, S, SP> pub struct InProcessForkExecutor<'a, H, OT, S, SP>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: FnMut(&S::Input) -> ExitKind + ?Sized,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
{ {
harness_fn: &'a mut H, harness_fn: &'a mut H,
shmem_provider: SP, shmem_provider: SP,
observers: OT, observers: OT,
handlers: InChildProcessHandlers, handlers: InChildProcessHandlers,
phantom: PhantomData<(I, S)>, phantom: PhantomData<S>,
} }
/// Timeout executor for [`InProcessForkExecutor`] /// Timeout executor for [`InProcessForkExecutor`]
#[cfg(all(feature = "std", target_os = "linux"))] #[cfg(all(feature = "std", target_os = "linux"))]
pub struct TimeoutInProcessForkExecutor<'a, H, I, OT, S, SP> pub struct TimeoutInProcessForkExecutor<'a, H, OT, S, SP>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: FnMut(&S::Input) -> ExitKind + ?Sized,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
{ {
harness_fn: &'a mut H, harness_fn: &'a mut H,
@ -1470,15 +1466,15 @@ where
observers: OT, observers: OT,
handlers: InChildProcessHandlers, handlers: InChildProcessHandlers,
itimerspec: libc::itimerspec, itimerspec: libc::itimerspec,
phantom: PhantomData<(I, S)>, phantom: PhantomData<S>,
} }
#[cfg(all(feature = "std", unix))] #[cfg(all(feature = "std", unix))]
impl<'a, H, I, OT, S, SP> Debug for InProcessForkExecutor<'a, H, I, OT, S, SP> impl<'a, H, OT, S, SP> Debug for InProcessForkExecutor<'a, H, OT, S, SP>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: FnMut(&S::Input) -> ExitKind + ?Sized,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
@ -1490,11 +1486,11 @@ where
} }
#[cfg(all(feature = "std", target_os = "linux"))] #[cfg(all(feature = "std", target_os = "linux"))]
impl<'a, H, I, OT, S, SP> Debug for TimeoutInProcessForkExecutor<'a, H, I, OT, S, SP> impl<'a, H, OT, S, SP> Debug for TimeoutInProcessForkExecutor<'a, H, OT, S, SP>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: FnMut(&S::Input) -> ExitKind + ?Sized,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
@ -1507,22 +1503,45 @@ where
} }
#[cfg(all(feature = "std", unix))] #[cfg(all(feature = "std", unix))]
impl<'a, EM, H, I, OT, S, SP, Z> Executor<EM, I, S, Z> impl<'a, H, OT, S, SP> UsesState for InProcessForkExecutor<'a, H, OT, S, SP>
for InProcessForkExecutor<'a, H, I, OT, S, SP>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: ?Sized + FnMut(&S::Input) -> ExitKind,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
{
type State = S;
}
#[cfg(all(feature = "std", target_os = "linux"))]
impl<'a, H, OT, S, SP> UsesState for TimeoutInProcessForkExecutor<'a, H, OT, S, SP>
where
H: ?Sized + FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<S>,
S: UsesInput,
SP: ShMemProvider,
{
type State = S;
}
#[cfg(all(feature = "std", unix))]
impl<'a, EM, H, OT, S, SP, Z> Executor<EM, Z> for InProcessForkExecutor<'a, H, OT, S, SP>
where
EM: UsesState<State = S>,
H: FnMut(&S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S>,
S: UsesInput,
SP: ShMemProvider,
Z: UsesState<State = S>,
{ {
#[allow(unreachable_code)] #[allow(unreachable_code)]
#[inline] #[inline]
fn run_target( fn run_target(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
_mgr: &mut EM, _mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
unsafe { unsafe {
self.shmem_provider.pre_fork()?; self.shmem_provider.pre_fork()?;
@ -1574,22 +1593,23 @@ where
} }
#[cfg(all(feature = "std", target_os = "linux"))] #[cfg(all(feature = "std", target_os = "linux"))]
impl<'a, EM, H, I, OT, S, SP, Z> Executor<EM, I, S, Z> impl<'a, EM, H, OT, S, SP, Z> Executor<EM, Z> for TimeoutInProcessForkExecutor<'a, H, OT, S, SP>
for TimeoutInProcessForkExecutor<'a, H, I, OT, S, SP>
where where
H: FnMut(&I) -> ExitKind + ?Sized, EM: UsesState<State = S>,
I: Input, H: FnMut(&S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
Z: UsesState<State = S>,
{ {
#[allow(unreachable_code)] #[allow(unreachable_code)]
#[inline] #[inline]
fn run_target( fn run_target(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
_mgr: &mut EM, _mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
unsafe { unsafe {
self.shmem_provider.pre_fork()?; self.shmem_provider.pre_fork()?;
@ -1661,11 +1681,11 @@ where
} }
#[cfg(all(feature = "std", unix))] #[cfg(all(feature = "std", unix))]
impl<'a, H, I, OT, S, SP> InProcessForkExecutor<'a, H, I, OT, S, SP> impl<'a, H, OT, S, SP> InProcessForkExecutor<'a, H, OT, S, SP>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: FnMut(&S::Input) -> ExitKind + ?Sized,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
{ {
/// Creates a new [`InProcessForkExecutor`] /// Creates a new [`InProcessForkExecutor`]
@ -1678,12 +1698,12 @@ where
shmem_provider: SP, shmem_provider: SP,
) -> Result<Self, Error> ) -> Result<Self, Error>
where where
EM: EventFirer<I> + EventRestarter<S>, EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<I, S>, OF: Feedback<S>,
S: HasSolutions<I> + HasClientPerfMonitor, S: HasSolutions + HasClientPerfMonitor,
Z: HasObjective<I, OF, S>, Z: HasObjective<OF, State = S>,
{ {
let handlers = InChildProcessHandlers::new::<Self, I, OT, S>()?; let handlers = InChildProcessHandlers::new::<Self>()?;
Ok(Self { Ok(Self {
harness_fn, harness_fn,
shmem_provider, shmem_provider,
@ -1707,11 +1727,11 @@ where
} }
#[cfg(all(feature = "std", target_os = "linux"))] #[cfg(all(feature = "std", target_os = "linux"))]
impl<'a, H, I, OT, S, SP> TimeoutInProcessForkExecutor<'a, H, I, OT, S, SP> impl<'a, H, OT, S, SP> TimeoutInProcessForkExecutor<'a, H, OT, S, SP>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: FnMut(&S::Input) -> ExitKind + ?Sized,
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
SP: ShMemProvider, SP: ShMemProvider,
{ {
/// Creates a new [`TimeoutInProcessForkExecutor`] /// Creates a new [`TimeoutInProcessForkExecutor`]
@ -1725,12 +1745,12 @@ where
shmem_provider: SP, shmem_provider: SP,
) -> Result<Self, Error> ) -> Result<Self, Error>
where where
EM: EventFirer<I> + EventRestarter<S>, EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<I, S>, OF: Feedback<S>,
S: HasSolutions<I> + HasClientPerfMonitor, S: HasSolutions + HasClientPerfMonitor,
Z: HasObjective<I, OF, S>, Z: HasObjective<OF, State = S>,
{ {
let handlers = InChildProcessHandlers::with_timeout::<Self, I, OT, S>()?; let handlers = InChildProcessHandlers::with_timeout::<Self>()?;
let milli_sec = timeout.as_millis(); let milli_sec = timeout.as_millis();
let it_value = libc::timespec { let it_value = libc::timespec {
tv_sec: (milli_sec / 1000) as _, tv_sec: (milli_sec / 1000) as _,
@ -1769,11 +1789,33 @@ where
} }
#[cfg(all(feature = "std", unix))] #[cfg(all(feature = "std", unix))]
impl<'a, H, I, OT, S, SP> HasObservers<I, OT, S> for InProcessForkExecutor<'a, H, I, OT, S, SP> impl<'a, H, OT, S, SP> UsesObservers for InProcessForkExecutor<'a, H, OT, S, SP>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: ?Sized + FnMut(&S::Input) -> ExitKind,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
SP: ShMemProvider,
{
type Observers = OT;
}
#[cfg(all(feature = "std", target_os = "linux"))]
impl<'a, H, OT, S, SP> UsesObservers for TimeoutInProcessForkExecutor<'a, H, OT, S, SP>
where
H: ?Sized + FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<S>,
S: UsesInput,
SP: ShMemProvider,
{
type Observers = OT;
}
#[cfg(all(feature = "std", unix))]
impl<'a, H, OT, S, SP> HasObservers for InProcessForkExecutor<'a, H, OT, S, SP>
where
H: FnMut(&S::Input) -> ExitKind + ?Sized,
S: UsesInput,
OT: ObserversTuple<S>,
SP: ShMemProvider, SP: ShMemProvider,
{ {
#[inline] #[inline]
@ -1788,12 +1830,11 @@ where
} }
#[cfg(all(feature = "std", target_os = "linux"))] #[cfg(all(feature = "std", target_os = "linux"))]
impl<'a, H, I, OT, S, SP> HasObservers<I, OT, S> impl<'a, H, OT, S, SP> HasObservers for TimeoutInProcessForkExecutor<'a, H, OT, S, SP>
for TimeoutInProcessForkExecutor<'a, H, I, OT, S, SP>
where where
H: FnMut(&I) -> ExitKind + ?Sized, H: FnMut(&S::Input) -> ExitKind + ?Sized,
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
SP: ShMemProvider, SP: ShMemProvider,
{ {
#[inline] #[inline]
@ -1819,16 +1860,14 @@ pub mod child_signal_handlers {
use crate::{ use crate::{
bolts::os::unix_signals::{ucontext_t, Signal}, bolts::os::unix_signals::{ucontext_t, Signal},
executors::{ExitKind, HasObservers}, executors::{ExitKind, HasObservers},
inputs::Input, inputs::UsesInput,
observers::ObserversTuple, observers::ObserversTuple,
}; };
/// invokes the `post_exec_child` hook on all observer in case the child process panics /// invokes the `post_exec_child` hook on all observer in case the child process panics
pub fn setup_child_panic_hook<E, I, OT, S>() pub fn setup_child_panic_hook<E>()
where where
E: HasObservers<I, OT, S>, E: HasObservers,
OT: ObserversTuple<I, S>,
I: Input,
{ {
let old_hook = panic::take_hook(); let old_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| { panic::set_hook(Box::new(move |panic_info| {
@ -1837,9 +1876,9 @@ pub mod child_signal_handlers {
if data.is_valid() { if data.is_valid() {
let executor = data.executor_mut::<E>(); let executor = data.executor_mut::<E>();
let observers = executor.observers_mut(); let observers = executor.observers_mut();
let state = data.state_mut::<S>(); let state = data.state_mut::<E::State>();
// Invalidate data to not execute again the observer hooks in the crash handler // Invalidate data to not execute again the observer hooks in the crash handler
let input = data.take_current_input::<I>(); let input = data.take_current_input::<<E::State as UsesInput>::Input>();
observers observers
.post_exec_child_all(state, input, &ExitKind::Crash) .post_exec_child_all(state, input, &ExitKind::Crash)
.expect("Failed to run post_exec on observers"); .expect("Failed to run post_exec on observers");
@ -1856,21 +1895,19 @@ pub mod child_signal_handlers {
/// The function should only be called from a child crash handler. /// The function should only be called from a child crash handler.
/// It will dereference the `data` pointer and assume it's valid. /// It will dereference the `data` pointer and assume it's valid.
#[cfg(unix)] #[cfg(unix)]
pub(crate) unsafe fn child_crash_handler<E, I, OT, S>( pub(crate) unsafe fn child_crash_handler<E>(
_signal: Signal, _signal: Signal,
_info: siginfo_t, _info: siginfo_t,
_context: &mut ucontext_t, _context: &mut ucontext_t,
data: &mut InProcessForkExecutorGlobalData, data: &mut InProcessForkExecutorGlobalData,
) where ) where
E: HasObservers<I, OT, S>, E: HasObservers,
OT: ObserversTuple<I, S>,
I: Input,
{ {
if data.is_valid() { if data.is_valid() {
let executor = data.executor_mut::<E>(); let executor = data.executor_mut::<E>();
let observers = executor.observers_mut(); let observers = executor.observers_mut();
let state = data.state_mut::<S>(); let state = data.state_mut::<E::State>();
let input = data.take_current_input::<I>(); let input = data.take_current_input::<<E::State as UsesInput>::Input>();
observers observers
.post_exec_child_all(state, input, &ExitKind::Crash) .post_exec_child_all(state, input, &ExitKind::Crash)
.expect("Failed to run post_exec on observers"); .expect("Failed to run post_exec on observers");
@ -1880,21 +1917,19 @@ pub mod child_signal_handlers {
} }
#[cfg(unix)] #[cfg(unix)]
pub(crate) unsafe fn child_timeout_handler<E, I, OT, S>( pub(crate) unsafe fn child_timeout_handler<E>(
_signal: Signal, _signal: Signal,
_info: siginfo_t, _info: siginfo_t,
_context: &mut ucontext_t, _context: &mut ucontext_t,
data: &mut InProcessForkExecutorGlobalData, data: &mut InProcessForkExecutorGlobalData,
) where ) where
E: HasObservers<I, OT, S>, E: HasObservers,
OT: ObserversTuple<I, S>,
I: Input,
{ {
if data.is_valid() { if data.is_valid() {
let executor = data.executor_mut::<E>(); let executor = data.executor_mut::<E>();
let observers = executor.observers_mut(); let observers = executor.observers_mut();
let state = data.state_mut::<S>(); let state = data.state_mut::<E::State>();
let input = data.take_current_input::<I>(); let input = data.take_current_input::<<E::State as UsesInput>::Input>();
observers observers
.post_exec_child_all(state, input, &ExitKind::Timeout) .post_exec_child_all(state, input, &ExitKind::Timeout)
.expect("Failed to run post_exec on observers"); .expect("Failed to run post_exec on observers");
@ -1910,22 +1945,24 @@ mod tests {
#[cfg(all(feature = "std", feature = "fork", unix))] #[cfg(all(feature = "std", feature = "fork", unix))]
use serial_test::serial; use serial_test::serial;
#[cfg(all(feature = "std", feature = "fork", unix))]
use crate::{
bolts::shmem::{ShMemProvider, StdShMemProvider},
executors::InProcessForkExecutor,
};
use crate::{ use crate::{
bolts::tuples::tuple_list, bolts::tuples::tuple_list,
events::NopEventManager,
executors::{inprocess::InProcessHandlers, Executor, ExitKind, InProcessExecutor}, executors::{inprocess::InProcessHandlers, Executor, ExitKind, InProcessExecutor},
inputs::NopInput, inputs::{NopInput, UsesInput},
state::NopState,
NopFuzzer,
}; };
impl UsesInput for () {
type Input = NopInput;
}
#[test] #[test]
fn test_inmem_exec() { fn test_inmem_exec() {
let mut harness = |_buf: &NopInput| ExitKind::Ok; let mut harness = |_buf: &NopInput| ExitKind::Ok;
let mut in_process_executor = InProcessExecutor::<_, NopInput, (), ()> { let mut in_process_executor = InProcessExecutor::<_, _, _> {
harness_fn: &mut harness, harness_fn: &mut harness,
observers: tuple_list!(), observers: tuple_list!(),
handlers: InProcessHandlers::nop(), handlers: InProcessHandlers::nop(),
@ -1933,7 +1970,12 @@ mod tests {
}; };
let input = NopInput {}; let input = NopInput {};
in_process_executor in_process_executor
.run_target(&mut (), &mut (), &mut (), &input) .run_target(
&mut NopFuzzer::new(),
&mut NopState::new(),
&mut NopEventManager::new(),
&input,
)
.unwrap(); .unwrap();
} }
@ -1941,12 +1983,18 @@ mod tests {
#[serial] #[serial]
#[cfg(all(feature = "std", feature = "fork", unix))] #[cfg(all(feature = "std", feature = "fork", unix))]
fn test_inprocessfork_exec() { fn test_inprocessfork_exec() {
use crate::executors::inprocess::InChildProcessHandlers; use crate::{
bolts::shmem::{ShMemProvider, StdShMemProvider},
events::SimpleEventManager,
executors::{inprocess::InChildProcessHandlers, InProcessForkExecutor},
state::NopState,
NopFuzzer,
};
let provider = StdShMemProvider::new().unwrap(); let provider = StdShMemProvider::new().unwrap();
let mut harness = |_buf: &NopInput| ExitKind::Ok; let mut harness = |_buf: &NopInput| ExitKind::Ok;
let mut in_process_fork_executor = InProcessForkExecutor::<_, NopInput, (), (), _> { let mut in_process_fork_executor = InProcessForkExecutor::<_, (), _, _> {
harness_fn: &mut harness, harness_fn: &mut harness,
shmem_provider: provider, shmem_provider: provider,
observers: tuple_list!(), observers: tuple_list!(),
@ -1954,8 +2002,11 @@ mod tests {
phantom: PhantomData, phantom: PhantomData,
}; };
let input = NopInput {}; let input = NopInput {};
let mut fuzzer = NopFuzzer::new();
let mut state = NopState::new();
let mut mgr = SimpleEventManager::printing();
in_process_fork_executor in_process_fork_executor
.run_target(&mut (), &mut (), &mut (), &input) .run_target(&mut fuzzer, &mut state, &mut mgr, &input)
.unwrap(); .unwrap();
} }
} }
@ -1982,7 +2033,7 @@ pub mod pybind {
/// Python class for OwnedInProcessExecutor (i.e. InProcessExecutor with owned harness) /// Python class for OwnedInProcessExecutor (i.e. InProcessExecutor with owned harness)
pub struct PythonOwnedInProcessExecutor { pub struct PythonOwnedInProcessExecutor {
/// Rust wrapped OwnedInProcessExecutor object /// Rust wrapped OwnedInProcessExecutor object
pub inner: OwnedInProcessExecutor<BytesInput, PythonObserversTuple, PythonStdState>, pub inner: OwnedInProcessExecutor<PythonObserversTuple, PythonStdState>,
} }
#[pymethods] #[pymethods]

View File

@ -31,7 +31,7 @@ pub use with_observers::WithObservers;
#[cfg(all(feature = "std", any(unix, doc)))] #[cfg(all(feature = "std", any(unix, doc)))]
pub mod command; pub mod command;
use core::fmt::Debug; use core::{fmt::Debug, marker::PhantomData};
#[cfg(all(feature = "std", any(unix, doc)))] #[cfg(all(feature = "std", any(unix, doc)))]
pub use command::CommandExecutor; pub use command::CommandExecutor;
@ -39,8 +39,9 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::AsSlice, bolts::AsSlice,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, UsesInput},
observers::ObserversTuple, observers::{ObserversTuple, UsesObservers},
state::UsesState,
Error, Error,
}; };
@ -100,29 +101,27 @@ impl From<ExitKind> for DiffExitKind {
crate::impl_serdeany!(DiffExitKind); crate::impl_serdeany!(DiffExitKind);
/// Holds a tuple of Observers /// Holds a tuple of Observers
pub trait HasObservers<I, OT, S>: Debug pub trait HasObservers: UsesObservers {
where
OT: ObserversTuple<I, S>,
{
/// Get the linked observers /// Get the linked observers
fn observers(&self) -> &OT; fn observers(&self) -> &Self::Observers;
/// Get the linked observers (mutable) /// Get the linked observers (mutable)
fn observers_mut(&mut self) -> &mut OT; fn observers_mut(&mut self) -> &mut Self::Observers;
} }
/// 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<EM, I, S, Z>: Debug pub trait Executor<EM, Z>: UsesState + Debug
where where
I: Input, EM: UsesState<State = Self::State>,
Z: UsesState<State = Self::State>,
{ {
/// Instruct the target about the input and run /// Instruct the target about the input and run
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error>; ) -> Result<ExitKind, Error>;
/// Wraps this Executor with the given [`ObserversTuple`] to implement [`HasObservers`]. /// Wraps this Executor with the given [`ObserversTuple`] to implement [`HasObservers`].
@ -132,7 +131,7 @@ where
fn with_observers<OT>(self, observers: OT) -> WithObservers<Self, OT> fn with_observers<OT>(self, observers: OT) -> WithObservers<Self, OT>
where where
Self: Sized, Self: Sized,
OT: ObserversTuple<I, S>, OT: ObserversTuple<Self::State>,
{ {
WithObservers::new(self, observers) WithObservers::new(self, observers)
} }
@ -145,18 +144,30 @@ where
/// A simple executor that does nothing. /// A simple executor that does nothing.
/// If intput len is 0, `run_target` will return Err /// If intput len is 0, `run_target` will return Err
#[derive(Debug)] #[derive(Debug)]
struct NopExecutor {} struct NopExecutor<S> {
phantom: PhantomData<S>,
}
impl<EM, I, S, Z> Executor<EM, I, S, Z> for NopExecutor impl<S> UsesState for NopExecutor<S>
where where
I: Input + HasTargetBytes, S: UsesInput,
{
type State = S;
}
impl<EM, S, Z> Executor<EM, Z> for NopExecutor<S>
where
EM: UsesState<State = S>,
S: UsesInput + Debug,
S::Input: HasTargetBytes,
Z: UsesState<State = S>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut S, _state: &mut Self::State,
_mgr: &mut EM, _mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
if input.target_bytes().as_slice().is_empty() { if input.target_bytes().as_slice().is_empty() {
Err(Error::empty("Input Empty")) Err(Error::empty("Input Empty"))
@ -168,19 +179,37 @@ where
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use core::marker::PhantomData;
use super::{Executor, NopExecutor}; use super::{Executor, NopExecutor};
use crate::inputs::BytesInput; use crate::{events::NopEventManager, inputs::BytesInput, state::NopState, NopFuzzer};
#[test] #[test]
fn nop_executor() { fn nop_executor() {
let empty_input = BytesInput::new(vec![]); let empty_input = BytesInput::new(vec![]);
let nonempty_input = BytesInput::new(vec![1u8]); let nonempty_input = BytesInput::new(vec![1u8]);
let mut executor = NopExecutor {}; let mut executor = NopExecutor {
phantom: PhantomData,
};
let mut fuzzer = NopFuzzer::new();
let mut state = NopState::new();
executor executor
.run_target(&mut (), &mut (), &mut (), &empty_input) .run_target(
&mut fuzzer,
&mut state,
&mut NopEventManager::new(),
&empty_input,
)
.unwrap_err(); .unwrap_err();
executor executor
.run_target(&mut (), &mut (), &mut (), &nonempty_input) .run_target(
&mut fuzzer,
&mut state,
&mut NopEventManager::new(),
&nonempty_input,
)
.unwrap(); .unwrap();
} }
} }
@ -198,9 +227,12 @@ pub mod pybind {
inprocess::pybind::PythonOwnedInProcessExecutor, Executor, ExitKind, HasObservers, inprocess::pybind::PythonOwnedInProcessExecutor, Executor, ExitKind, HasObservers,
}, },
fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper}, fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper},
inputs::{BytesInput, HasBytesVec}, inputs::HasBytesVec,
observers::pybind::PythonObserversTuple, observers::{pybind::PythonObserversTuple, UsesObservers},
state::pybind::{PythonStdState, PythonStdStateWrapper}, state::{
pybind::{PythonStdState, PythonStdStateWrapper},
UsesState,
},
Error, Error,
}; };
@ -293,7 +325,15 @@ pub mod pybind {
} }
} }
impl HasObservers<BytesInput, PythonObserversTuple, PythonStdState> for PyObjectExecutor { impl UsesState for PyObjectExecutor {
type State = PythonStdState;
}
impl UsesObservers for PyObjectExecutor {
type Observers = PythonObserversTuple;
}
impl HasObservers for PyObjectExecutor {
#[inline] #[inline]
fn observers(&self) -> &PythonObserversTuple { fn observers(&self) -> &PythonObserversTuple {
&self.tuple &self.tuple
@ -305,16 +345,14 @@ pub mod pybind {
} }
} }
impl Executor<PythonEventManager, BytesInput, PythonStdState, PythonStdFuzzer> impl Executor<PythonEventManager, PythonStdFuzzer> for PyObjectExecutor {
for PyObjectExecutor
{
#[inline] #[inline]
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut PythonStdFuzzer, fuzzer: &mut PythonStdFuzzer,
state: &mut PythonStdState, state: &mut Self::State,
mgr: &mut PythonEventManager, mgr: &mut PythonEventManager,
input: &BytesInput, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
let ek = Python::with_gil(|py| -> PyResult<_> { let ek = Python::with_gil(|py| -> PyResult<_> {
let ek: PythonExitKind = self let ek: PythonExitKind = self
@ -344,7 +382,7 @@ pub mod pybind {
#[pyclass(unsendable, name = "Executor")] #[pyclass(unsendable, name = "Executor")]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// Executor + HasObservers Trait binding /// Executor<Input = I> + HasObservers Trait binding
pub struct PythonExecutor { pub struct PythonExecutor {
wrapper: PythonExecutorWrapper, wrapper: PythonExecutorWrapper,
} }
@ -404,7 +442,15 @@ pub mod pybind {
} }
} }
impl HasObservers<BytesInput, PythonObserversTuple, PythonStdState> for PythonExecutor { impl UsesState for PythonExecutor {
type State = PythonStdState;
}
impl UsesObservers for PythonExecutor {
type Observers = PythonObserversTuple;
}
impl HasObservers for PythonExecutor {
#[inline] #[inline]
fn observers(&self) -> &PythonObserversTuple { fn observers(&self) -> &PythonObserversTuple {
let ptr = unwrap_me!(self.wrapper, e, { let ptr = unwrap_me!(self.wrapper, e, {
@ -422,14 +468,14 @@ pub mod pybind {
} }
} }
impl Executor<PythonEventManager, BytesInput, PythonStdState, PythonStdFuzzer> for PythonExecutor { impl Executor<PythonEventManager, PythonStdFuzzer> for PythonExecutor {
#[inline] #[inline]
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut PythonStdFuzzer, fuzzer: &mut PythonStdFuzzer,
state: &mut PythonStdState, state: &mut Self::State,
mgr: &mut PythonEventManager, mgr: &mut PythonEventManager,
input: &BytesInput, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
unwrap_me_mut!(self.wrapper, e, { e.run_target(fuzzer, state, mgr, input) }) unwrap_me_mut!(self.wrapper, e, { e.run_target(fuzzer, state, mgr, input) })
} }

View File

@ -1,28 +1,27 @@
//! A `ShadowExecutor` wraps an executor to have shadow observer that will not be considered by the feedbacks and the manager //! A `ShadowExecutor` wraps an executor to have shadow observer that will not be considered by the feedbacks and the manager
use core::{ use core::fmt::{self, Debug, Formatter};
fmt::{self, Debug, Formatter},
marker::PhantomData,
};
use crate::{ use crate::{
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
inputs::Input, observers::{ObserversTuple, UsesObservers},
observers::ObserversTuple, state::UsesState,
Error, Error,
}; };
/// A [`ShadowExecutor`] wraps an executor and a set of shadow observers /// A [`ShadowExecutor`] wraps an executor and a set of shadow observers
pub struct ShadowExecutor<E: Debug, I: Debug, S, SOT: Debug> { pub struct ShadowExecutor<E, SOT> {
/// The wrapped executor /// The wrapped executor
executor: E, executor: E,
/// The shadow observers /// The shadow observers
shadow_observers: SOT, shadow_observers: SOT,
/// phantom data
phantom: PhantomData<(I, S)>,
} }
impl<E: Debug, I: Debug, S, SOT: Debug> Debug for ShadowExecutor<E, I, S, SOT> { impl<E, SOT> Debug for ShadowExecutor<E, SOT>
where
E: UsesState + Debug,
SOT: ObserversTuple<E::State> + Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("ShadowExecutor") f.debug_struct("ShadowExecutor")
.field("executor", &self.executor) .field("executor", &self.executor)
@ -31,16 +30,16 @@ impl<E: Debug, I: Debug, S, SOT: Debug> Debug for ShadowExecutor<E, I, S, SOT> {
} }
} }
impl<E: Debug, I: Debug, S, SOT: Debug> ShadowExecutor<E, I, S, SOT> impl<E, SOT> ShadowExecutor<E, SOT>
where where
SOT: ObserversTuple<I, S>, E: HasObservers + Debug,
SOT: ObserversTuple<E::State> + Debug,
{ {
/// Create a new `ShadowExecutor`, wrapping the given `executor`. /// Create a new `ShadowExecutor`, wrapping the given `executor`.
pub fn new(executor: E, shadow_observers: SOT) -> Self { pub fn new(executor: E, shadow_observers: SOT) -> Self {
Self { Self {
executor, executor,
shadow_observers, shadow_observers,
phantom: PhantomData,
} }
} }
@ -57,38 +56,50 @@ where
} }
} }
impl<E, EM, I, S, SOT, Z> Executor<EM, I, S, Z> for ShadowExecutor<E, I, S, SOT> impl<E, EM, SOT, Z> Executor<EM, Z> for ShadowExecutor<E, SOT>
where where
E: Executor<EM, I, S, Z>, E: Executor<EM, Z> + HasObservers,
I: Input, SOT: ObserversTuple<E::State>,
SOT: ObserversTuple<I, S>, EM: UsesState<State = E::State>,
Z: UsesState<State = E::State>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
self.executor.run_target(fuzzer, state, mgr, input) self.executor.run_target(fuzzer, state, mgr, input)
} }
} }
impl<E, I, OT, S, SOT> HasObservers<I, OT, S> for ShadowExecutor<E, I, S, SOT> impl<E, SOT> UsesState for ShadowExecutor<E, SOT>
where where
I: Debug, E: UsesState,
S: Debug, {
E: HasObservers<I, OT, S>, type State = E::State;
OT: ObserversTuple<I, S>, }
SOT: ObserversTuple<I, S>,
impl<E, SOT> UsesObservers for ShadowExecutor<E, SOT>
where
E: UsesObservers,
{
type Observers = E::Observers;
}
impl<E, SOT> HasObservers for ShadowExecutor<E, SOT>
where
E: HasObservers,
SOT: ObserversTuple<E::State>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &Self::Observers {
self.executor.observers() self.executor.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> &mut Self::Observers {
self.executor.observers_mut() self.executor.observers_mut()
} }
} }

View File

@ -33,8 +33,8 @@ use windows::Win32::{
use crate::executors::inprocess::{HasInProcessHandlers, GLOBAL_STATE}; use crate::executors::inprocess::{HasInProcessHandlers, GLOBAL_STATE};
use crate::{ use crate::{
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
inputs::Input, observers::UsesObservers,
observers::ObserversTuple, state::UsesState,
Error, Error,
}; };
@ -77,6 +77,7 @@ const ITIMER_REAL: c_int = 0;
/// The timeout executor is a wrapper that sets a timeout before each run /// The timeout executor is a wrapper that sets a timeout before each run
pub struct TimeoutExecutor<E> { pub struct TimeoutExecutor<E> {
/// The wrapped [`Executor`]
executor: E, executor: E,
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
itimerspec: libc::itimerspec, itimerspec: libc::itimerspec,
@ -263,18 +264,19 @@ impl<E: HasInProcessHandlers> TimeoutExecutor<E> {
} }
#[cfg(windows)] #[cfg(windows)]
impl<E, EM, I, S, Z> Executor<EM, I, S, Z> for TimeoutExecutor<E> impl<E, EM, Z> Executor<EM, Z> for TimeoutExecutor<E>
where where
E: Executor<EM, I, S, Z> + HasInProcessHandlers, E: Executor<EM, Z> + HasInProcessHandlers,
I: Input, EM: UsesState<State = E::State>,
Z: UsesState<State = E::State>,
{ {
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
unsafe { unsafe {
let data = &mut GLOBAL_STATE; let data = &mut GLOBAL_STATE;
@ -333,17 +335,18 @@ where
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
impl<E, EM, I, S, Z> Executor<EM, I, S, Z> for TimeoutExecutor<E> impl<E, EM, Z> Executor<EM, Z> for TimeoutExecutor<E>
where where
E: Executor<EM, I, S, Z>, E: Executor<EM, Z>,
I: Input, EM: UsesState<State = E::State>,
Z: UsesState<State = E::State>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
unsafe { unsafe {
libc::timer_settime(self.timerid, 0, addr_of_mut!(self.itimerspec), null_mut()); libc::timer_settime(self.timerid, 0, addr_of_mut!(self.itimerspec), null_mut());
@ -364,17 +367,18 @@ where
} }
#[cfg(all(unix, not(target_os = "linux")))] #[cfg(all(unix, not(target_os = "linux")))]
impl<E, EM, I, S, Z> Executor<EM, I, S, Z> for TimeoutExecutor<E> impl<E, EM, Z> Executor<EM, Z> for TimeoutExecutor<E>
where where
E: Executor<EM, I, S, Z>, E: Executor<EM, Z>,
I: Input, EM: UsesState<State = E::State>,
Z: UsesState<State = E::State>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
unsafe { unsafe {
setitimer(ITIMER_REAL, &mut self.itimerval, null_mut()); setitimer(ITIMER_REAL, &mut self.itimerval, null_mut());
@ -393,18 +397,31 @@ where
} }
} }
impl<E, I, OT, S> HasObservers<I, OT, S> for TimeoutExecutor<E> impl<E> UsesState for TimeoutExecutor<E>
where where
E: HasObservers<I, OT, S>, E: UsesState,
OT: ObserversTuple<I, S>, {
type State = E::State;
}
impl<E> UsesObservers for TimeoutExecutor<E>
where
E: UsesObservers,
{
type Observers = E::Observers;
}
impl<E> HasObservers for TimeoutExecutor<E>
where
E: HasObservers,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &Self::Observers {
self.executor.observers() self.executor.observers()
} }
#[inline] #[inline]
fn observers_mut(&mut self) -> &mut OT { fn observers_mut(&mut self) -> &mut Self::Observers {
self.executor.observers_mut() self.executor.observers_mut()
} }
} }

View File

@ -4,39 +4,55 @@ use core::fmt::Debug;
use crate::{ use crate::{
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
inputs::Input, observers::{ObserversTuple, UsesObservers},
observers::ObserversTuple, state::UsesState,
Error, Error,
}; };
/// A wrapper for any [`Executor`] to make it implement [`HasObservers`] using a given [`ObserversTuple`]. /// A wrapper for any [`Executor`] to make it implement [`HasObservers`] using a given [`ObserversTuple`].
#[derive(Debug)] #[derive(Debug)]
pub struct WithObservers<E: Debug, OT: Debug> { pub struct WithObservers<E, OT> {
executor: E, executor: E,
observers: OT, observers: OT,
} }
impl<E, EM, I, OT, S, Z> Executor<EM, I, S, Z> for WithObservers<E, OT> impl<E, EM, OT, Z> Executor<EM, Z> for WithObservers<E, OT>
where where
I: Input, E: Executor<EM, Z> + Debug,
E: Executor<EM, I, S, Z>,
OT: Debug, OT: Debug,
EM: UsesState<State = E::State>,
Z: UsesState<State = E::State>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
self.executor.run_target(fuzzer, state, mgr, input) self.executor.run_target(fuzzer, state, mgr, input)
} }
} }
impl<I, E: Debug, OT: Debug, S> HasObservers<I, OT, S> for WithObservers<E, OT> impl<E, OT> UsesState for WithObservers<E, OT>
where where
I: Input, E: UsesState,
OT: ObserversTuple<I, S>, {
type State = E::State;
}
impl<E, OT> UsesObservers for WithObservers<E, OT>
where
E: UsesState,
OT: ObserversTuple<E::State>,
{
type Observers = OT;
}
impl<E, OT> HasObservers for WithObservers<E, OT>
where
E: HasObservers + Debug,
OT: ObserversTuple<E::State> + Debug,
{ {
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
&self.observers &self.observers

View File

@ -4,6 +4,7 @@
//! to be not interesting. //! to be not interesting.
//! Requires a [`ConcolicObserver`] to observe the concolic trace. //! Requires a [`ConcolicObserver`] to observe the concolic trace.
use alloc::{borrow::ToOwned, string::String}; use alloc::{borrow::ToOwned, string::String};
use core::{fmt::Debug, marker::PhantomData};
use crate::{ use crate::{
bolts::tuples::Named, bolts::tuples::Named,
@ -11,7 +12,7 @@ use crate::{
events::EventFirer, events::EventFirer,
executors::ExitKind, executors::ExitKind,
feedbacks::Feedback, feedbacks::Feedback,
inputs::Input, inputs::UsesInput,
observers::{ observers::{
concolic::{ConcolicMetadata, ConcolicObserver}, concolic::{ConcolicMetadata, ConcolicObserver},
ObserversTuple, ObserversTuple,
@ -25,12 +26,13 @@ use crate::{
/// to be not interesting. /// to be not interesting.
/// Requires a [`ConcolicObserver`] to observe the concolic trace. /// Requires a [`ConcolicObserver`] to observe the concolic trace.
#[derive(Debug)] #[derive(Debug)]
pub struct ConcolicFeedback { pub struct ConcolicFeedback<S> {
name: String, name: String,
metadata: Option<ConcolicMetadata>, metadata: Option<ConcolicMetadata>,
phantom: PhantomData<S>,
} }
impl ConcolicFeedback { impl<S> ConcolicFeedback<S> {
/// Creates a concolic feedback from an observer /// Creates a concolic feedback from an observer
#[allow(unused)] #[allow(unused)]
#[must_use] #[must_use]
@ -38,33 +40,33 @@ impl ConcolicFeedback {
Self { Self {
name: observer.name().to_owned(), name: observer.name().to_owned(),
metadata: None, metadata: None,
phantom: PhantomData,
} }
} }
} }
impl Named for ConcolicFeedback { impl<S> Named for ConcolicFeedback<S> {
fn name(&self) -> &str { fn name(&self) -> &str {
&self.name &self.name
} }
} }
impl<I, S> Feedback<I, S> for ConcolicFeedback impl<S> Feedback<S> for ConcolicFeedback<S>
where where
I: Input, S: UsesInput + Debug + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &<S as UsesInput>::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
self.metadata = observers self.metadata = observers
.match_name::<ConcolicObserver>(&self.name) .match_name::<ConcolicObserver>(&self.name)
@ -75,7 +77,7 @@ where
fn append_metadata( fn append_metadata(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_testcase: &mut Testcase<I>, _testcase: &mut Testcase<<S as UsesInput>::Input>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Some(metadata) = self.metadata.take() { if let Some(metadata) = self.metadata.take() {
_testcase.metadata_mut().insert(metadata); _testcase.metadata_mut().insert(metadata);
@ -83,7 +85,11 @@ where
Ok(()) Ok(())
} }
fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn discard_metadata(
&mut self,
_state: &mut S,
_input: &<S as UsesInput>::Input,
) -> Result<(), Error> {
Ok(()) Ok(())
} }
} }

View File

@ -16,7 +16,7 @@ use crate::{
feedbacks::Feedback, feedbacks::Feedback,
inputs::Input, inputs::Input,
observers::{Observer, ObserversTuple}, observers::{Observer, ObserversTuple},
state::{HasClientPerfMonitor, HasMetadata}, state::{HasClientPerfMonitor, HasMetadata, State},
Error, Error,
}; };
@ -48,7 +48,7 @@ impl DiffResult {
/// A [`DiffFeedback`] compares the content of two [`Observer`]s using the given compare function. /// A [`DiffFeedback`] compares the content of two [`Observer`]s using the given compare function.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct DiffFeedback<F, O1, O2> pub struct DiffFeedback<F, I, O1, O2, S>
where where
F: FnMut(&O1, &O2) -> DiffResult, F: FnMut(&O1, &O2) -> DiffResult,
{ {
@ -60,10 +60,10 @@ where
o2_name: String, o2_name: String,
/// The function used to compare the two observers /// The function used to compare the two observers
compare_fn: F, compare_fn: F,
phantomm: PhantomData<(O1, O2)>, phantomm: PhantomData<(O1, O2, I, S)>,
} }
impl<F, O1, O2> DiffFeedback<F, O1, O2> impl<F, I, O1, O2, S> DiffFeedback<F, I, O1, O2, S>
where where
F: FnMut(&O1, &O2) -> DiffResult, F: FnMut(&O1, &O2) -> DiffResult,
O1: Named, O1: Named,
@ -90,7 +90,7 @@ where
} }
} }
impl<F, O1, O2> Named for DiffFeedback<F, O1, O2> impl<F, I, O1, O2, S> Named for DiffFeedback<F, I, O1, O2, S>
where where
F: FnMut(&O1, &O2) -> DiffResult, F: FnMut(&O1, &O2) -> DiffResult,
O1: Named, O1: Named,
@ -101,7 +101,7 @@ where
} }
} }
impl<F, O1, O2> Debug for DiffFeedback<F, O1, O2> impl<F, I, O1, O2, S> Debug for DiffFeedback<F, I, O1, O2, S>
where where
F: FnMut(&O1, &O2) -> DiffResult, F: FnMut(&O1, &O2) -> DiffResult,
O1: Named, O1: Named,
@ -116,13 +116,13 @@ where
} }
} }
impl<F, I, O1, O2, S> Feedback<I, S> for DiffFeedback<F, O1, O2> impl<F, I, O1, O2, S> Feedback<S> for DiffFeedback<F, I, O1, O2, S>
where where
F: FnMut(&O1, &O2) -> DiffResult, F: FnMut(&O1, &O2) -> DiffResult,
I: Input, I: Input,
S: HasMetadata + HasClientPerfMonitor, S: HasMetadata + HasClientPerfMonitor + State<Input = I>,
O1: Observer<I, S> + PartialEq<O2>, O1: Observer<S> + PartialEq<O2>,
O2: Observer<I, S>, O2: Observer<S>,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
@ -134,8 +134,8 @@ where
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S> + MatchName, OT: ObserversTuple<S> + MatchName,
{ {
fn err(name: &str) -> Error { fn err(name: &str) -> Error {
Error::illegal_argument(format!("DiffFeedback: observer {name} not found")) Error::illegal_argument(format!("DiffFeedback: observer {name} not found"))
@ -154,19 +154,16 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use core::marker::PhantomData;
use crate::{ use crate::{
bolts::{ bolts::tuples::{tuple_list, Named},
serdeany::SerdeAnyMap,
tuples::{tuple_list, Named},
},
events::EventFirer, events::EventFirer,
executors::ExitKind, executors::ExitKind,
feedbacks::{differential::DiffResult, DiffFeedback, Feedback}, feedbacks::{differential::DiffResult, DiffFeedback, Feedback},
inputs::{BytesInput, Input}, inputs::{BytesInput, UsesInput},
monitors::ClientPerfMonitor,
observers::Observer, observers::Observer,
state::{HasClientPerfMonitor, HasMetadata}, state::{NopState, UsesState},
}; };
#[derive(Debug)] #[derive(Debug)]
@ -182,7 +179,7 @@ mod tests {
} }
} }
} }
impl<I, S> Observer<I, S> for NopObserver {} impl<S> Observer<S> for NopObserver where S: UsesInput {}
impl PartialEq for NopObserver { impl PartialEq for NopObserver {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.value == other.value self.value == other.value
@ -194,39 +191,30 @@ mod tests {
} }
} }
struct NopEventFirer; struct NopEventFirer<S> {
impl<I: Input> EventFirer<I> for NopEventFirer { phantom: PhantomData<S>,
fn fire<S>( }
impl<S> UsesState for NopEventFirer<S>
where
S: UsesInput,
{
type State = S;
}
impl<S> EventFirer for NopEventFirer<S>
where
S: UsesInput,
{
fn fire(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_event: crate::events::Event<I>, _event: crate::events::Event<S::Input>,
) -> Result<(), crate::Error> { ) -> Result<(), crate::Error> {
Ok(()) Ok(())
} }
} }
struct NopState;
impl HasMetadata for NopState {
fn metadata(&self) -> &SerdeAnyMap {
unimplemented!()
}
fn metadata_mut(&mut self) -> &mut SerdeAnyMap {
unimplemented!()
}
}
impl HasClientPerfMonitor for NopState {
fn introspection_monitor(&self) -> &ClientPerfMonitor {
unimplemented!()
}
fn introspection_monitor_mut(&mut self) -> &mut ClientPerfMonitor {
unimplemented!()
}
}
fn test_diff(should_equal: bool) { fn test_diff(should_equal: bool) {
let mut nop_state = NopState; let mut nop_state = NopState::new();
let o1 = NopObserver::new("o1", true); let o1 = NopObserver::new("o1", true);
let o2 = NopObserver::new("o2", should_equal); let o2 = NopObserver::new("o2", should_equal);
@ -245,7 +233,9 @@ mod tests {
diff_feedback diff_feedback
.is_interesting( .is_interesting(
&mut nop_state, &mut nop_state,
&mut NopEventFirer {}, &mut NopEventFirer {
phantom: PhantomData
},
&BytesInput::new(vec![0]), &BytesInput::new(vec![0]),
&observers, &observers,
&ExitKind::Ok &ExitKind::Ok

View File

@ -21,7 +21,7 @@ use crate::{
events::{Event, EventFirer}, events::{Event, EventFirer},
executors::ExitKind, executors::ExitKind,
feedbacks::{Feedback, HasObserverName}, feedbacks::{Feedback, HasObserverName},
inputs::Input, inputs::UsesInput,
monitors::UserStats, monitors::UserStats,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
state::{HasClientPerfMonitor, HasMetadata, HasNamedMetadata}, state::{HasClientPerfMonitor, HasMetadata, HasNamedMetadata},
@ -32,20 +32,19 @@ use crate::{
pub const MAPFEEDBACK_PREFIX: &str = "mapfeedback_metadata_"; pub const MAPFEEDBACK_PREFIX: &str = "mapfeedback_metadata_";
/// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from ``HitcountsMapObserver``. /// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from ``HitcountsMapObserver``.
pub type AflMapFeedback<I, O, S, T> = MapFeedback<I, DifferentIsNovel, O, OrReducer, S, T>; pub type AflMapFeedback<O, S, T> = MapFeedback<DifferentIsNovel, O, OrReducer, S, T>;
/// A [`MapFeedback`] that strives to maximize the map contents. /// A [`MapFeedback`] that strives to maximize the map contents.
pub type MaxMapFeedback<I, O, S, T> = MapFeedback<I, DifferentIsNovel, O, MaxReducer, S, T>; pub type MaxMapFeedback<O, S, T> = MapFeedback<DifferentIsNovel, O, MaxReducer, S, T>;
/// A [`MapFeedback`] that strives to minimize the map contents. /// A [`MapFeedback`] that strives to minimize the map contents.
pub type MinMapFeedback<I, O, S, T> = MapFeedback<I, DifferentIsNovel, O, MinReducer, S, T>; pub type MinMapFeedback<O, S, T> = MapFeedback<DifferentIsNovel, O, MinReducer, S, T>;
/// A [`MapFeedback`] that strives to maximize the map contents, /// A [`MapFeedback`] that strives to maximize the map contents,
/// but only, if a value is larger than `pow2` of the previous. /// but only, if a value is larger than `pow2` of the previous.
pub type MaxMapPow2Feedback<I, O, S, T> = MapFeedback<I, NextPow2IsNovel, O, MaxReducer, S, T>; pub type MaxMapPow2Feedback<O, S, T> = MapFeedback<NextPow2IsNovel, O, MaxReducer, S, T>;
/// A [`MapFeedback`] that strives to maximize the map contents, /// A [`MapFeedback`] that strives to maximize the map contents,
/// but only, if a value is larger than `pow2` of the previous. /// but only, if a value is larger than `pow2` of the previous.
pub type MaxMapOneOrFilledFeedback<I, O, S, T> = pub type MaxMapOneOrFilledFeedback<O, S, T> = MapFeedback<OneOrFilledIsNovel, O, MaxReducer, S, T>;
MapFeedback<I, OneOrFilledIsNovel, O, MaxReducer, S, T>;
/// 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>: 'static + Debug pub trait Reducer<T>: 'static + Debug
@ -333,15 +332,7 @@ where
/// The most common AFL-like feedback type /// The most common AFL-like feedback type
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MapFeedback<I, N, O, R, S, T> pub struct MapFeedback<N, O, R, S, T> {
where
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
R: Reducer<T>,
O: MapObserver<Entry = T>,
for<'it> O: AsIter<'it, Item = T>,
N: IsNovel<T>,
S: HasNamedMetadata,
{
/// Indexes used in the last observation /// Indexes used in the last observation
indexes: Option<Vec<usize>>, indexes: Option<Vec<usize>>,
/// New indexes observed in the last observation /// New indexes observed in the last observation
@ -353,18 +344,16 @@ where
/// Name of the feedback as shown in the `UserStats` /// Name of the feedback as shown in the `UserStats`
stats_name: String, stats_name: String,
/// Phantom Data of Reducer /// Phantom Data of Reducer
phantom: PhantomData<(I, N, S, R, O, T)>, phantom: PhantomData<(N, O, R, S, T)>,
} }
impl<I, N, O, R, S, T> Feedback<I, S> for MapFeedback<I, N, O, R, S, T> impl<N, O, R, S, T> Feedback<S> for MapFeedback<N, O, R, S, T>
where where
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, N: IsNovel<T> + Debug,
R: Reducer<T>, O: MapObserver<Entry = T> + for<'it> AsIter<'it, Item = T> + Debug,
O: MapObserver<Entry = T>, R: Reducer<T> + Debug,
for<'it> O: AsIter<'it, Item = T>, S: UsesInput + HasClientPerfMonitor + HasNamedMetadata + Debug,
N: IsNovel<T>, T: Default + Copy + Serialize + for<'de> Deserialize<'de> + PartialEq + Debug + 'static,
I: Input,
S: HasNamedMetadata + HasClientPerfMonitor + Debug,
{ {
fn init_state(&mut self, state: &mut S) -> Result<(), Error> { fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
// Initialize `MapFeedbackMetadata` with an empty vector and add it to the state. // Initialize `MapFeedbackMetadata` with an empty vector and add it to the state.
@ -378,13 +367,13 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &<S as UsesInput>::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
self.is_interesting_default(state, manager, input, observers, exit_kind) self.is_interesting_default(state, manager, input, observers, exit_kind)
} }
@ -394,18 +383,22 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &<S as UsesInput>::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
self.is_interesting_default(state, manager, input, observers, exit_kind) self.is_interesting_default(state, manager, input, observers, exit_kind)
} }
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<I>) -> Result<(), Error> { fn append_metadata(
&mut self,
_state: &mut S,
testcase: &mut Testcase<<S as UsesInput>::Input>,
) -> Result<(), Error> {
if let Some(v) = self.indexes.as_mut() { if let Some(v) = self.indexes.as_mut() {
let meta = MapIndexesMetadata::new(core::mem::take(v)); let meta = MapIndexesMetadata::new(core::mem::take(v));
testcase.add_metadata(meta); testcase.add_metadata(meta);
@ -418,7 +411,11 @@ where
} }
/// Discard the stored metadata in case that the testcase is not added to the corpus /// Discard the stored metadata in case that the testcase is not added to the corpus
fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn discard_metadata(
&mut self,
_state: &mut S,
_input: &<S as UsesInput>::Input,
) -> Result<(), Error> {
if let Some(v) = self.indexes.as_mut() { if let Some(v) = self.indexes.as_mut() {
v.clear(); v.clear();
} }
@ -431,12 +428,11 @@ where
/// Specialize for the common coverage map size, maximization of u8s /// Specialize for the common coverage map size, maximization of u8s
#[rustversion::nightly] #[rustversion::nightly]
impl<I, O, S> Feedback<I, S> for MapFeedback<I, DifferentIsNovel, O, MaxReducer, S, u8> impl<O, S> Feedback<S> for MapFeedback<DifferentIsNovel, O, MaxReducer, S, u8>
where where
O: MapObserver<Entry = u8> + AsSlice<u8>, O: MapObserver<Entry = u8> + AsSlice<u8>,
for<'it> O: AsIter<'it, Item = u8>, for<'it> O: AsIter<'it, Item = u8>,
I: Input, S: UsesInput + HasNamedMetadata + HasClientPerfMonitor + Debug,
S: HasNamedMetadata + HasClientPerfMonitor + Debug,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
#[allow(clippy::needless_range_loop)] #[allow(clippy::needless_range_loop)]
@ -444,13 +440,13 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
_input: &I, _input: &<S as UsesInput>::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
// 128 bits vectors // 128 bits vectors
type VectorType = core::simd::u8x16; type VectorType = core::simd::u8x16;
@ -550,22 +546,14 @@ where
} }
} }
impl<I, N, O, R, S, T> Named for MapFeedback<I, N, O, R, S, T> impl<N, O, R, S, T> Named for MapFeedback<N, O, R, S, T> {
where
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
R: Reducer<T>,
N: IsNovel<T>,
O: MapObserver<Entry = T>,
for<'it> O: AsIter<'it, Item = T>,
S: HasNamedMetadata,
{
#[inline] #[inline]
fn name(&self) -> &str { fn name(&self) -> &str {
self.name.as_str() self.name.as_str()
} }
} }
impl<I, N, O, R, S, T> HasObserverName for MapFeedback<I, N, O, R, S, T> impl<N, O, R, S, T> HasObserverName for MapFeedback<N, O, R, S, T>
where where
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
R: Reducer<T>, R: Reducer<T>,
@ -584,15 +572,14 @@ fn create_stats_name(name: &str) -> String {
name.to_lowercase() name.to_lowercase()
} }
impl<I, N, O, R, S, T> MapFeedback<I, N, O, R, S, T> impl<N, O, R, S, T> MapFeedback<N, O, R, S, T>
where where
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
R: Reducer<T>, R: Reducer<T>,
O: MapObserver<Entry = T>, O: MapObserver<Entry = T>,
for<'it> O: AsIter<'it, Item = T>, for<'it> O: AsIter<'it, Item = T>,
N: IsNovel<T>, N: IsNovel<T>,
I: Input, S: UsesInput + HasNamedMetadata + HasClientPerfMonitor + Debug,
S: HasNamedMetadata + HasClientPerfMonitor + Debug,
{ {
/// Create new `MapFeedback` /// Create new `MapFeedback`
#[must_use] #[must_use]
@ -673,13 +660,13 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
_input: &I, _input: &S::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
let mut interesting = false; let mut interesting = false;
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
@ -735,13 +722,13 @@ where
/// A [`ReachabilityFeedback`] reports if a target has been reached. /// A [`ReachabilityFeedback`] reports if a target has been reached.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ReachabilityFeedback<O> { pub struct ReachabilityFeedback<O, S> {
name: String, name: String,
target_idx: Vec<usize>, target_idx: Vec<usize>,
phantom: PhantomData<O>, phantom: PhantomData<(O, S)>,
} }
impl<O> ReachabilityFeedback<O> impl<O, S> ReachabilityFeedback<O, S>
where where
O: MapObserver<Entry = usize>, O: MapObserver<Entry = usize>,
for<'it> O: AsIter<'it, Item = usize>, for<'it> O: AsIter<'it, Item = usize>,
@ -767,25 +754,24 @@ where
} }
} }
impl<I, O, S> Feedback<I, S> for ReachabilityFeedback<O> impl<O, S> Feedback<S> for ReachabilityFeedback<O, S>
where where
I: Input, S: UsesInput + Debug + HasClientPerfMonitor,
O: MapObserver<Entry = usize>, O: MapObserver<Entry = usize>,
for<'it> O: AsIter<'it, Item = usize>, for<'it> O: AsIter<'it, Item = usize>,
S: HasClientPerfMonitor,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &<S as UsesInput>::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
let observer = observers.match_name::<O>(&self.name).unwrap(); let observer = observers.match_name::<O>(&self.name).unwrap();
@ -804,7 +790,11 @@ where
} }
} }
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<I>) -> Result<(), Error> { fn append_metadata(
&mut self,
_state: &mut S,
testcase: &mut Testcase<<S as UsesInput>::Input>,
) -> Result<(), Error> {
if !self.target_idx.is_empty() { if !self.target_idx.is_empty() {
let meta = MapIndexesMetadata::new(core::mem::take(self.target_idx.as_mut())); let meta = MapIndexesMetadata::new(core::mem::take(self.target_idx.as_mut()));
testcase.add_metadata(meta); testcase.add_metadata(meta);
@ -812,13 +802,17 @@ where
Ok(()) Ok(())
} }
fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn discard_metadata(
&mut self,
_state: &mut S,
_input: &<S as UsesInput>::Input,
) -> Result<(), Error> {
self.target_idx.clear(); self.target_idx.clear();
Ok(()) Ok(())
} }
} }
impl<O> Named for ReachabilityFeedback<O> impl<O, S> Named for ReachabilityFeedback<O, S>
where where
O: MapObserver<Entry = usize>, O: MapObserver<Entry = usize>,
for<'it> O: AsIter<'it, Item = usize>, for<'it> O: AsIter<'it, Item = usize>,
@ -862,9 +856,7 @@ pub mod pybind {
use pyo3::prelude::*; use pyo3::prelude::*;
use super::{Debug, HasObserverName, MaxMapFeedback}; use super::{Debug, HasObserverName, MaxMapFeedback};
use crate::{ use crate::{feedbacks::pybind::PythonFeedback, state::pybind::PythonStdState};
feedbacks::pybind::PythonFeedback, inputs::BytesInput, state::pybind::PythonStdState,
};
macro_rules! define_python_map_feedback { macro_rules! define_python_map_feedback {
($struct_name:ident, $py_name:tt, $datatype:ty, $map_observer_type_name: ident, $my_std_state_type_name: ident) => { ($struct_name:ident, $py_name:tt, $datatype:ty, $map_observer_type_name: ident, $my_std_state_type_name: ident) => {
@ -876,7 +868,6 @@ pub mod pybind {
pub struct $struct_name { pub struct $struct_name {
/// Rust wrapped MaxMapFeedback object /// Rust wrapped MaxMapFeedback object
pub inner: MaxMapFeedback< pub inner: MaxMapFeedback<
BytesInput,
$map_observer_type_name, /* PythonMapObserverI8 */ $map_observer_type_name, /* PythonMapObserverI8 */
$my_std_state_type_name, $my_std_state_type_name,
$datatype, $datatype,

View File

@ -1,5 +1,7 @@
//! The feedbacks reduce observer state after each run to a single `is_interesting`-value. //! The feedbacks reduce observer state after each run to a single `is_interesting`-value.
//! If a testcase is interesting, it may be added to a Corpus. //! If a testcase is interesting, it may be added to a Corpus.
//!
//! TODO: make S of Feedback<S> an associated type when specialisation + AT is stable
pub mod map; pub mod map;
pub use map::*; pub use map::*;
@ -36,7 +38,7 @@ use crate::{
corpus::Testcase, corpus::Testcase,
events::EventFirer, events::EventFirer,
executors::ExitKind, executors::ExitKind,
inputs::Input, inputs::UsesInput,
observers::{ListObserver, ObserversTuple, TimeObserver}, observers::{ListObserver, ObserversTuple, TimeObserver},
state::HasClientPerfMonitor, state::HasClientPerfMonitor,
Error, Error,
@ -45,10 +47,9 @@ use crate::{
/// 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, S>: Named + Debug pub trait Feedback<S>: Named + Debug
where where
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
/// Initializes the feedback state. /// Initializes the feedback state.
/// This method is called after that the `State` is created. /// This method is called after that the `State` is created.
@ -62,13 +63,13 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>; OT: ObserversTuple<S>;
/// Returns if the result of a run is interesting and the value input should be stored in a corpus. /// Returns if the result of a run is interesting and the value input should be stored in a corpus.
/// It also keeps track of introspection stats. /// It also keeps track of introspection stats.
@ -79,13 +80,13 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
// Start a timer for this feedback // Start a timer for this feedback
let start_time = crate::bolts::cpu::read_time_counter(); let start_time = crate::bolts::cpu::read_time_counter();
@ -109,14 +110,14 @@ where
fn append_metadata( fn append_metadata(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_testcase: &mut Testcase<I>, _testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Discard the stored metadata in case that the testcase is not added to the corpus /// Discard the stored metadata in case that the testcase is not added to the corpus
#[inline] #[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(()) Ok(())
} }
} }
@ -129,42 +130,39 @@ pub trait HasObserverName {
/// A combined feedback consisting of multiple [`Feedback`]s /// A combined feedback consisting of multiple [`Feedback`]s
#[derive(Debug)] #[derive(Debug)]
pub struct CombinedFeedback<A, B, FL, I, S> pub struct CombinedFeedback<A, B, FL, S>
where where
A: Feedback<I, S>, A: Feedback<S>,
B: Feedback<I, S>, B: Feedback<S>,
FL: FeedbackLogic<A, B, I, S>, FL: FeedbackLogic<A, B, S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
/// First [`Feedback`] /// First [`Feedback`]
pub first: A, pub first: A,
/// Second [`Feedback`] /// Second [`Feedback`]
pub second: B, pub second: B,
name: String, name: String,
phantom: PhantomData<(I, S, FL)>, phantom: PhantomData<(S, FL)>,
} }
impl<A, B, FL, I, S> Named for CombinedFeedback<A, B, FL, I, S> impl<A, B, FL, S> Named for CombinedFeedback<A, B, FL, S>
where where
A: Feedback<I, S>, A: Feedback<S>,
B: Feedback<I, S>, B: Feedback<S>,
FL: FeedbackLogic<A, B, I, S>, FL: FeedbackLogic<A, B, S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn name(&self) -> &str { fn name(&self) -> &str {
self.name.as_ref() self.name.as_ref()
} }
} }
impl<A, B, FL, I, S> CombinedFeedback<A, B, FL, I, S> impl<A, B, FL, S> CombinedFeedback<A, B, FL, S>
where where
A: Feedback<I, S>, A: Feedback<S>,
B: Feedback<I, S>, B: Feedback<S>,
FL: FeedbackLogic<A, B, I, S>, FL: FeedbackLogic<A, B, S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
/// Create a new combined feedback /// Create a new combined feedback
pub fn new(first: A, second: B) -> Self { pub fn new(first: A, second: B) -> Self {
@ -178,13 +176,12 @@ where
} }
} }
impl<A, B, FL, I, S> Feedback<I, S> for CombinedFeedback<A, B, FL, I, S> impl<A, B, FL, S> Feedback<S> for CombinedFeedback<A, B, FL, S>
where where
A: Feedback<I, S>, A: Feedback<S>,
B: Feedback<I, S>, B: Feedback<S>,
FL: FeedbackLogic<A, B, I, S>, FL: FeedbackLogic<A, B, S>,
I: Input, S: UsesInput + HasClientPerfMonitor + Debug,
S: HasClientPerfMonitor + Debug,
{ {
fn init_state(&mut self, state: &mut S) -> Result<(), Error> { fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
self.first.init_state(state)?; self.first.init_state(state)?;
@ -197,13 +194,13 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
FL::is_pair_interesting( FL::is_pair_interesting(
&mut self.first, &mut self.first,
@ -222,13 +219,13 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
FL::is_pair_interesting_introspection( FL::is_pair_interesting_introspection(
&mut self.first, &mut self.first,
@ -242,25 +239,28 @@ where
} }
#[inline] #[inline]
fn append_metadata(&mut self, state: &mut S, testcase: &mut Testcase<I>) -> Result<(), Error> { fn append_metadata(
&mut self,
state: &mut S,
testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> {
self.first.append_metadata(state, testcase)?; self.first.append_metadata(state, testcase)?;
self.second.append_metadata(state, testcase) self.second.append_metadata(state, testcase)
} }
#[inline] #[inline]
fn discard_metadata(&mut self, state: &mut S, input: &I) -> Result<(), Error> { fn discard_metadata(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.first.discard_metadata(state, input)?; self.first.discard_metadata(state, input)?;
self.second.discard_metadata(state, input) self.second.discard_metadata(state, input)
} }
} }
/// Logical combination of two feedbacks /// Logical combination of two feedbacks
pub trait FeedbackLogic<A, B, I, S>: 'static + Debug pub trait FeedbackLogic<A, B, S>: 'static + Debug
where where
A: Feedback<I, S>, A: Feedback<S>,
B: Feedback<I, S>, B: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
/// The name of this combination /// The name of this combination
fn name() -> &'static str; fn name() -> &'static str;
@ -271,13 +271,13 @@ where
second: &mut B, second: &mut B,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>; OT: ObserversTuple<S>;
/// If this pair is interesting (with introspection features enabled) /// If this pair is interesting (with introspection features enabled)
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
@ -287,33 +287,31 @@ where
second: &mut B, second: &mut B,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>; OT: ObserversTuple<S>;
} }
/// Factory for feedbacks which should be sensitive to an existing context, e.g. observer(s) from a /// Factory for feedbacks which should be sensitive to an existing context, e.g. observer(s) from a
/// specific execution /// specific execution
pub trait FeedbackFactory<F, I, S, T> pub trait FeedbackFactory<F, S, T>
where where
F: Feedback<I, S>, F: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
/// Create the feedback from the provided context /// Create the feedback from the provided context
fn create_feedback(&self, ctx: &T) -> F; fn create_feedback(&self, ctx: &T) -> F;
} }
impl<FE, FU, I, S, T> FeedbackFactory<FE, I, S, T> for FU impl<FE, FU, S, T> FeedbackFactory<FE, S, T> for FU
where where
FU: Fn(&T) -> FE, FU: Fn(&T) -> FE,
FE: Feedback<I, S>, FE: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn create_feedback(&self, ctx: &T) -> FE { fn create_feedback(&self, ctx: &T) -> FE {
self(ctx) self(ctx)
@ -340,11 +338,10 @@ where
} }
} }
impl<F, I, S, T> FeedbackFactory<F, I, S, T> for DefaultFeedbackFactory<F> impl<F, S, T> FeedbackFactory<F, S, T> for DefaultFeedbackFactory<F>
where where
F: Feedback<I, S> + Default, F: Feedback<S> + Default,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn create_feedback(&self, _ctx: &T) -> F { fn create_feedback(&self, _ctx: &T) -> F {
F::default() F::default()
@ -367,12 +364,11 @@ pub struct LogicEagerAnd {}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LogicFastAnd {} pub struct LogicFastAnd {}
impl<A, B, I, S> FeedbackLogic<A, B, I, S> for LogicEagerOr impl<A, B, S> FeedbackLogic<A, B, S> for LogicEagerOr
where where
A: Feedback<I, S>, A: Feedback<S>,
B: Feedback<I, S>, B: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn name() -> &'static str { fn name() -> &'static str {
"Eager OR" "Eager OR"
@ -383,13 +379,13 @@ where
second: &mut B, second: &mut B,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
let a = first.is_interesting(state, manager, input, observers, exit_kind)?; let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
let b = second.is_interesting(state, manager, input, observers, exit_kind)?; let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
@ -402,13 +398,13 @@ where
second: &mut B, second: &mut B,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
// Execute this feedback // Execute this feedback
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
@ -418,12 +414,11 @@ where
} }
} }
impl<A, B, I, S> FeedbackLogic<A, B, I, S> for LogicFastOr impl<A, B, S> FeedbackLogic<A, B, S> for LogicFastOr
where where
A: Feedback<I, S>, A: Feedback<S>,
B: Feedback<I, S>, B: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn name() -> &'static str { fn name() -> &'static str {
"Fast OR" "Fast OR"
@ -434,13 +429,13 @@ where
second: &mut B, second: &mut B,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
let a = first.is_interesting(state, manager, input, observers, exit_kind)?; let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
if a { if a {
@ -456,13 +451,13 @@ where
second: &mut B, second: &mut B,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
// Execute this feedback // Execute this feedback
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
@ -475,12 +470,11 @@ where
} }
} }
impl<A, B, I, S> FeedbackLogic<A, B, I, S> for LogicEagerAnd impl<A, B, S> FeedbackLogic<A, B, S> for LogicEagerAnd
where where
A: Feedback<I, S>, A: Feedback<S>,
B: Feedback<I, S>, B: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn name() -> &'static str { fn name() -> &'static str {
"Eager AND" "Eager AND"
@ -491,13 +485,13 @@ where
second: &mut B, second: &mut B,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
let a = first.is_interesting(state, manager, input, observers, exit_kind)?; let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
let b = second.is_interesting(state, manager, input, observers, exit_kind)?; let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
@ -510,13 +504,13 @@ where
second: &mut B, second: &mut B,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
// Execute this feedback // Execute this feedback
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
@ -526,12 +520,11 @@ where
} }
} }
impl<A, B, I, S> FeedbackLogic<A, B, I, S> for LogicFastAnd impl<A, B, S> FeedbackLogic<A, B, S> for LogicFastAnd
where where
A: Feedback<I, S>, A: Feedback<S>,
B: Feedback<I, S>, B: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn name() -> &'static str { fn name() -> &'static str {
"Fast AND" "Fast AND"
@ -542,13 +535,13 @@ where
second: &mut B, second: &mut B,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
let a = first.is_interesting(state, manager, input, observers, exit_kind)?; let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
if !a { if !a {
@ -564,13 +557,13 @@ where
second: &mut B, second: &mut B,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
// Execute this feedback // Execute this feedback
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
@ -585,42 +578,40 @@ where
/// Combine two feedbacks with an eager AND operation, /// Combine two feedbacks with an eager AND operation,
/// will call all feedbacks functions even if not necessary to conclude the result /// will call all feedbacks functions even if not necessary to conclude the result
pub type EagerAndFeedback<A, B, I, S> = CombinedFeedback<A, B, LogicEagerAnd, I, S>; pub type EagerAndFeedback<A, B, S> = CombinedFeedback<A, B, LogicEagerAnd, S>;
/// Combine two feedbacks with an fast AND operation, /// Combine two feedbacks with an fast AND operation,
/// might skip calling feedbacks functions if not necessary to conclude the result /// might skip calling feedbacks functions if not necessary to conclude the result
pub type FastAndFeedback<A, B, I, S> = CombinedFeedback<A, B, LogicFastAnd, I, S>; pub type FastAndFeedback<A, B, S> = CombinedFeedback<A, B, LogicFastAnd, S>;
/// Combine two feedbacks with an eager OR operation, /// Combine two feedbacks with an eager OR operation,
/// will call all feedbacks functions even if not necessary to conclude the result /// will call all feedbacks functions even if not necessary to conclude the result
pub type EagerOrFeedback<A, B, I, S> = CombinedFeedback<A, B, LogicEagerOr, I, S>; pub type EagerOrFeedback<A, B, S> = CombinedFeedback<A, B, LogicEagerOr, S>;
/// Combine two feedbacks with an fast OR operation, /// Combine two feedbacks with an fast OR operation,
/// might skip calling feedbacks functions if not necessary to conclude the result. /// might skip calling feedbacks functions if not necessary to conclude the result.
/// This means any feedback that is not first might be skipped, use caution when using with /// This means any feedback that is not first might be skipped, use caution when using with
/// `TimeFeedback` /// `TimeFeedback`
pub type FastOrFeedback<A, B, I, S> = CombinedFeedback<A, B, LogicFastOr, I, S>; pub type FastOrFeedback<A, B, S> = CombinedFeedback<A, B, LogicFastOr, S>;
/// Compose feedbacks with an `NOT` operation /// Compose feedbacks with an `NOT` operation
#[derive(Clone)] #[derive(Clone)]
pub struct NotFeedback<A, I, S> pub struct NotFeedback<A, S>
where where
A: Feedback<I, S>, A: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
/// The feedback to invert /// The feedback to invert
pub first: A, pub first: A,
/// The name /// The name
name: String, name: String,
phantom: PhantomData<(I, S)>, phantom: PhantomData<S>,
} }
impl<A, I, S> Debug for NotFeedback<A, I, S> impl<A, S> Debug for NotFeedback<A, S>
where where
A: Feedback<I, S>, A: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("NotFeedback") f.debug_struct("NotFeedback")
@ -630,11 +621,10 @@ where
} }
} }
impl<A, I, S> Feedback<I, S> for NotFeedback<A, I, S> impl<A, S> Feedback<S> for NotFeedback<A, S>
where where
A: Feedback<I, S>, A: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn init_state(&mut self, state: &mut S) -> Result<(), Error> { fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
self.first.init_state(state) self.first.init_state(state)
@ -645,13 +635,13 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: &S::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
Ok(!self Ok(!self
.first .first
@ -659,21 +649,24 @@ where
} }
#[inline] #[inline]
fn append_metadata(&mut self, state: &mut S, testcase: &mut Testcase<I>) -> Result<(), Error> { fn append_metadata(
&mut self,
state: &mut S,
testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> {
self.first.append_metadata(state, testcase) self.first.append_metadata(state, testcase)
} }
#[inline] #[inline]
fn discard_metadata(&mut self, state: &mut S, input: &I) -> Result<(), Error> { fn discard_metadata(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.first.discard_metadata(state, input) self.first.discard_metadata(state, input)
} }
} }
impl<A, I, S> Named for NotFeedback<A, I, S> impl<A, S> Named for NotFeedback<A, S>
where where
A: Feedback<I, S>, A: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
#[inline] #[inline]
fn name(&self) -> &str { fn name(&self) -> &str {
@ -681,11 +674,10 @@ where
} }
} }
impl<A, I, S> NotFeedback<A, I, S> impl<A, S> NotFeedback<A, S>
where where
A: Feedback<I, S>, A: Feedback<S>,
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
/// Creates a new [`NotFeedback`]. /// Creates a new [`NotFeedback`].
pub fn new(first: A) -> Self { pub fn new(first: A) -> Self {
@ -751,23 +743,22 @@ macro_rules! feedback_not {
} }
/// Hack to use () as empty Feedback /// Hack to use () as empty Feedback
impl<I, S> Feedback<I, S> for () impl<S> Feedback<S> for ()
where where
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &S::Input,
_observers: &OT, _observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
Ok(false) Ok(false)
} }
@ -784,23 +775,22 @@ impl Named for () {
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CrashFeedback {} pub struct CrashFeedback {}
impl<I, S> Feedback<I, S> for CrashFeedback impl<S> Feedback<S> for CrashFeedback
where where
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &S::Input,
_observers: &OT, _observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
if let ExitKind::Crash = exit_kind { if let ExitKind::Crash = exit_kind {
Ok(true) Ok(true)
@ -838,23 +828,22 @@ pub type CrashFeedbackFactory = DefaultFeedbackFactory<CrashFeedback>;
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TimeoutFeedback {} pub struct TimeoutFeedback {}
impl<I, S> Feedback<I, S> for TimeoutFeedback impl<S> Feedback<S> for TimeoutFeedback
where where
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &S::Input,
_observers: &OT, _observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
if let ExitKind::Timeout = exit_kind { if let ExitKind::Timeout = exit_kind {
Ok(true) Ok(true)
@ -897,23 +886,22 @@ pub struct TimeFeedback {
name: String, name: String,
} }
impl<I, S> Feedback<I, S> for TimeFeedback impl<S> Feedback<S> for TimeFeedback
where where
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &S::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
let observer = observers.match_name::<TimeObserver>(self.name()).unwrap(); let observer = observers.match_name::<TimeObserver>(self.name()).unwrap();
@ -923,7 +911,11 @@ where
/// 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]
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<I>) -> Result<(), Error> { fn append_metadata(
&mut self,
_state: &mut S,
testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> {
*testcase.exec_time_mut() = self.exec_time; *testcase.exec_time_mut() = self.exec_time;
self.exec_time = None; self.exec_time = None;
Ok(()) Ok(())
@ -931,7 +923,7 @@ where
/// Discard the stored metadata in case that the testcase is not added to the corpus /// Discard the stored metadata in case that the testcase is not added to the corpus
#[inline] #[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.exec_time = None; self.exec_time = None;
Ok(()) Ok(())
} }
@ -974,10 +966,9 @@ where
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
impl<I, S, T> Feedback<I, S> for ListFeedback<T> impl<S, T> Feedback<S> for ListFeedback<T>
where where
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
T: Debug + Serialize + serde::de::DeserializeOwned, T: Debug + Serialize + serde::de::DeserializeOwned,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
@ -985,13 +976,13 @@ where
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &S::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
let observer = observers let observer = observers
@ -1045,10 +1036,9 @@ pub enum ConstFeedback {
False, False,
} }
impl<I, S> Feedback<I, S> for ConstFeedback impl<S> Feedback<S> for ConstFeedback
where where
I: Input, S: UsesInput + HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
#[inline] #[inline]
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
@ -1056,13 +1046,13 @@ where
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &S::Input,
_observers: &OT, _observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
Ok(match self { Ok(match self {
ConstFeedback::True => true, ConstFeedback::True => true,
@ -1168,7 +1158,7 @@ pub mod pybind {
} }
} }
impl Feedback<BytesInput, PythonStdState> for PyObjectFeedback { impl Feedback<PythonStdState> for PyObjectFeedback {
fn init_state(&mut self, state: &mut PythonStdState) -> Result<(), Error> { fn init_state(&mut self, state: &mut PythonStdState) -> Result<(), Error> {
Python::with_gil(|py| -> PyResult<()> { Python::with_gil(|py| -> PyResult<()> {
self.inner self.inner
@ -1187,8 +1177,8 @@ pub mod pybind {
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<BytesInput>, EM: EventFirer<State = PythonStdState>,
OT: ObserversTuple<BytesInput, PythonStdState>, OT: ObserversTuple<PythonStdState>,
{ {
// SAFETY: We use this observer in Python ony when the ObserverTuple is PythonObserversTuple // SAFETY: We use this observer in Python ony when the ObserverTuple is PythonObserversTuple
let dont_look_at_this: &PythonObserversTuple = let dont_look_at_this: &PythonObserversTuple =
@ -1295,7 +1285,7 @@ pub mod pybind {
#[derive(Debug)] #[derive(Debug)]
#[pyclass(unsendable, name = "NotFeedback")] #[pyclass(unsendable, name = "NotFeedback")]
pub struct PythonNotFeedback { pub struct PythonNotFeedback {
pub inner: NotFeedback<PythonFeedback, BytesInput, PythonStdState>, pub inner: NotFeedback<PythonFeedback, PythonStdState>,
} }
#[pymethods] #[pymethods]
@ -1318,7 +1308,7 @@ pub mod pybind {
#[derive(Debug)] #[derive(Debug)]
#[pyclass(unsendable, name = $pystring)] #[pyclass(unsendable, name = $pystring)]
pub struct $pyname { pub struct $pyname {
pub inner: $feed<PythonFeedback, PythonFeedback, BytesInput, PythonStdState>, pub inner: $feed<PythonFeedback, PythonFeedback, PythonStdState>,
} }
#[pymethods] #[pymethods]
@ -1624,10 +1614,10 @@ pub mod pybind {
} }
} }
impl Feedback<BytesInput, PythonStdState> for PythonFeedback { impl Feedback<PythonStdState> for PythonFeedback {
fn init_state(&mut self, state: &mut PythonStdState) -> Result<(), Error> { fn init_state(&mut self, state: &mut PythonStdState) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, f, { unwrap_me_mut!(self.wrapper, f, {
Feedback::<BytesInput, PythonStdState>::init_state(f, state) Feedback::<PythonStdState>::init_state(f, state)
}) })
} }
@ -1640,8 +1630,8 @@ pub mod pybind {
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<BytesInput>, EM: EventFirer<State = PythonStdState>,
OT: ObserversTuple<BytesInput, PythonStdState>, OT: ObserversTuple<PythonStdState>,
{ {
unwrap_me_mut!(self.wrapper, f, { unwrap_me_mut!(self.wrapper, f, {
f.is_interesting(state, manager, input, observers, exit_kind) f.is_interesting(state, manager, input, observers, exit_kind)

View File

@ -1,6 +1,6 @@
//! Nautilus grammar mutator, see <https://github.com/nautilus-fuzz/nautilus> //! Nautilus grammar mutator, see <https://github.com/nautilus-fuzz/nautilus>
use alloc::string::String; use alloc::string::String;
use core::fmt::Debug; use core::{fmt::Debug, marker::PhantomData};
use std::fs::create_dir_all; use std::fs::create_dir_all;
use grammartec::{chunkstore::ChunkStore, context::Context}; use grammartec::{chunkstore::ChunkStore, context::Context};
@ -16,6 +16,7 @@ use crate::{
generators::NautilusContext, generators::NautilusContext,
inputs::NautilusInput, inputs::NautilusInput,
observers::ObserversTuple, observers::ObserversTuple,
prelude::UsesInput,
state::{HasClientPerfMonitor, HasMetadata}, state::{HasClientPerfMonitor, HasMetadata},
Error, Error,
}; };
@ -52,33 +53,37 @@ impl NautilusChunksMetadata {
} }
/// A nautilus feedback for grammar fuzzing /// A nautilus feedback for grammar fuzzing
pub struct NautilusFeedback<'a> { pub struct NautilusFeedback<'a, S> {
ctx: &'a Context, ctx: &'a Context,
phantom: PhantomData<S>,
} }
impl Debug for NautilusFeedback<'_> { impl<S> Debug for NautilusFeedback<'_, S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "NautilusFeedback {{}}") write!(f, "NautilusFeedback {{}}")
} }
} }
impl<'a> NautilusFeedback<'a> { impl<'a, S> NautilusFeedback<'a, S> {
/// Create a new [`NautilusFeedback`] /// Create a new [`NautilusFeedback`]
#[must_use] #[must_use]
pub fn new(context: &'a NautilusContext) -> Self { pub fn new(context: &'a NautilusContext) -> Self {
Self { ctx: &context.ctx } Self {
ctx: &context.ctx,
phantom: PhantomData,
}
} }
} }
impl<'a> Named for NautilusFeedback<'a> { impl<'a, S> Named for NautilusFeedback<'a, S> {
fn name(&self) -> &str { fn name(&self) -> &str {
"NautilusFeedback" "NautilusFeedback"
} }
} }
impl<'a, S> Feedback<NautilusInput, S> for NautilusFeedback<'a> impl<'a, S> Feedback<S> for NautilusFeedback<'a, S>
where where
S: HasMetadata + HasClientPerfMonitor, S: HasMetadata + HasClientPerfMonitor + UsesInput<Input = NautilusInput>,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
@ -90,8 +95,8 @@ where
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<NautilusInput>, EM: EventFirer<State = S>,
OT: ObserversTuple<NautilusInput, S>, OT: ObserversTuple<S>,
{ {
Ok(false) Ok(false)
} }

View File

@ -11,7 +11,7 @@ use crate::{
events::EventFirer, events::EventFirer,
executors::ExitKind, executors::ExitKind,
feedbacks::{Feedback, HasObserverName}, feedbacks::{Feedback, HasObserverName},
inputs::Input, inputs::UsesInput,
observers::{ObserverWithHashField, ObserversTuple}, observers::{ObserverWithHashField, ObserversTuple},
state::{HasClientPerfMonitor, HasNamedMetadata}, state::{HasClientPerfMonitor, HasNamedMetadata},
Error, Error,
@ -68,17 +68,16 @@ impl HashSetState<u64> for NewHashFeedbackMetadata {
/// A [`NewHashFeedback`] maintains a hashset of already seen stacktraces and considers interesting unseen ones /// A [`NewHashFeedback`] maintains a hashset of already seen stacktraces and considers interesting unseen ones
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct NewHashFeedback<O> { pub struct NewHashFeedback<O, S> {
name: String, name: String,
observer_name: String, observer_name: String,
o_type: PhantomData<O>, o_type: PhantomData<(O, S)>,
} }
impl<I, S, O> Feedback<I, S> for NewHashFeedback<O> impl<O, S> Feedback<S> for NewHashFeedback<O, S>
where where
I: Input,
S: HasClientPerfMonitor + HasNamedMetadata,
O: ObserverWithHashField + Named + Debug, O: ObserverWithHashField + Named + Debug,
S: UsesInput + Debug + HasNamedMetadata + HasClientPerfMonitor,
{ {
fn init_state(&mut self, state: &mut S) -> Result<(), Error> { fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
state.add_named_metadata(NewHashFeedbackMetadata::default(), &self.name); state.add_named_metadata(NewHashFeedbackMetadata::default(), &self.name);
@ -90,13 +89,13 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &<S as UsesInput>::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
let observer = observers let observer = observers
.match_name::<O>(&self.observer_name) .match_name::<O>(&self.observer_name)
@ -122,21 +121,21 @@ where
} }
} }
impl<O> Named for NewHashFeedback<O> { impl<O, S> Named for NewHashFeedback<O, S> {
#[inline] #[inline]
fn name(&self) -> &str { fn name(&self) -> &str {
&self.name &self.name
} }
} }
impl<O> HasObserverName for NewHashFeedback<O> { impl<O, S> HasObserverName for NewHashFeedback<O, S> {
#[inline] #[inline]
fn observer_name(&self) -> &str { fn observer_name(&self) -> &str {
&self.observer_name &self.observer_name
} }
} }
impl<O> NewHashFeedback<O> impl<O, S> NewHashFeedback<O, S>
where where
O: ObserverWithHashField + Named + Debug, O: ObserverWithHashField + Named + Debug,
{ {

View File

@ -1,23 +1,29 @@
//! The `Fuzzer` is the main struct for a fuzz campaign. //! The `Fuzzer` is the main struct for a fuzz campaign.
use alloc::string::ToString; use alloc::string::ToString;
use core::{marker::PhantomData, time::Duration}; use core::{fmt::Debug, marker::PhantomData, time::Duration};
use serde::{de::DeserializeOwned, Serialize};
#[cfg(test)]
use crate::inputs::Input;
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
use crate::monitors::PerfFeature; use crate::monitors::PerfFeature;
#[cfg(test)]
use crate::state::NopState;
use crate::{ use crate::{
bolts::current_time, bolts::current_time,
corpus::{Corpus, Testcase}, corpus::{Corpus, Testcase},
events::{Event, EventConfig, EventFirer, EventManager, ProgressReporter}, events::{Event, EventConfig, EventFirer, EventProcessor, ProgressReporter},
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
feedbacks::Feedback, feedbacks::Feedback,
inputs::Input, inputs::UsesInput,
mark_feature_time, mark_feature_time,
observers::ObserversTuple, observers::ObserversTuple,
schedulers::Scheduler, schedulers::Scheduler,
stages::StagesTuple, stages::StagesTuple,
start_timer, start_timer,
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasSolutions}, state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasSolutions, UsesState},
Error, Error,
}; };
@ -25,10 +31,9 @@ use crate::{
const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15); const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
/// Holds a scheduler /// Holds a scheduler
pub trait HasScheduler<CS, I, S> pub trait HasScheduler<CS>: UsesState
where where
CS: Scheduler<I, S>, CS: Scheduler<State = Self::State>,
I: Input,
{ {
/// The scheduler /// The scheduler
fn scheduler(&self) -> &CS; fn scheduler(&self) -> &CS;
@ -38,11 +43,10 @@ where
} }
/// Holds an feedback /// Holds an feedback
pub trait HasFeedback<F, I, S> pub trait HasFeedback<F>: UsesState
where where
F: Feedback<I, S>, F: Feedback<Self::State>,
I: Input, Self::State: HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
/// The feedback /// The feedback
fn feedback(&self) -> &F; fn feedback(&self) -> &F;
@ -52,11 +56,10 @@ where
} }
/// Holds an objective feedback /// Holds an objective feedback
pub trait HasObjective<I, OF, S> pub trait HasObjective<OF>: UsesState
where where
OF: Feedback<I, S>, OF: Feedback<Self::State>,
I: Input, Self::State: HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
/// The objective feedback /// The objective feedback
fn objective(&self) -> &OF; fn objective(&self) -> &OF;
@ -66,56 +69,53 @@ where
} }
/// Evaluate if an input is interesting using the feedback /// Evaluate if an input is interesting using the feedback
pub trait ExecutionProcessor<I, OT, S> pub trait ExecutionProcessor<OT>: UsesState {
where
OT: ObserversTuple<I, S>,
I: Input,
{
/// Evaluate if a set of observation channels has an interesting state /// Evaluate if a set of observation channels has an interesting state
fn process_execution<EM>( fn process_execution<EM>(
&mut self, &mut self,
state: &mut S, state: &mut Self::State,
manager: &mut EM, manager: &mut EM,
input: I, input: <Self::State as UsesInput>::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
send_events: bool, send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error> ) -> Result<(ExecuteInputResult, Option<usize>), Error>
where where
EM: EventFirer<I>; EM: EventFirer<State = Self::State>;
} }
/// Evaluate an input modifying the state of the fuzzer /// Evaluate an input modifying the state of the fuzzer
pub trait EvaluatorObservers<I, OT, S>: Sized pub trait EvaluatorObservers<OT>: UsesState + Sized {
where
I: Input,
OT: ObserversTuple<I, S>,
{
/// Runs the input and triggers observers and feedback, /// Runs the input and triggers observers and feedback,
/// returns if is interesting an (option) the index of the new testcase in the corpus /// returns if is interesting an (option) the index of the new
/// [`crate::corpus::Testcase`] in the [`crate::corpus::Corpus`]
fn evaluate_input_with_observers<E, EM>( fn evaluate_input_with_observers<E, EM>(
&mut self, &mut self,
state: &mut S, state: &mut Self::State,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: I, input: <Self::State as UsesInput>::Input,
send_events: bool, send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error> ) -> Result<(ExecuteInputResult, Option<usize>), Error>
where where
E: Executor<EM, I, S, Self> + HasObservers<I, OT, S>, E: Executor<EM, Self> + HasObservers<Observers = OT, State = Self::State>,
EM: EventManager<E, I, S, Self>; EM: EventFirer<State = Self::State>;
} }
/// Evaluate an input modifying the state of the fuzzer /// Evaluate an input modifying the state of the fuzzer
pub trait Evaluator<E, EM, I, S> { pub trait Evaluator<E, EM>: UsesState
where
E: UsesState<State = Self::State>,
EM: UsesState<State = Self::State>,
{
/// Runs the input and triggers observers and feedback, /// Runs the input and triggers observers and feedback,
/// returns if is interesting an (option) the index of the new testcase in the corpus /// returns if is interesting an (option) the index of the new [`crate::corpus::Testcase`] in the corpus
fn evaluate_input( fn evaluate_input(
&mut self, &mut self,
state: &mut S, state: &mut Self::State,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: I, input: <Self::State as UsesInput>::Input,
) -> Result<(ExecuteInputResult, Option<usize>), Error> { ) -> Result<(ExecuteInputResult, Option<usize>), Error> {
self.evaluate_input_events(state, executor, manager, input, true) self.evaluate_input_events(state, executor, manager, input, true)
} }
@ -125,10 +125,10 @@ pub trait Evaluator<E, EM, I, S> {
/// This version has a boolean to decide if send events to the manager. /// This version has a boolean to decide if send events to the manager.
fn evaluate_input_events( fn evaluate_input_events(
&mut self, &mut self,
state: &mut S, state: &mut Self::State,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: I, input: <Self::State as UsesInput>::Input,
send_events: bool, send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error>; ) -> Result<(ExecuteInputResult, Option<usize>), Error>;
@ -138,20 +138,20 @@ pub trait Evaluator<E, EM, I, S> {
/// Usually, you want to use [`Evaluator::evaluate_input`], unless you know what you are doing. /// Usually, you want to use [`Evaluator::evaluate_input`], unless you know what you are doing.
fn add_input( fn add_input(
&mut self, &mut self,
state: &mut S, state: &mut Self::State,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: I, input: <Self::State as UsesInput>::Input,
) -> Result<usize, Error>; ) -> Result<usize, Error>;
} }
/// The main fuzzer trait. /// The main fuzzer trait.
pub trait Fuzzer<E, EM, I, S, ST> pub trait Fuzzer<E, EM, ST>: Sized + UsesState
where where
I: Input, Self::State: HasClientPerfMonitor + HasMetadata + HasExecutions,
EM: ProgressReporter<I>, E: UsesState<State = Self::State>,
S: HasExecutions + HasClientPerfMonitor + HasMetadata, EM: ProgressReporter<State = Self::State>,
ST: ?Sized, ST: StagesTuple<E, EM, Self::State, Self>,
{ {
/// Fuzz for a single iteration. /// Fuzz for a single iteration.
/// Returns the index of the last fuzzed corpus item. /// Returns the index of the last fuzzed corpus item.
@ -166,7 +166,7 @@ where
&mut self, &mut self,
stages: &mut ST, stages: &mut ST,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut EM::State,
manager: &mut EM, manager: &mut EM,
) -> Result<usize, Error>; ) -> Result<usize, Error>;
@ -175,7 +175,7 @@ where
&mut self, &mut self,
stages: &mut ST, stages: &mut ST,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut EM::State,
manager: &mut EM, manager: &mut EM,
) -> Result<usize, Error> { ) -> Result<usize, Error> {
let mut last = current_time(); let mut last = current_time();
@ -199,7 +199,7 @@ where
&mut self, &mut self,
stages: &mut ST, stages: &mut ST,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut EM::State,
manager: &mut EM, manager: &mut EM,
iters: u64, iters: u64,
) -> Result<usize, Error> { ) -> Result<usize, Error> {
@ -240,27 +240,35 @@ pub enum ExecuteInputResult {
/// Your default fuzzer instance, for everyday use. /// Your default fuzzer instance, for everyday use.
#[derive(Debug)] #[derive(Debug)]
pub struct StdFuzzer<CS, F, I, OF, OT, S> pub struct StdFuzzer<CS, F, OF, OT>
where where
CS: Scheduler<I, S>, CS: Scheduler,
F: Feedback<I, S>, F: Feedback<CS::State>,
I: Input, OF: Feedback<CS::State>,
OF: Feedback<I, S>, CS::State: HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
scheduler: CS, scheduler: CS,
feedback: F, feedback: F,
objective: OF, objective: OF,
phantom: PhantomData<(I, OT, S)>, phantom: PhantomData<OT>,
} }
impl<CS, F, I, OF, OT, S> HasScheduler<CS, I, S> for StdFuzzer<CS, F, I, OF, OT, S> impl<CS, F, OF, OT> UsesState for StdFuzzer<CS, F, OF, OT>
where where
CS: Scheduler<I, S>, CS: Scheduler,
F: Feedback<I, S>, F: Feedback<CS::State>,
I: Input, OF: Feedback<CS::State>,
OF: Feedback<I, S>, CS::State: HasClientPerfMonitor,
S: HasClientPerfMonitor, {
type State = CS::State;
}
impl<CS, F, OF, OT> HasScheduler<CS> for StdFuzzer<CS, F, OF, OT>
where
CS: Scheduler,
F: Feedback<CS::State>,
OF: Feedback<CS::State>,
CS::State: HasClientPerfMonitor,
{ {
fn scheduler(&self) -> &CS { fn scheduler(&self) -> &CS {
&self.scheduler &self.scheduler
@ -271,13 +279,12 @@ where
} }
} }
impl<CS, F, I, OF, OT, S> HasFeedback<F, I, S> for StdFuzzer<CS, F, I, OF, OT, S> impl<CS, F, OF, OT> HasFeedback<F> for StdFuzzer<CS, F, OF, OT>
where where
CS: Scheduler<I, S>, CS: Scheduler,
F: Feedback<I, S>, F: Feedback<CS::State>,
I: Input, OF: Feedback<CS::State>,
OF: Feedback<I, S>, CS::State: HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn feedback(&self) -> &F { fn feedback(&self) -> &F {
&self.feedback &self.feedback
@ -288,13 +295,12 @@ where
} }
} }
impl<CS, F, I, OF, OT, S> HasObjective<I, OF, S> for StdFuzzer<CS, F, I, OF, OT, S> impl<CS, F, OF, OT> HasObjective<OF> for StdFuzzer<CS, F, OF, OT>
where where
CS: Scheduler<I, S>, CS: Scheduler,
F: Feedback<I, S>, F: Feedback<CS::State>,
I: Input, OF: Feedback<CS::State>,
OF: Feedback<I, S>, CS::State: HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn objective(&self) -> &OF { fn objective(&self) -> &OF {
&self.objective &self.objective
@ -305,27 +311,26 @@ where
} }
} }
impl<CS, F, I, OF, OT, S> ExecutionProcessor<I, OT, S> for StdFuzzer<CS, F, I, OF, OT, S> impl<CS, F, OF, OT> ExecutionProcessor<OT> for StdFuzzer<CS, F, OF, OT>
where where
CS: Scheduler<I, S>, CS: Scheduler,
F: Feedback<I, S>, F: Feedback<CS::State>,
I: Input, OF: Feedback<CS::State>,
OF: Feedback<I, S>, OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned,
OT: ObserversTuple<I, S> + serde::Serialize + serde::de::DeserializeOwned, CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions,
S: HasCorpus<I> + HasSolutions<I> + HasClientPerfMonitor + HasExecutions,
{ {
/// Evaluate if a set of observation channels has an interesting state /// Evaluate if a set of observation channels has an interesting state
fn process_execution<EM>( fn process_execution<EM>(
&mut self, &mut self,
state: &mut S, state: &mut CS::State,
manager: &mut EM, manager: &mut EM,
input: I, input: <CS::State as UsesInput>::Input,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
send_events: bool, send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error> ) -> Result<(ExecuteInputResult, Option<usize>), Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = Self::State>,
{ {
let mut res = ExecuteInputResult::None; let mut res = ExecuteInputResult::None;
@ -378,7 +383,7 @@ where
let observers_buf = if manager.configuration() == EventConfig::AlwaysUnique { let observers_buf = if manager.configuration() == EventConfig::AlwaysUnique {
None None
} else { } else {
Some(manager.serialize_observers(observers)?) Some(manager.serialize_observers::<OT>(observers)?)
}; };
manager.fire( manager.fire(
state, state,
@ -419,28 +424,27 @@ where
} }
} }
impl<CS, F, I, OF, OT, S> EvaluatorObservers<I, OT, S> for StdFuzzer<CS, F, I, OF, OT, S> impl<CS, F, OF, OT> EvaluatorObservers<OT> for StdFuzzer<CS, F, OF, OT>
where where
CS: Scheduler<I, S>, CS: Scheduler,
OT: ObserversTuple<I, S> + serde::Serialize + serde::de::DeserializeOwned, OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned,
F: Feedback<I, S>, F: Feedback<CS::State>,
I: Input, OF: Feedback<CS::State>,
OF: Feedback<I, S>, CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions,
S: HasCorpus<I> + HasSolutions<I> + HasClientPerfMonitor + HasExecutions,
{ {
/// Process one input, adding to the respective corpuses if needed and firing the right events /// Process one input, adding to the respective corpora if needed and firing the right events
#[inline] #[inline]
fn evaluate_input_with_observers<E, EM>( fn evaluate_input_with_observers<E, EM>(
&mut self, &mut self,
state: &mut S, state: &mut Self::State,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: I, input: <Self::State as UsesInput>::Input,
send_events: bool, send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error> ) -> Result<(ExecuteInputResult, Option<usize>), Error>
where where
E: Executor<EM, I, S, Self> + HasObservers<I, OT, S>, E: Executor<EM, Self> + HasObservers<Observers = OT, State = Self::State>,
EM: EventManager<E, I, S, Self>, EM: EventFirer<State = Self::State>,
{ {
let exit_kind = self.execute_input(state, executor, manager, &input)?; let exit_kind = self.execute_input(state, executor, manager, &input)?;
let observers = executor.observers(); let observers = executor.observers();
@ -448,37 +452,36 @@ where
} }
} }
impl<CS, E, EM, F, I, OF, OT, S> Evaluator<E, EM, I, S> for StdFuzzer<CS, F, I, OF, OT, S> impl<CS, E, EM, F, OF, OT> Evaluator<E, EM> for StdFuzzer<CS, F, OF, OT>
where where
CS: Scheduler<I, S>, CS: Scheduler,
E: Executor<EM, I, S, Self> + HasObservers<I, OT, S>, E: HasObservers<State = CS::State, Observers = OT> + Executor<EM, Self>,
OT: ObserversTuple<I, S> + serde::Serialize + serde::de::DeserializeOwned, EM: EventFirer<State = CS::State>,
EM: EventManager<E, I, S, Self>, F: Feedback<CS::State>,
F: Feedback<I, S>, OF: Feedback<CS::State>,
I: Input, OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned,
OF: Feedback<I, S>, CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions,
S: HasCorpus<I> + HasSolutions<I> + HasClientPerfMonitor + HasExecutions,
{ {
/// Process one input, adding to the respective corpuses if needed and firing the right events /// Process one input, adding to the respective corpora if needed and firing the right events
#[inline] #[inline]
fn evaluate_input_events( fn evaluate_input_events(
&mut self, &mut self,
state: &mut S, state: &mut CS::State,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: I, input: <CS::State as UsesInput>::Input,
send_events: bool, send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error> { ) -> Result<(ExecuteInputResult, Option<usize>), Error> {
self.evaluate_input_with_observers(state, executor, manager, input, send_events) self.evaluate_input_with_observers(state, executor, manager, input, send_events)
} }
/// Adds an input, even if it's not conisered `interesting` by any of the executors /// Adds an input, even if it's not considered `interesting` by any of the executors
fn add_input( fn add_input(
&mut self, &mut self,
state: &mut S, state: &mut CS::State,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: I, input: <CS::State as UsesInput>::Input,
) -> Result<usize, Error> { ) -> Result<usize, Error> {
let exit_kind = self.execute_input(state, executor, manager, &input)?; let exit_kind = self.execute_input(state, executor, manager, &input)?;
let observers = executor.observers(); let observers = executor.observers();
@ -496,7 +499,7 @@ where
let observers_buf = if manager.configuration() == EventConfig::AlwaysUnique { let observers_buf = if manager.configuration() == EventConfig::AlwaysUnique {
None None
} else { } else {
Some(manager.serialize_observers(observers)?) Some(manager.serialize_observers::<OT>(observers)?)
}; };
manager.fire( manager.fire(
state, state,
@ -514,21 +517,21 @@ where
} }
} }
impl<CS, E, EM, F, I, OF, OT, S, ST> Fuzzer<E, EM, I, S, ST> for StdFuzzer<CS, F, I, OF, OT, S> impl<CS, E, EM, F, OF, OT, ST> Fuzzer<E, EM, ST> for StdFuzzer<CS, F, OF, OT>
where where
CS: Scheduler<I, S>, CS: Scheduler,
EM: EventManager<E, I, S, Self>, E: UsesState<State = CS::State>,
F: Feedback<I, S>, EM: ProgressReporter + EventProcessor<E, Self, State = CS::State>,
I: Input, F: Feedback<CS::State>,
S: HasClientPerfMonitor + HasExecutions + HasMetadata, OF: Feedback<CS::State>,
OF: Feedback<I, S>, CS::State: HasClientPerfMonitor + HasExecutions + HasMetadata,
ST: StagesTuple<E, EM, S, Self> + ?Sized, ST: StagesTuple<E, EM, CS::State, Self>,
{ {
fn fuzz_one( fn fuzz_one(
&mut self, &mut self,
stages: &mut ST, stages: &mut ST,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut CS::State,
manager: &mut EM, manager: &mut EM,
) -> Result<usize, Error> { ) -> Result<usize, Error> {
// Init timer for scheduler // Init timer for scheduler
@ -564,13 +567,12 @@ where
} }
} }
impl<CS, F, I, OF, OT, S> StdFuzzer<CS, F, I, OF, OT, S> impl<CS, F, OF, OT> StdFuzzer<CS, F, OF, OT>
where where
CS: Scheduler<I, S>, CS: Scheduler,
F: Feedback<I, S>, F: Feedback<CS::State>,
I: Input, OF: Feedback<CS::State>,
OF: Feedback<I, S>, CS::State: UsesInput + HasExecutions + HasClientPerfMonitor,
S: HasExecutions + HasClientPerfMonitor,
{ {
/// Create a new `StdFuzzer` with standard behavior. /// Create a new `StdFuzzer` with standard behavior.
pub fn new(scheduler: CS, feedback: F, objective: OF) -> Self { pub fn new(scheduler: CS, feedback: F, objective: OF) -> Self {
@ -585,14 +587,15 @@ where
/// Runs the input and triggers observers and feedback /// Runs the input and triggers observers and feedback
pub fn execute_input<E, EM>( pub fn execute_input<E, EM>(
&mut self, &mut self,
state: &mut S, state: &mut CS::State,
executor: &mut E, executor: &mut E,
event_mgr: &mut EM, event_mgr: &mut EM,
input: &I, input: &<CS::State as UsesInput>::Input,
) -> Result<ExitKind, Error> ) -> Result<ExitKind, Error>
where where
E: Executor<EM, I, S, Self> + HasObservers<I, OT, S>, E: Executor<EM, Self> + HasObservers<Observers = OT, State = CS::State>,
OT: ObserversTuple<I, S>, EM: UsesState<State = CS::State>,
OT: ObserversTuple<CS::State>,
{ {
start_timer!(state); start_timer!(state);
executor.observers_mut().pre_exec_all(state, input)?; executor.observers_mut().pre_exec_all(state, input)?;
@ -614,46 +617,39 @@ where
} }
} }
/// Structs with this trait will execute an [`Input`] /// Structs with this trait will execute an input
pub trait ExecutesInput<I, OT, S, Z> pub trait ExecutesInput<E, EM>: UsesState
where where
I: Input, E: UsesState<State = Self::State>,
OT: ObserversTuple<I, S>, EM: UsesState<State = Self::State>,
{ {
/// Runs the input and triggers observers and feedback /// Runs the input and triggers observers and feedback
fn execute_input<E, EM>( fn execute_input(
&mut self, &mut self,
state: &mut S, state: &mut Self::State,
executor: &mut E, executor: &mut E,
event_mgr: &mut EM, event_mgr: &mut EM,
input: &I, input: &<Self::State as UsesInput>::Input,
) -> Result<ExitKind, Error> ) -> Result<ExitKind, Error>;
where
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
OT: ObserversTuple<I, S>;
} }
impl<CS, F, I, OF, OT, S> ExecutesInput<I, OT, S, Self> for StdFuzzer<CS, F, I, OF, OT, S> impl<CS, E, EM, F, OF> ExecutesInput<E, EM> for StdFuzzer<CS, F, OF, E::Observers>
where where
CS: Scheduler<I, S>, CS: Scheduler,
F: Feedback<I, S>, F: Feedback<CS::State>,
I: Input, OF: Feedback<CS::State>,
OT: ObserversTuple<I, S>, E: Executor<EM, Self> + HasObservers<State = CS::State>,
OF: Feedback<I, S>, EM: UsesState<State = CS::State>,
S: HasExecutions + HasClientPerfMonitor, CS::State: UsesInput + HasExecutions + HasClientPerfMonitor,
{ {
/// Runs the input and triggers observers and feedback /// Runs the input and triggers observers and feedback
fn execute_input<E, EM>( fn execute_input(
&mut self, &mut self,
state: &mut S, state: &mut CS::State,
executor: &mut E, executor: &mut E,
event_mgr: &mut EM, event_mgr: &mut EM,
input: &I, input: &<CS::State as UsesInput>::Input,
) -> Result<ExitKind, Error> ) -> Result<ExitKind, Error> {
where
E: Executor<EM, I, S, Self> + HasObservers<I, OT, S>,
OT: ObserversTuple<I, S>,
{
start_timer!(state); start_timer!(state);
executor.observers_mut().pre_exec_all(state, input)?; executor.observers_mut().pre_exec_all(state, input)?;
mark_feature_time!(state, PerfFeature::PreExecObservers); mark_feature_time!(state, PerfFeature::PreExecObservers);
@ -674,6 +670,48 @@ where
} }
} }
#[cfg(test)]
#[derive(Clone, Debug, Default)]
pub(crate) struct NopFuzzer<I> {
phantom: PhantomData<I>,
}
#[cfg(test)]
impl<I> NopFuzzer<I> {
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
#[cfg(test)]
impl<I> UsesState for NopFuzzer<I>
where
I: Input,
{
type State = NopState<I>;
}
#[cfg(test)]
impl<ST, E, I, EM> Fuzzer<E, EM, ST> for NopFuzzer<I>
where
E: UsesState<State = NopState<I>>,
EM: ProgressReporter<State = NopState<I>>,
I: Input,
ST: StagesTuple<E, EM, NopState<I>, Self>,
{
fn fuzz_one(
&mut self,
_stages: &mut ST,
_executor: &mut E,
_state: &mut EM::State,
_manager: &mut EM,
) -> Result<usize, Error> {
unimplemented!()
}
}
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)] #[allow(missing_docs)]
/// `Fuzzer` Python bindings /// `Fuzzer` Python bindings
@ -697,12 +735,10 @@ pub mod pybind {
/// `StdFuzzer` with fixed generics /// `StdFuzzer` with fixed generics
pub type PythonStdFuzzer = StdFuzzer< pub type PythonStdFuzzer = StdFuzzer<
QueueScheduler, QueueScheduler<PythonStdState>,
PythonFeedback, PythonFeedback,
BytesInput,
PythonFeedback, PythonFeedback,
PythonObserversTuple, PythonObserversTuple,
PythonStdState,
>; >;
/// Python class for StdFuzzer /// Python class for StdFuzzer

View File

@ -109,3 +109,10 @@ pub trait HasBytesVec {
/// The internal bytes map (as mutable borrow) /// The internal bytes map (as mutable borrow)
fn bytes_mut(&mut self) -> &mut Vec<u8>; fn bytes_mut(&mut self) -> &mut Vec<u8>;
} }
/// Defines the input type shared across traits of the type.
/// Needed for consistency across HasCorpus/HasSolutions and friends.
pub trait UsesInput {
/// Type which will be used throughout this state.
type Input: Input;
}

View File

@ -453,19 +453,21 @@ pub mod prelude {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[cfg(feature = "std")]
use crate::events::SimpleEventManager;
use crate::{ use crate::{
bolts::{rands::StdRand, tuples::tuple_list}, bolts::{rands::StdRand, tuples::tuple_list},
corpus::{Corpus, InMemoryCorpus, Testcase}, corpus::{Corpus, InMemoryCorpus, Testcase},
events::NopEventManager,
executors::{ExitKind, InProcessExecutor}, executors::{ExitKind, InProcessExecutor},
feedbacks::ConstFeedback,
fuzzer::Fuzzer,
inputs::BytesInput, inputs::BytesInput,
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{mutations::BitFlipMutator, StdScheduledMutator}, mutators::{mutations::BitFlipMutator, StdScheduledMutator},
schedulers::RandScheduler, schedulers::RandScheduler,
stages::StdMutationalStage, stages::StdMutationalStage,
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
Fuzzer, StdFuzzer, StdFuzzer,
}; };
#[test] #[test]
@ -474,25 +476,31 @@ mod tests {
let rand = StdRand::with_seed(0); let rand = StdRand::with_seed(0);
let mut corpus = InMemoryCorpus::<BytesInput>::new(); let mut corpus = InMemoryCorpus::<BytesInput>::new();
let testcase = Testcase::new(vec![0; 4]); let testcase = Testcase::new(vec![0; 4].into());
corpus.add(testcase).unwrap(); corpus.add(testcase).unwrap();
let mut feedback = ConstFeedback::new(false);
let mut objective = ConstFeedback::new(false);
let mut state = StdState::new( let mut state = StdState::new(
rand, rand,
corpus, corpus,
InMemoryCorpus::<BytesInput>::new(), InMemoryCorpus::<BytesInput>::new(),
&mut (), &mut feedback,
&mut (), &mut objective,
) )
.unwrap(); .unwrap();
let monitor = SimpleMonitor::new(|s| { let _monitor = SimpleMonitor::new(|s| {
println!("{s}"); println!("{s}");
}); });
let mut event_manager = SimpleEventManager::new(monitor); let mut event_manager = NopEventManager::new();
let feedback = ConstFeedback::new(false);
let objective = ConstFeedback::new(false);
let scheduler = RandScheduler::new(); let scheduler = RandScheduler::new();
let mut fuzzer = StdFuzzer::new(scheduler, (), ()); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
let mut harness = |_buf: &BytesInput| ExitKind::Ok; let mut harness = |_buf: &BytesInput| ExitKind::Ok;
let mut executor = InProcessExecutor::new( let mut executor = InProcessExecutor::new(
@ -515,8 +523,8 @@ mod tests {
let state_serialized = postcard::to_allocvec(&state).unwrap(); let state_serialized = postcard::to_allocvec(&state).unwrap();
let state_deserialized: StdState< let state_deserialized: StdState<
_,
InMemoryCorpus<BytesInput>, InMemoryCorpus<BytesInput>,
BytesInput,
StdRand, StdRand,
InMemoryCorpus<BytesInput>, InMemoryCorpus<BytesInput>,
> = postcard::from_bytes(state_serialized.as_slice()).unwrap(); > = postcard::from_bytes(state_serialized.as_slice()).unwrap();

View File

@ -277,6 +277,67 @@ impl Default for NopMonitor {
} }
} }
#[cfg(feature = "std")]
/// Tracking monitor during fuzzing that just prints to `stdout`.
#[derive(Debug, Clone, Default)]
pub struct SimplePrintingMonitor {
start_time: Duration,
client_stats: Vec<ClientStats>,
}
#[cfg(feature = "std")]
impl SimplePrintingMonitor {
/// Create a new [`SimplePrintingMonitor`]
#[must_use]
pub fn new() -> Self {
Self::default()
}
}
#[cfg(feature = "std")]
impl Monitor for SimplePrintingMonitor {
/// the client monitor, mutable
fn client_stats_mut(&mut self) -> &mut Vec<ClientStats> {
&mut self.client_stats
}
/// the client monitor
fn client_stats(&self) -> &[ClientStats] {
&self.client_stats
}
/// Time this fuzzing run stated
fn start_time(&mut self) -> Duration {
self.start_time
}
fn display(&mut self, event_msg: String, sender_id: u32) {
println!(
"[{} #{}] run time: {}, clients: {}, corpus: {}, objectives: {}, executions: {}, exec/sec: {}",
event_msg,
sender_id,
format_duration_hms(&(current_time() - self.start_time)),
self.client_stats().len(),
self.corpus_size(),
self.objective_size(),
self.total_execs(),
self.execs_per_sec()
);
// Only print perf monitor if the feature is enabled
#[cfg(feature = "introspection")]
{
// Print the client performance monitor.
println!(
"Client {:03}:\n{}",
sender_id, self.client_stats[sender_id as usize].introspection_monitor
);
// Separate the spacing just a bit
println!();
}
}
}
/// Tracking monitor during fuzzing. /// Tracking monitor during fuzzing.
#[derive(Clone)] #[derive(Clone)]
pub struct SimpleMonitor<F> pub struct SimpleMonitor<F>

View File

@ -9,7 +9,7 @@ use crate::{
tuples::{tuple_list, tuple_list_type}, tuples::{tuple_list, tuple_list_type},
}, },
corpus::Corpus, corpus::Corpus,
inputs::EncodedInput, inputs::{EncodedInput, UsesInput},
mutators::{ mutators::{
mutations::{buffer_copy, buffer_self_copy, ARITH_MAX}, mutations::{buffer_copy, buffer_self_copy, ARITH_MAX},
MutationResult, Mutator, Named, MutationResult, Mutator, Named,
@ -22,7 +22,7 @@ use crate::{
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedRandMutator; pub struct EncodedRandMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedRandMutator { impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedRandMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -57,7 +57,7 @@ impl EncodedRandMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedIncMutator; pub struct EncodedIncMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedIncMutator { impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedIncMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -92,7 +92,7 @@ impl EncodedIncMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedDecMutator; pub struct EncodedDecMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedDecMutator { impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedDecMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -127,7 +127,7 @@ impl EncodedDecMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedAddMutator; pub struct EncodedAddMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedAddMutator { impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedAddMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -166,7 +166,7 @@ impl EncodedAddMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedDeleteMutator; pub struct EncodedDeleteMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedDeleteMutator { impl<S: HasRand + UsesInput<Input = EncodedInput>> Mutator<S> for EncodedDeleteMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -206,9 +206,9 @@ pub struct EncodedInsertCopyMutator {
tmp_buf: Vec<u32>, tmp_buf: Vec<u32>,
} }
impl<S> Mutator<EncodedInput, S> for EncodedInsertCopyMutator impl<S> Mutator<S> for EncodedInsertCopyMutator
where where
S: HasRand + HasMaxSize, S: UsesInput<Input = EncodedInput> + HasRand + HasMaxSize,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -267,7 +267,7 @@ impl EncodedInsertCopyMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedCopyMutator; pub struct EncodedCopyMutator;
impl<S: HasRand> Mutator<EncodedInput, S> for EncodedCopyMutator { impl<S: UsesInput<Input = EncodedInput> + HasRand> Mutator<S> for EncodedCopyMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -307,9 +307,9 @@ impl EncodedCopyMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedCrossoverInsertMutator; pub struct EncodedCrossoverInsertMutator;
impl<S> Mutator<EncodedInput, S> for EncodedCrossoverInsertMutator impl<S> Mutator<S> for EncodedCrossoverInsertMutator
where where
S: HasRand + HasCorpus<EncodedInput> + HasMaxSize, S: UsesInput<Input = EncodedInput> + HasRand + HasCorpus + HasMaxSize,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -381,9 +381,9 @@ impl EncodedCrossoverInsertMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EncodedCrossoverReplaceMutator; pub struct EncodedCrossoverReplaceMutator;
impl<S> Mutator<EncodedInput, S> for EncodedCrossoverReplaceMutator impl<S> Mutator<S> for EncodedCrossoverReplaceMutator
where where
S: HasRand + HasCorpus<EncodedInput>, S: UsesInput<Input = EncodedInput> + HasRand + HasCorpus,
{ {
fn mutate( fn mutate(
&mut self, &mut self,

View File

@ -10,7 +10,7 @@ use crate::{
bolts::{rands::Rand, tuples::Named}, bolts::{rands::Rand, tuples::Named},
corpus::Corpus, corpus::Corpus,
generators::GramatronGenerator, generators::GramatronGenerator,
inputs::{GramatronInput, Terminal}, inputs::{GramatronInput, Terminal, UsesInput},
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
state::{HasCorpus, HasMetadata, HasRand}, state::{HasCorpus, HasMetadata, HasRand},
Error, Error,
@ -27,9 +27,9 @@ where
generator: &'a GramatronGenerator<'a, S>, generator: &'a GramatronGenerator<'a, S>,
} }
impl<'a, S> Mutator<GramatronInput, S> for GramatronRandomMutator<'a, S> impl<'a, S> Mutator<S> for GramatronRandomMutator<'a, S>
where where
S: HasRand + HasMetadata, S: UsesInput<Input = GramatronInput> + HasRand + HasMetadata,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -96,9 +96,9 @@ impl GramatronIdxMapMetadata {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct GramatronSpliceMutator; pub struct GramatronSpliceMutator;
impl<S> Mutator<GramatronInput, S> for GramatronSpliceMutator impl<S> Mutator<S> for GramatronSpliceMutator
where where
S: HasRand + HasCorpus<GramatronInput> + HasMetadata, S: UsesInput<Input = GramatronInput> + HasRand + HasCorpus + HasMetadata,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -169,9 +169,9 @@ pub struct GramatronRecursionMutator {
feature: Vec<Terminal>, feature: Vec<Terminal>,
} }
impl<S> Mutator<GramatronInput, S> for GramatronRecursionMutator impl<S> Mutator<S> for GramatronRecursionMutator
where where
S: HasRand + HasMetadata, S: UsesInput<Input = GramatronInput> + HasRand + HasMetadata,
{ {
fn mutate( fn mutate(
&mut self, &mut self,

View File

@ -7,7 +7,7 @@ use core::cmp::{max, min};
use crate::{ use crate::{
bolts::{rands::Rand, tuples::Named}, bolts::{rands::Rand, tuples::Named},
corpus::Corpus, corpus::Corpus,
inputs::{GeneralizedInput, GeneralizedItem}, inputs::{GeneralizedInput, GeneralizedItem, UsesInput},
mutators::{token_mutations::Tokens, MutationResult, Mutator}, mutators::{token_mutations::Tokens, MutationResult, Mutator},
stages::generalization::GeneralizedIndexesMetadata, stages::generalization::GeneralizedIndexesMetadata,
state::{HasCorpus, HasMetadata, HasRand}, state::{HasCorpus, HasMetadata, HasRand},
@ -24,7 +24,7 @@ fn extend_with_random_generalized<S>(
gap_indices: &mut Vec<usize>, gap_indices: &mut Vec<usize>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
S: HasMetadata + HasRand + HasCorpus<GeneralizedInput>, S: HasMetadata + HasRand + HasCorpus<Input = GeneralizedInput>,
{ {
let rand_idx = state.rand_mut().next() as usize; let rand_idx = state.rand_mut().next() as usize;
@ -128,9 +128,9 @@ pub struct GrimoireExtensionMutator {
gap_indices: Vec<usize>, gap_indices: Vec<usize>,
} }
impl<S> Mutator<GeneralizedInput, S> for GrimoireExtensionMutator impl<S> Mutator<S> for GrimoireExtensionMutator
where where
S: HasMetadata + HasRand + HasCorpus<GeneralizedInput>, S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand + HasCorpus,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -176,9 +176,9 @@ pub struct GrimoireRecursiveReplacementMutator {
gap_indices: Vec<usize>, gap_indices: Vec<usize>,
} }
impl<S> Mutator<GeneralizedInput, S> for GrimoireRecursiveReplacementMutator impl<S> Mutator<S> for GrimoireRecursiveReplacementMutator
where where
S: HasMetadata + HasRand + HasCorpus<GeneralizedInput>, S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand + HasCorpus,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -247,9 +247,9 @@ impl GrimoireRecursiveReplacementMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct GrimoireStringReplacementMutator {} pub struct GrimoireStringReplacementMutator {}
impl<S> Mutator<GeneralizedInput, S> for GrimoireStringReplacementMutator impl<S> Mutator<S> for GrimoireStringReplacementMutator
where where
S: HasMetadata + HasRand, S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -355,9 +355,9 @@ pub struct GrimoireRandomDeleteMutator {
gap_indices: Vec<usize>, gap_indices: Vec<usize>,
} }
impl<S> Mutator<GeneralizedInput, S> for GrimoireRandomDeleteMutator impl<S> Mutator<S> for GrimoireRandomDeleteMutator
where where
S: HasMetadata + HasRand + HasCorpus<GeneralizedInput>, S: UsesInput<Input = GeneralizedInput> + HasMetadata + HasRand + HasCorpus,
{ {
fn mutate( fn mutate(
&mut self, &mut self,

View File

@ -22,7 +22,7 @@ pub use nautilus::*;
use crate::{ use crate::{
bolts::tuples::{HasConstLen, Named}, bolts::tuples::{HasConstLen, Named},
inputs::Input, inputs::UsesInput,
Error, Error,
}; };
@ -42,15 +42,15 @@ pub enum MutationResult {
/// A mutator takes input, and mutates it. /// A mutator takes input, and mutates it.
/// Simple as that. /// Simple as that.
pub trait Mutator<I, S> pub trait Mutator<S>
where where
I: Input, S: UsesInput,
{ {
/// Mutate a given input /// Mutate a given input
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error>; ) -> Result<MutationResult, Error>;
@ -66,15 +66,15 @@ where
} }
/// A `Tuple` of `Mutators` that can execute multiple `Mutators` in a row. /// A `Tuple` of `Mutators` that can execute multiple `Mutators` in a row.
pub trait MutatorsTuple<I, S>: HasConstLen pub trait MutatorsTuple<S>: HasConstLen
where where
I: Input, S: UsesInput,
{ {
/// Runs the `mutate` function on all `Mutators` in this `Tuple`. /// Runs the `mutate` function on all `Mutators` in this `Tuple`.
fn mutate_all( fn mutate_all(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error>; ) -> Result<MutationResult, Error>;
@ -91,7 +91,7 @@ where
&mut self, &mut self,
index: usize, index: usize,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error>; ) -> Result<MutationResult, Error>;
@ -105,14 +105,14 @@ where
) -> Result<(), Error>; ) -> Result<(), Error>;
} }
impl<I, S> MutatorsTuple<I, S> for () impl<S> MutatorsTuple<S> for ()
where where
I: Input, S: UsesInput,
{ {
fn mutate_all( fn mutate_all(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_input: &mut I, _input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
@ -131,7 +131,7 @@ where
&mut self, &mut self,
_index: usize, _index: usize,
_state: &mut S, _state: &mut S,
_input: &mut I, _input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
Ok(MutationResult::Skipped) Ok(MutationResult::Skipped)
@ -148,16 +148,16 @@ where
} }
} }
impl<Head, Tail, I, S> MutatorsTuple<I, S> for (Head, Tail) impl<Head, Tail, S> MutatorsTuple<S> for (Head, Tail)
where where
Head: Mutator<I, S> + Named, Head: Mutator<S> + Named,
Tail: MutatorsTuple<I, S>, Tail: MutatorsTuple<S>,
I: Input, S: UsesInput,
{ {
fn mutate_all( fn mutate_all(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let r = self.0.mutate(state, input, stage_idx)?; let r = self.0.mutate(state, input, stage_idx)?;
@ -182,7 +182,7 @@ where
&mut self, &mut self,
index: usize, index: usize,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if index == 0 { if index == 0 {
@ -234,7 +234,7 @@ pub mod pybind {
} }
} }
impl Mutator<BytesInput, PythonStdState> for PyObjectMutator { impl Mutator<PythonStdState> for PyObjectMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut PythonStdState, state: &mut PythonStdState,
@ -329,7 +329,7 @@ pub mod pybind {
} }
} }
impl Mutator<BytesInput, PythonStdState> for PythonMutator { impl Mutator<PythonStdState> for PythonMutator {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut PythonStdState, state: &mut PythonStdState,

View File

@ -13,7 +13,6 @@ use crate::{
rands::{Rand, StdRand}, rands::{Rand, StdRand},
}, },
corpus::Corpus, corpus::Corpus,
inputs::Input,
mutators::{ComposedByMutations, MutationResult, Mutator, MutatorsTuple, ScheduledMutator}, mutators::{ComposedByMutations, MutationResult, Mutator, MutatorsTuple, ScheduledMutator},
state::{HasCorpus, HasMetadata, HasRand, HasSolutions}, state::{HasCorpus, HasMetadata, HasRand, HasSolutions},
Error, Error,
@ -363,46 +362,43 @@ pub enum MOptMode {
/// This is the main struct of `MOpt`, an `AFL` mutator. /// This is the main struct of `MOpt`, an `AFL` mutator.
/// See the original `MOpt` implementation in <https://github.com/puppet-meteor/MOpt-AFL> /// See the original `MOpt` implementation in <https://github.com/puppet-meteor/MOpt-AFL>
pub struct StdMOptMutator<I, MT, S> pub struct StdMOptMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ {
mode: MOptMode, mode: MOptMode,
finds_before: usize, finds_before: usize,
mutations: MT, mutations: MT,
max_stack_pow: u64, max_stack_pow: u64,
phantom: PhantomData<(I, S)>, phantom: PhantomData<S>,
} }
impl<I, MT, S> Debug for StdMOptMutator<I, MT, S> impl<MT, S> Debug for StdMOptMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"StdMOptMutator with {} mutations for Input type {}", "StdMOptMutator with {} mutations for Input type {}",
self.mutations.len(), self.mutations.len(),
core::any::type_name::<I>() core::any::type_name::<S::Input>()
) )
} }
} }
impl<I, MT, S> Mutator<I, S> for StdMOptMutator<I, MT, S> impl<MT, S> Mutator<S> for StdMOptMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ {
#[inline] #[inline]
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
self.finds_before = state.corpus().count() + state.solutions().count(); self.finds_before = state.corpus().count() + state.solutions().count();
@ -528,11 +524,10 @@ where
} }
} }
impl<I, MT, S> StdMOptMutator<I, MT, S> impl<MT, S> StdMOptMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ {
/// Create a new [`StdMOptMutator`]. /// Create a new [`StdMOptMutator`].
pub fn new( pub fn new(
@ -555,7 +550,7 @@ where
fn core_mutate( fn core_mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let mut r = MutationResult::Skipped; let mut r = MutationResult::Skipped;
@ -585,7 +580,7 @@ where
fn pilot_mutate( fn pilot_mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let mut r = MutationResult::Skipped; let mut r = MutationResult::Skipped;
@ -620,11 +615,10 @@ where
} }
} }
impl<I, MT, S> ComposedByMutations<I, MT, S> for StdMOptMutator<I, MT, S> impl<MT, S> ComposedByMutations<MT, S> for StdMOptMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ {
/// Get the mutations /// Get the mutations
#[inline] #[inline]
@ -639,19 +633,18 @@ where
} }
} }
impl<I, MT, S> ScheduledMutator<I, MT, S> for StdMOptMutator<I, MT, S> impl<MT, S> ScheduledMutator<MT, S> for StdMOptMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: HasRand + HasMetadata + HasCorpus + HasSolutions,
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ {
/// Compute the number of iterations used to apply stacked mutations /// Compute the number of iterations used to apply stacked mutations
fn iterations(&self, state: &mut S, _: &I) -> u64 { fn iterations(&self, state: &mut S, _: &S::Input) -> u64 {
1 << (1 + state.rand_mut().below(self.max_stack_pow)) 1 << (1 + state.rand_mut().below(self.max_stack_pow))
} }
/// Get the next mutation to apply /// Get the next mutation to apply
fn schedule(&self, state: &mut S, _: &I) -> usize { fn schedule(&self, state: &mut S, _: &S::Input) -> usize {
state state
.metadata_mut() .metadata_mut()
.get_mut::<MOpt>() .get_mut::<MOpt>()
@ -663,7 +656,7 @@ where
fn scheduled_mutate( fn scheduled_mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let mode = self.mode; let mode = self.mode;

View File

@ -9,7 +9,7 @@ use core::{
use crate::{ use crate::{
bolts::{rands::Rand, tuples::Named}, bolts::{rands::Rand, tuples::Named},
corpus::Corpus, corpus::Corpus,
inputs::{HasBytesVec, Input}, inputs::{HasBytesVec, UsesInput},
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
state::{HasCorpus, HasMaxSize, HasRand}, state::{HasCorpus, HasMaxSize, HasRand},
Error, Error,
@ -100,15 +100,15 @@ pub const INTERESTING_32: [i32; 27] = [
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BitFlipMutator; pub struct BitFlipMutator;
impl<I, S> Mutator<I, S> for BitFlipMutator impl<S> Mutator<S> for BitFlipMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut <S as UsesInput>::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -140,15 +140,15 @@ impl BitFlipMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ByteFlipMutator; pub struct ByteFlipMutator;
impl<I, S> Mutator<I, S> for ByteFlipMutator impl<S> Mutator<S> for ByteFlipMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -178,15 +178,15 @@ impl ByteFlipMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ByteIncMutator; pub struct ByteIncMutator;
impl<I, S> Mutator<I, S> for ByteIncMutator impl<S> Mutator<S> for ByteIncMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -217,15 +217,15 @@ impl ByteIncMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ByteDecMutator; pub struct ByteDecMutator;
impl<I, S> Mutator<I, S> for ByteDecMutator impl<S> Mutator<S> for ByteDecMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -256,15 +256,15 @@ impl ByteDecMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ByteNegMutator; pub struct ByteNegMutator;
impl<I, S> Mutator<I, S> for ByteNegMutator impl<S> Mutator<S> for ByteNegMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -295,15 +295,15 @@ impl ByteNegMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ByteRandMutator; pub struct ByteRandMutator;
impl<I, S> Mutator<I, S> for ByteRandMutator impl<S> Mutator<S> for ByteRandMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -339,15 +339,15 @@ macro_rules! add_mutator_impl {
pub struct $name; pub struct $name;
#[allow(trivial_numeric_casts)] #[allow(trivial_numeric_casts)]
impl<I, S> Mutator<I, S> for $name impl<S> Mutator<S> for $name
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().len() < size_of::<$size>() { if input.bytes().len() < size_of::<$size>() {
@ -405,16 +405,16 @@ macro_rules! interesting_mutator_impl {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct $name; pub struct $name;
impl<I, S> Mutator<I, S> for $name impl<S> Mutator<S> for $name
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
if input.bytes().len() < size_of::<$size>() { if input.bytes().len() < size_of::<$size>() {
@ -458,15 +458,15 @@ interesting_mutator_impl!(DwordInterestingMutator, u32, INTERESTING_32);
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesDeleteMutator; pub struct BytesDeleteMutator;
impl<I, S> Mutator<I, S> for BytesDeleteMutator impl<S> Mutator<S> for BytesDeleteMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -500,15 +500,15 @@ impl BytesDeleteMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesExpandMutator; pub struct BytesExpandMutator;
impl<I, S> Mutator<I, S> for BytesExpandMutator impl<S> Mutator<S> for BytesExpandMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand + HasMaxSize,
S: HasRand + HasMaxSize, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -549,15 +549,15 @@ impl BytesExpandMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesInsertMutator; pub struct BytesInsertMutator;
impl<I, S> Mutator<I, S> for BytesInsertMutator impl<S> Mutator<S> for BytesInsertMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand + HasMaxSize,
S: HasRand + HasMaxSize, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -604,15 +604,15 @@ impl BytesInsertMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesRandInsertMutator; pub struct BytesRandInsertMutator;
impl<I, S> Mutator<I, S> for BytesRandInsertMutator impl<S> Mutator<S> for BytesRandInsertMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand + HasMaxSize,
S: HasRand + HasMaxSize, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -656,15 +656,15 @@ impl BytesRandInsertMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesSetMutator; pub struct BytesSetMutator;
impl<I, S> Mutator<I, S> for BytesSetMutator impl<S> Mutator<S> for BytesSetMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -700,15 +700,15 @@ impl BytesSetMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesRandSetMutator; pub struct BytesRandSetMutator;
impl<I, S> Mutator<I, S> for BytesRandSetMutator impl<S> Mutator<S> for BytesRandSetMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -744,15 +744,15 @@ impl BytesRandSetMutator {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct BytesCopyMutator; pub struct BytesCopyMutator;
impl<I, S> Mutator<I, S> for BytesCopyMutator impl<S> Mutator<S> for BytesCopyMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -790,15 +790,15 @@ pub struct BytesInsertCopyMutator {
tmp_buf: Vec<u8>, tmp_buf: Vec<u8>,
} }
impl<I, S> Mutator<I, S> for BytesInsertCopyMutator impl<S> Mutator<S> for BytesInsertCopyMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand + HasMaxSize,
S: HasRand + HasMaxSize, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -852,15 +852,15 @@ impl BytesInsertCopyMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct BytesSwapMutator; pub struct BytesSwapMutator;
impl<I, S> Mutator<I, S> for BytesSwapMutator impl<S> Mutator<S> for BytesSwapMutator
where where
I: Input + HasBytesVec, S: UsesInput + HasRand,
S: HasRand, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -898,15 +898,15 @@ impl BytesSwapMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct CrossoverInsertMutator; pub struct CrossoverInsertMutator;
impl<I, S> Mutator<I, S> for CrossoverInsertMutator impl<S> Mutator<S> for CrossoverInsertMutator
where where
I: Input + HasBytesVec, S: HasCorpus + HasRand + HasMaxSize,
S: HasRand + HasCorpus<I> + HasMaxSize, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -973,15 +973,15 @@ impl CrossoverInsertMutator {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct CrossoverReplaceMutator; pub struct CrossoverReplaceMutator;
impl<I, S> Mutator<I, S> for CrossoverReplaceMutator impl<S> Mutator<S> for CrossoverReplaceMutator
where where
I: Input + HasBytesVec, S: HasCorpus + HasRand,
S: HasRand + HasCorpus<I>, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -1056,16 +1056,16 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct SpliceMutator; pub struct SpliceMutator;
impl<I, S> Mutator<I, S> for SpliceMutator impl<S> Mutator<S> for SpliceMutator
where where
I: Input + HasBytesVec, S: HasCorpus + HasRand,
S: HasRand + HasCorpus<I>, S::Input: HasBytesVec,
{ {
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
// We don't want to use the testcase we're already using for splicing // We don't want to use the testcase we're already using for splicing
@ -1173,15 +1173,16 @@ mod tests {
tuples::{tuple_list, HasConstLen}, tuples::{tuple_list, HasConstLen},
}, },
corpus::{Corpus, InMemoryCorpus}, corpus::{Corpus, InMemoryCorpus},
feedbacks::ConstFeedback,
inputs::BytesInput, inputs::BytesInput,
mutators::MutatorsTuple, mutators::MutatorsTuple,
state::{HasMetadata, StdState}, state::{HasMetadata, StdState},
}; };
fn test_mutations<I, S>() -> impl MutatorsTuple<I, S> fn test_mutations<S>() -> impl MutatorsTuple<S>
where where
I: Input + HasBytesVec, S: HasRand + HasCorpus + HasMetadata + HasMaxSize,
S: HasRand + HasCorpus<I> + HasMetadata + HasMaxSize, S::Input: HasBytesVec,
{ {
tuple_list!( tuple_list!(
BitFlipMutator::new(), BitFlipMutator::new(),
@ -1226,12 +1227,21 @@ mod tests {
let rand = StdRand::with_seed(1337); let rand = StdRand::with_seed(1337);
let mut corpus = InMemoryCorpus::new(); let mut corpus = InMemoryCorpus::new();
let mut feedback = ConstFeedback::new(false);
let mut objective = ConstFeedback::new(false);
corpus corpus
.add(BytesInput::new(vec![0x42; 0x1337]).into()) .add(BytesInput::new(vec![0x42; 0x1337]).into())
.unwrap(); .unwrap();
let mut state = let mut state = StdState::new(
StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); rand,
corpus,
InMemoryCorpus::new(),
&mut feedback,
&mut objective,
)
.unwrap();
let mut mutations = test_mutations(); let mut mutations = test_mutations();
for _ in 0..2 { for _ in 0..2 {

View File

@ -14,6 +14,7 @@ use crate::{
generators::nautilus::NautilusContext, generators::nautilus::NautilusContext,
inputs::nautilus::NautilusInput, inputs::nautilus::NautilusInput,
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
prelude::UsesInput,
state::{HasCorpus, HasMetadata}, state::{HasCorpus, HasMetadata},
Error, Error,
}; };
@ -30,7 +31,10 @@ impl Debug for NautilusRandomMutator<'_> {
} }
} }
impl<S> Mutator<NautilusInput, S> for NautilusRandomMutator<'_> { impl<S> Mutator<S> for NautilusRandomMutator<'_>
where
S: UsesInput<Input = NautilusInput>,
{
fn mutate( fn mutate(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
@ -91,7 +95,10 @@ impl Debug for NautilusRecursionMutator<'_> {
} }
} }
impl<S> Mutator<NautilusInput, S> for NautilusRecursionMutator<'_> { impl<S> Mutator<S> for NautilusRecursionMutator<'_>
where
S: UsesInput<Input = NautilusInput>,
{
fn mutate( fn mutate(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
@ -154,9 +161,9 @@ impl Debug for NautilusSpliceMutator<'_> {
} }
} }
impl<S> Mutator<NautilusInput, S> for NautilusSpliceMutator<'_> impl<S> Mutator<S> for NautilusSpliceMutator<'_>
where where
S: HasCorpus<NautilusInput> + HasMetadata, S: HasCorpus + HasMetadata + UsesInput<Input = NautilusInput>,
{ {
fn mutate( fn mutate(
&mut self, &mut self,

View File

@ -16,9 +16,9 @@ use crate::{
AsMutSlice, AsSlice, AsMutSlice, AsSlice,
}, },
corpus::Corpus, corpus::Corpus,
inputs::Input, inputs::UsesInput,
mutators::{MutationResult, Mutator, MutatorsTuple}, mutators::{MutationResult, Mutator, MutatorsTuple},
state::{HasCorpus, HasMetadata, HasRand}, state::{HasCorpus, HasMetadata, HasRand, State},
Error, Error,
}; };
@ -53,10 +53,10 @@ impl LogMutationMetadata {
} }
/// A [`Mutator`] that composes multiple mutations into one. /// A [`Mutator`] that composes multiple mutations into one.
pub trait ComposedByMutations<I, MT, S> pub trait ComposedByMutations<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: UsesInput,
{ {
/// Get the mutations /// Get the mutations
fn mutations(&self) -> &MT; fn mutations(&self) -> &MT;
@ -66,23 +66,23 @@ where
} }
/// A [`Mutator`] scheduling multiple [`Mutator`]s for an input. /// A [`Mutator`] scheduling multiple [`Mutator`]s for an input.
pub trait ScheduledMutator<I, MT, S>: ComposedByMutations<I, MT, S> + Mutator<I, S> pub trait ScheduledMutator<MT, S>: ComposedByMutations<MT, S> + Mutator<S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: UsesInput,
{ {
/// Compute the number of iterations used to apply stacked mutations /// Compute the number of iterations used to apply stacked mutations
fn iterations(&self, state: &mut S, input: &I) -> u64; fn iterations(&self, state: &mut S, input: &S::Input) -> u64;
/// Get the next mutation to apply /// Get the next mutation to apply
fn schedule(&self, state: &mut S, input: &I) -> usize; fn schedule(&self, state: &mut S, input: &S::Input) -> usize;
/// New default implementation for mutate. /// New default implementation for mutate.
/// Implementations must forward mutate() to this method /// Implementations must forward mutate() to this method
fn scheduled_mutate( fn scheduled_mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let mut r = MutationResult::Skipped; let mut r = MutationResult::Skipped;
@ -101,55 +101,51 @@ where
} }
/// A [`Mutator`] that schedules one of the embedded mutations on each call. /// A [`Mutator`] that schedules one of the embedded mutations on each call.
pub struct StdScheduledMutator<I, MT, S> pub struct StdScheduledMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: State + HasRand,
S: HasRand,
{ {
mutations: MT, mutations: MT,
max_stack_pow: u64, max_stack_pow: u64,
phantom: PhantomData<(I, S)>, phantom: PhantomData<S>,
} }
impl<I, MT, S> Debug for StdScheduledMutator<I, MT, S> impl<MT, S> Debug for StdScheduledMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: State + HasRand,
S: HasRand,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"StdScheduledMutator with {} mutations for Input type {}", "StdScheduledMutator with {} mutations for Input type {}",
self.mutations.len(), self.mutations.len(),
core::any::type_name::<I>() core::any::type_name::<S::Input>()
) )
} }
} }
impl<I, MT, S> Mutator<I, S> for StdScheduledMutator<I, MT, S> impl<MT, S> Mutator<S> for StdScheduledMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: State + HasRand,
S: HasRand,
{ {
#[inline] #[inline]
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
self.scheduled_mutate(state, input, stage_idx) self.scheduled_mutate(state, input, stage_idx)
} }
} }
impl<I, MT, S> ComposedByMutations<I, MT, S> for StdScheduledMutator<I, MT, S> impl<MT, S> ComposedByMutations<MT, S> for StdScheduledMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: State + HasRand,
S: HasRand,
{ {
/// Get the mutations /// Get the mutations
#[inline] #[inline]
@ -164,29 +160,27 @@ where
} }
} }
impl<I, MT, S> ScheduledMutator<I, MT, S> for StdScheduledMutator<I, MT, S> impl<MT, S> ScheduledMutator<MT, S> for StdScheduledMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: State + HasRand,
S: HasRand,
{ {
/// Compute the number of iterations used to apply stacked mutations /// Compute the number of iterations used to apply stacked mutations
fn iterations(&self, state: &mut S, _: &I) -> u64 { fn iterations(&self, state: &mut S, _: &S::Input) -> u64 {
1 << (1 + state.rand_mut().below(self.max_stack_pow)) 1 << (1 + state.rand_mut().below(self.max_stack_pow))
} }
/// Get the next mutation to apply /// Get the next mutation to apply
fn schedule(&self, state: &mut S, _: &I) -> usize { fn schedule(&self, state: &mut S, _: &S::Input) -> usize {
debug_assert!(!self.mutations().is_empty()); debug_assert!(!self.mutations().is_empty());
state.rand_mut().below(self.mutations().len() as u64) as usize state.rand_mut().below(self.mutations().len() as u64) as usize
} }
} }
impl<I, MT, S> StdScheduledMutator<I, MT, S> impl<MT, S> StdScheduledMutator<MT, S>
where where
I: Input, MT: MutatorsTuple<S>,
MT: MutatorsTuple<I, S>, S: State + HasRand,
S: HasRand,
{ {
/// Create a new [`StdScheduledMutator`] instance specifying mutations /// Create a new [`StdScheduledMutator`] instance specifying mutations
pub fn new(mutations: MT) -> Self { pub fn new(mutations: MT) -> Self {
@ -279,46 +273,43 @@ pub fn tokens_mutations() -> tuple_list_type!(TokenInsert, TokenReplace) {
} }
/// A logging [`Mutator`] that wraps around a [`StdScheduledMutator`]. /// A logging [`Mutator`] that wraps around a [`StdScheduledMutator`].
pub struct LoggerScheduledMutator<I, MT, S, SM> pub struct LoggerScheduledMutator<MT, S, SM>
where where
I: Input, MT: MutatorsTuple<S> + NamedTuple,
MT: MutatorsTuple<I, S> + NamedTuple, S: UsesInput + HasRand + HasCorpus,
S: HasRand + HasCorpus<I>, SM: ScheduledMutator<MT, S>,
SM: ScheduledMutator<I, MT, S>,
{ {
scheduled: SM, scheduled: SM,
mutation_log: Vec<usize>, mutation_log: Vec<usize>,
phantom: PhantomData<(I, MT, S)>, phantom: PhantomData<(MT, S)>,
} }
impl<I, MT, S, SM> Debug for LoggerScheduledMutator<I, MT, S, SM> impl<MT, S, SM> Debug for LoggerScheduledMutator<MT, S, SM>
where where
I: Input, MT: MutatorsTuple<S> + NamedTuple,
MT: MutatorsTuple<I, S> + NamedTuple, S: UsesInput + HasRand + HasCorpus,
S: HasRand + HasCorpus<I>, SM: ScheduledMutator<MT, S>,
SM: ScheduledMutator<I, MT, S>,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"LoggerScheduledMutator with {} mutations for Input type {}", "LoggerScheduledMutator with {} mutations for Input type {}",
self.scheduled.mutations().len(), self.scheduled.mutations().len(),
core::any::type_name::<I>() core::any::type_name::<<S as UsesInput>::Input>()
) )
} }
} }
impl<I, MT, S, SM> Mutator<I, S> for LoggerScheduledMutator<I, MT, S, SM> impl<MT, S, SM> Mutator<S> for LoggerScheduledMutator<MT, S, SM>
where where
I: Input, MT: MutatorsTuple<S> + NamedTuple,
MT: MutatorsTuple<I, S> + NamedTuple, S: State + HasRand + HasCorpus,
S: HasRand + HasCorpus<I>, SM: ScheduledMutator<MT, S>,
SM: ScheduledMutator<I, MT, S>,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut <S as UsesInput>::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
self.scheduled_mutate(state, input, stage_idx) self.scheduled_mutate(state, input, stage_idx)
@ -346,12 +337,11 @@ where
} }
} }
impl<I, MT, S, SM> ComposedByMutations<I, MT, S> for LoggerScheduledMutator<I, MT, S, SM> impl<MT, S, SM> ComposedByMutations<MT, S> for LoggerScheduledMutator<MT, S, SM>
where where
I: Input, MT: MutatorsTuple<S> + NamedTuple,
MT: MutatorsTuple<I, S> + NamedTuple, S: State + HasRand + HasCorpus,
S: HasRand + HasCorpus<I>, SM: ScheduledMutator<MT, S>,
SM: ScheduledMutator<I, MT, S>,
{ {
#[inline] #[inline]
fn mutations(&self) -> &MT { fn mutations(&self) -> &MT {
@ -364,20 +354,19 @@ where
} }
} }
impl<I, MT, S, SM> ScheduledMutator<I, MT, S> for LoggerScheduledMutator<I, MT, S, SM> impl<MT, S, SM> ScheduledMutator<MT, S> for LoggerScheduledMutator<MT, S, SM>
where where
I: Input, MT: MutatorsTuple<S> + NamedTuple,
MT: MutatorsTuple<I, S> + NamedTuple, S: State + HasRand + HasCorpus,
S: HasRand + HasCorpus<I>, SM: ScheduledMutator<MT, S>,
SM: ScheduledMutator<I, MT, S>,
{ {
/// Compute the number of iterations used to apply stacked mutations /// Compute the number of iterations used to apply stacked mutations
fn iterations(&self, state: &mut S, _: &I) -> u64 { fn iterations(&self, state: &mut S, _: &<S as UsesInput>::Input) -> u64 {
1 << (1 + state.rand_mut().below(6)) 1 << (1 + state.rand_mut().below(6))
} }
/// Get the next mutation to apply /// Get the next mutation to apply
fn schedule(&self, state: &mut S, _: &I) -> usize { fn schedule(&self, state: &mut S, _: &<S as UsesInput>::Input) -> usize {
debug_assert!(!self.scheduled.mutations().is_empty()); debug_assert!(!self.scheduled.mutations().is_empty());
state state
.rand_mut() .rand_mut()
@ -387,7 +376,7 @@ where
fn scheduled_mutate( fn scheduled_mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut <S as UsesInput>::Input,
stage_idx: i32, stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let mut r = MutationResult::Skipped; let mut r = MutationResult::Skipped;
@ -407,12 +396,11 @@ where
} }
} }
impl<I, MT, S, SM> LoggerScheduledMutator<I, MT, S, SM> impl<MT, S, SM> LoggerScheduledMutator<MT, S, SM>
where where
I: Input, MT: MutatorsTuple<S> + NamedTuple,
MT: MutatorsTuple<I, S> + NamedTuple, S: State + HasRand + HasCorpus,
S: HasRand + HasCorpus<I>, SM: ScheduledMutator<MT, S>,
SM: ScheduledMutator<I, MT, S>,
{ {
/// Create a new [`StdScheduledMutator`] instance without mutations and corpus /// Create a new [`StdScheduledMutator`] instance without mutations and corpus
pub fn new(scheduled: SM) -> Self { pub fn new(scheduled: SM) -> Self {
@ -429,6 +417,7 @@ mod tests {
use crate::{ use crate::{
bolts::rands::{Rand, StdRand, XkcdRand}, bolts::rands::{Rand, StdRand, XkcdRand},
corpus::{Corpus, InMemoryCorpus, Testcase}, corpus::{Corpus, InMemoryCorpus, Testcase},
feedbacks::ConstFeedback,
inputs::{BytesInput, HasBytesVec}, inputs::{BytesInput, HasBytesVec},
mutators::{ mutators::{
mutations::SpliceMutator, mutations::SpliceMutator,
@ -443,14 +432,27 @@ mod tests {
// With the current impl, seed of 1 will result in a split at pos 2. // With the current impl, seed of 1 will result in a split at pos 2.
let mut rand = XkcdRand::with_seed(5); let mut rand = XkcdRand::with_seed(5);
let mut corpus: InMemoryCorpus<BytesInput> = InMemoryCorpus::new(); let mut corpus: InMemoryCorpus<BytesInput> = InMemoryCorpus::new();
corpus.add(Testcase::new(vec![b'a', b'b', b'c'])).unwrap(); corpus
corpus.add(Testcase::new(vec![b'd', b'e', b'f'])).unwrap(); .add(Testcase::new(vec![b'a', b'b', b'c'].into()))
.unwrap();
corpus
.add(Testcase::new(vec![b'd', b'e', b'f'].into()))
.unwrap();
let testcase = corpus.get(0).expect("Corpus did not contain entries"); let testcase = corpus.get(0).expect("Corpus did not contain entries");
let mut input = testcase.borrow_mut().load_input().unwrap().clone(); let mut input = testcase.borrow_mut().load_input().unwrap().clone();
let mut state = let mut feedback = ConstFeedback::new(false);
StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); let mut objective = ConstFeedback::new(false);
let mut state = StdState::new(
rand,
corpus,
InMemoryCorpus::new(),
&mut feedback,
&mut objective,
)
.unwrap();
rand.set_seed(5); rand.set_seed(5);
@ -470,15 +472,28 @@ mod tests {
// With the current impl, seed of 1 will result in a split at pos 2. // With the current impl, seed of 1 will result in a split at pos 2.
let rand = StdRand::with_seed(0x1337); let rand = StdRand::with_seed(0x1337);
let mut corpus: InMemoryCorpus<BytesInput> = InMemoryCorpus::new(); let mut corpus: InMemoryCorpus<BytesInput> = InMemoryCorpus::new();
corpus.add(Testcase::new(vec![b'a', b'b', b'c'])).unwrap(); corpus
corpus.add(Testcase::new(vec![b'd', b'e', b'f'])).unwrap(); .add(Testcase::new(vec![b'a', b'b', b'c'].into()))
.unwrap();
corpus
.add(Testcase::new(vec![b'd', b'e', b'f'].into()))
.unwrap();
let testcase = corpus.get(0).expect("Corpus did not contain entries"); let testcase = corpus.get(0).expect("Corpus did not contain entries");
let mut input = testcase.borrow_mut().load_input().unwrap().clone(); let mut input = testcase.borrow_mut().load_input().unwrap().clone();
let input_prior = input.clone(); let input_prior = input.clone();
let mut state = let mut feedback = ConstFeedback::new(false);
StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); let mut objective = ConstFeedback::new(false);
let mut state = StdState::new(
rand,
corpus,
InMemoryCorpus::new(),
&mut feedback,
&mut objective,
)
.unwrap();
let mut havoc = StdScheduledMutator::new(havoc_mutations()); let mut havoc = StdScheduledMutator::new(havoc_mutations());
@ -507,16 +522,14 @@ pub mod pybind {
use pyo3::prelude::*; use pyo3::prelude::*;
use super::{havoc_mutations, Debug, HavocMutationsType, StdScheduledMutator}; use super::{havoc_mutations, Debug, HavocMutationsType, StdScheduledMutator};
use crate::{ use crate::{mutators::pybind::PythonMutator, state::pybind::PythonStdState};
inputs::BytesInput, mutators::pybind::PythonMutator, state::pybind::PythonStdState,
};
#[pyclass(unsendable, name = "StdHavocMutator")] #[pyclass(unsendable, name = "StdHavocMutator")]
#[derive(Debug)] #[derive(Debug)]
/// Python class for StdHavocMutator /// Python class for StdHavocMutator
pub struct PythonStdHavocMutator { pub struct PythonStdHavocMutator {
/// Rust wrapped StdHavocMutator object /// Rust wrapped StdHavocMutator object
pub inner: StdScheduledMutator<BytesInput, HavocMutationsType, PythonStdState>, pub inner: StdScheduledMutator<HavocMutationsType, PythonStdState>,
} }
#[pymethods] #[pymethods]

View File

@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize};
use crate::mutators::str_decode; use crate::mutators::str_decode;
use crate::{ use crate::{
bolts::{rands::Rand, AsSlice}, bolts::{rands::Rand, AsSlice},
inputs::{HasBytesVec, Input}, inputs::{HasBytesVec, UsesInput},
mutators::{buffer_self_copy, mutations::buffer_copy, MutationResult, Mutator, Named}, mutators::{buffer_self_copy, mutations::buffer_copy, MutationResult, Mutator, Named},
observers::cmp::{CmpValues, CmpValuesMetadata}, observers::cmp::{CmpValues, CmpValuesMetadata},
state::{HasMaxSize, HasMetadata, HasRand}, state::{HasMaxSize, HasMetadata, HasRand},
@ -295,15 +295,15 @@ impl<'it> IntoIterator for &'it Tokens {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct TokenInsert; pub struct TokenInsert;
impl<I, S> Mutator<I, S> for TokenInsert impl<S> Mutator<S> for TokenInsert
where where
I: Input + HasBytesVec, S: UsesInput + HasMetadata + HasRand + HasMaxSize,
S: HasMetadata + HasRand + HasMaxSize, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -361,15 +361,15 @@ impl TokenInsert {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct TokenReplace; pub struct TokenReplace;
impl<I, S> Mutator<I, S> for TokenReplace impl<S> Mutator<S> for TokenReplace
where where
I: Input + HasBytesVec, S: UsesInput + HasMetadata + HasRand + HasMaxSize,
S: HasMetadata + HasRand + HasMaxSize, S::Input: HasBytesVec,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -423,16 +423,16 @@ impl TokenReplace {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct I2SRandReplace; pub struct I2SRandReplace;
impl<I, S> Mutator<I, S> for I2SRandReplace impl<S> Mutator<S> for I2SRandReplace
where where
I: Input + HasBytesVec, S: UsesInput + HasMetadata + HasRand + HasMaxSize,
S: HasMetadata + HasRand + HasMaxSize, S::Input: HasBytesVec,
{ {
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
fn mutate( fn mutate(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &mut I, input: &mut S::Input,
_stage_idx: i32, _stage_idx: i32,
) -> Result<MutationResult, Error> { ) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();

View File

@ -4,12 +4,13 @@ use alloc::{
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
}; };
use core::fmt::Debug; use core::{fmt::Debug, marker::PhantomData};
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{ use crate::{
bolts::{ownedref::OwnedRefMut, tuples::Named, AsMutSlice, AsSlice}, bolts::{ownedref::OwnedRefMut, tuples::Named, AsMutSlice, AsSlice},
inputs::UsesInput,
observers::Observer, observers::Observer,
state::HasMetadata, state::HasMetadata,
Error, Error,
@ -111,9 +112,10 @@ pub trait CmpMap: Debug {
} }
/// A [`CmpObserver`] observes the traced comparisons during the current execution using a [`CmpMap`] /// A [`CmpObserver`] observes the traced comparisons during the current execution using a [`CmpMap`]
pub trait CmpObserver<CM, I, S>: Observer<I, S> pub trait CmpObserver<CM, S>: Observer<S>
where where
CM: CmpMap, CM: CmpMap,
S: UsesInput,
{ {
/// Get the number of usable cmps (all by default) /// Get the number of usable cmps (all by default)
fn usable_count(&self) -> usize; fn usable_count(&self) -> usize;
@ -194,18 +196,21 @@ where
/// A standard [`CmpObserver`] observer /// A standard [`CmpObserver`] observer
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(bound = "CM: serde::de::DeserializeOwned")] #[serde(bound = "CM: serde::de::DeserializeOwned")]
pub struct StdCmpObserver<'a, CM> pub struct StdCmpObserver<'a, CM, S>
where where
CM: CmpMap + Serialize, CM: CmpMap + Serialize,
S: UsesInput,
{ {
cmp_map: OwnedRefMut<'a, CM>, cmp_map: OwnedRefMut<'a, CM>,
size: Option<OwnedRefMut<'a, usize>>, size: Option<OwnedRefMut<'a, usize>>,
name: String, name: String,
phantom: PhantomData<S>,
} }
impl<'a, CM, I, S> CmpObserver<CM, I, S> for StdCmpObserver<'a, CM> impl<'a, CM, S> CmpObserver<CM, S> for StdCmpObserver<'a, CM, S>
where where
CM: CmpMap + Serialize + DeserializeOwned, CM: CmpMap + Serialize + DeserializeOwned,
S: UsesInput + Debug,
{ {
/// Get the number of usable cmps (all by default) /// Get the number of usable cmps (all by default)
fn usable_count(&self) -> usize { fn usable_count(&self) -> usize {
@ -224,28 +229,31 @@ where
} }
} }
impl<'a, CM, I, S> Observer<I, S> for StdCmpObserver<'a, CM> impl<'a, CM, S> Observer<S> for StdCmpObserver<'a, CM, S>
where where
CM: CmpMap + Serialize + DeserializeOwned, CM: CmpMap + Serialize + DeserializeOwned,
S: UsesInput + Debug,
{ {
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.cmp_map.as_mut().reset()?; self.cmp_map.as_mut().reset()?;
Ok(()) Ok(())
} }
} }
impl<'a, CM> Named for StdCmpObserver<'a, CM> impl<'a, CM, S> Named for StdCmpObserver<'a, CM, S>
where where
CM: CmpMap + Serialize + DeserializeOwned, CM: CmpMap + Serialize + DeserializeOwned,
S: UsesInput,
{ {
fn name(&self) -> &str { fn name(&self) -> &str {
&self.name &self.name
} }
} }
impl<'a, CM> StdCmpObserver<'a, CM> impl<'a, CM, S> StdCmpObserver<'a, CM, S>
where where
CM: CmpMap + Serialize + DeserializeOwned, CM: CmpMap + Serialize + DeserializeOwned,
S: UsesInput,
{ {
/// Creates a new [`StdCmpObserver`] with the given name and map. /// Creates a new [`StdCmpObserver`] with the given name and map.
#[must_use] #[must_use]
@ -254,6 +262,7 @@ where
name: name.to_string(), name: name.to_string(),
size: None, size: None,
cmp_map: OwnedRefMut::Ref(map), cmp_map: OwnedRefMut::Ref(map),
phantom: PhantomData,
} }
} }
@ -264,6 +273,7 @@ where
name: name.to_string(), name: name.to_string(),
size: Some(OwnedRefMut::Ref(size)), size: Some(OwnedRefMut::Ref(size)),
cmp_map: OwnedRefMut::Ref(map), cmp_map: OwnedRefMut::Ref(map),
phantom: PhantomData,
} }
} }
} }

View File

@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::tuples::Named, bolts::tuples::Named,
inputs::UsesInput,
observers::{ observers::{
concolic::{serialization_format::MessageFileReader, ConcolicMetadata}, concolic::{serialization_format::MessageFileReader, ConcolicMetadata},
Observer, Observer,
@ -18,7 +19,7 @@ pub struct ConcolicObserver<'map> {
name: String, name: String,
} }
impl<'map, I, S> Observer<I, S> for ConcolicObserver<'map> {} impl<'map, S> Observer<S> for ConcolicObserver<'map> where S: UsesInput {}
impl<'map> ConcolicObserver<'map> { impl<'map> ConcolicObserver<'map> {
/// Create the concolic observer metadata for this run /// Create the concolic observer metadata for this run

View File

@ -24,6 +24,7 @@ use crate::{
AsIter, AsIterMut, AsMutSlice, AsSlice, HasLen, AsIter, AsIterMut, AsMutSlice, AsSlice, HasLen,
}, },
executors::ExitKind, executors::ExitKind,
inputs::UsesInput,
observers::Observer, observers::Observer,
Error, Error,
}; };
@ -198,8 +199,9 @@ where
name: String, name: String,
} }
impl<'a, I, S, T> Observer<I, S> for StdMapObserver<'a, T> impl<'a, S, T> Observer<S> for StdMapObserver<'a, T>
where where
S: UsesInput,
T: Bounded T: Bounded
+ PartialEq + PartialEq
+ Default + Default
@ -210,7 +212,7 @@ where
+ Debug, + Debug,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.reset_map() self.reset_map()
} }
} }
@ -499,13 +501,14 @@ where
name: String, name: String,
} }
impl<'a, I, S, T, const N: usize> Observer<I, S> for ConstMapObserver<'a, T, N> impl<'a, S, T, const N: usize> Observer<S> for ConstMapObserver<'a, T, N>
where where
S: UsesInput,
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver, Self: MapObserver,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.reset_map() self.reset_map()
} }
} }
@ -770,13 +773,14 @@ where
name: String, name: String,
} }
impl<'a, I, S, T> Observer<I, S> for VariableMapObserver<'a, T> impl<'a, S, T> Observer<S> for VariableMapObserver<'a, T>
where where
S: UsesInput,
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver, Self: MapObserver,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.reset_map() self.reset_map()
} }
} }
@ -1038,18 +1042,24 @@ where
base: M, base: M,
} }
impl<I, S, M> Observer<I, S> for HitcountsMapObserver<M> impl<S, M> Observer<S> for HitcountsMapObserver<M>
where where
M: MapObserver<Entry = u8> + Observer<I, S> + AsMutSlice<u8>, M: MapObserver<Entry = u8> + Observer<S> + AsMutSlice<u8>,
S: UsesInput,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> { fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.base.pre_exec(state, input) self.base.pre_exec(state, input)
} }
#[inline] #[inline]
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
fn post_exec(&mut self, state: &mut S, input: &I, exit_kind: &ExitKind) -> Result<(), Error> { fn post_exec(
&mut self,
state: &mut S,
input: &S::Input,
exit_kind: &ExitKind,
) -> Result<(), Error> {
let map = self.as_mut_slice(); let map = self.as_mut_slice();
let len = map.len(); let len = map.len();
if (len & 1) != 0 { if (len & 1) != 0 {
@ -1237,19 +1247,25 @@ where
base: M, base: M,
} }
impl<I, S, M> Observer<I, S> for HitcountsIterableMapObserver<M> impl<S, M> Observer<S> for HitcountsIterableMapObserver<M>
where where
M: MapObserver<Entry = u8> + Observer<I, S>, M: MapObserver<Entry = u8> + Observer<S>,
for<'it> M: AsIterMut<'it, Item = u8>, for<'it> M: AsIterMut<'it, Item = u8>,
S: UsesInput,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> { fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.base.pre_exec(state, input) self.base.pre_exec(state, input)
} }
#[inline] #[inline]
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
fn post_exec(&mut self, state: &mut S, input: &I, exit_kind: &ExitKind) -> Result<(), Error> { fn post_exec(
&mut self,
state: &mut S,
input: &S::Input,
exit_kind: &ExitKind,
) -> Result<(), Error> {
for item in self.as_iter_mut() { for item in self.as_iter_mut() {
*item = unsafe { *COUNT_CLASS_LOOKUP.get_unchecked((*item) as usize) }; *item = unsafe { *COUNT_CLASS_LOOKUP.get_unchecked((*item) as usize) };
} }
@ -1429,13 +1445,14 @@ where
iter_idx: usize, iter_idx: usize,
} }
impl<'a, I, S, T> Observer<I, S> for MultiMapObserver<'a, T> impl<'a, S, T> Observer<S> for MultiMapObserver<'a, T>
where where
S: UsesInput,
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver, Self: MapObserver,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.reset_map() self.reset_map()
} }
} }
@ -1685,13 +1702,14 @@ where
name: String, name: String,
} }
impl<I, S, T> Observer<I, S> for OwnedMapObserver<T> impl<S, T> Observer<S> for OwnedMapObserver<T>
where where
S: UsesInput,
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver, Self: MapObserver,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.reset_map() self.reset_map()
} }
} }
@ -1904,7 +1922,7 @@ pub mod pybind {
AsIter, AsIterMut, AsMutSlice, AsSlice, Debug, Error, HasLen, Iter, IterMut, MapObserver, AsIter, AsIterMut, AsMutSlice, AsSlice, Debug, Error, HasLen, Iter, IterMut, MapObserver,
Named, Observer, OwnedMapObserver, StdMapObserver, String, Vec, Named, Observer, OwnedMapObserver, StdMapObserver, String, Vec,
}; };
use crate::observers::pybind::PythonObserver; use crate::{inputs::UsesInput, observers::pybind::PythonObserver};
#[macro_export] #[macro_export]
macro_rules! mapob_unwrap_me { macro_rules! mapob_unwrap_me {
@ -2240,12 +2258,13 @@ pub mod pybind {
} }
} }
impl<I, S> Observer<I, S> for $struct_name_trait impl<S> Observer<S> for $struct_name_trait
where where
Self: MapObserver, Self: MapObserver,
S: UsesInput,
{ {
#[inline] #[inline]
fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> { fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { m.pre_exec(state, input) }) mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { m.pre_exec(state, input) })
} }
} }

View File

@ -39,12 +39,17 @@ use crate::{
tuples::{MatchName, Named}, tuples::{MatchName, Named},
}, },
executors::ExitKind, executors::ExitKind,
inputs::UsesInput,
state::UsesState,
Error, Error,
}; };
/// 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<I, S>: Named + Debug { pub trait Observer<S>: Named + Debug
where
S: UsesInput,
{
/// The testcase finished execution, calculate any changes. /// The testcase finished execution, calculate any changes.
/// Reserved for future use. /// Reserved for future use.
#[inline] #[inline]
@ -54,7 +59,7 @@ pub trait Observer<I, S>: Named + Debug {
/// Called right before execution starts. /// Called right before execution starts.
#[inline] #[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(()) Ok(())
} }
@ -63,7 +68,7 @@ pub trait Observer<I, S>: Named + Debug {
fn post_exec( fn post_exec(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_input: &I, _input: &S::Input,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
@ -71,7 +76,7 @@ pub trait Observer<I, S>: Named + Debug {
/// Called right before execution starts in the child process, if any. /// Called right before execution starts in the child process, if any.
#[inline] #[inline]
fn pre_exec_child(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec_child(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(()) Ok(())
} }
@ -80,7 +85,7 @@ pub trait Observer<I, S>: Named + Debug {
fn post_exec_child( fn post_exec_child(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_input: &I, _input: &S::Input,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
@ -109,27 +114,37 @@ pub trait Observer<I, S>: Named + Debug {
fn observe_stderr(&mut self, stderr: &str) {} fn observe_stderr(&mut self, stderr: &str) {}
} }
/// Defines the observer type shared across traits of the type.
/// Needed for consistency across HasCorpus/HasSolutions and friends.
pub trait UsesObservers: UsesState {
/// The observers type
type Observers: ObserversTuple<Self::State>;
}
/// A haskell-style tuple of observers /// A haskell-style tuple of observers
pub trait ObserversTuple<I, S>: MatchName + Debug { pub trait ObserversTuple<S>: MatchName + Debug
where
S: UsesInput,
{
/// This is called right before the next execution. /// This is called right before the next execution.
fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error>; fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error>;
/// This is called right after the last execution /// This is called right after the last execution
fn post_exec_all( fn post_exec_all(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &I, input: &S::Input,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<(), Error>; ) -> Result<(), Error>;
/// This is called right before the next execution in the child process, if any. /// This is called right before the next execution in the child process, if any.
fn pre_exec_child_all(&mut self, state: &mut S, input: &I) -> Result<(), Error>; fn pre_exec_child_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error>;
/// This is called right after the last execution in the child process, if any. /// This is called right after the last execution in the child process, if any.
fn post_exec_child_all( fn post_exec_child_all(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &I, input: &S::Input,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<(), Error>; ) -> Result<(), Error>;
@ -144,28 +159,31 @@ pub trait ObserversTuple<I, S>: MatchName + Debug {
fn observe_stderr(&mut self, stderr: &str); fn observe_stderr(&mut self, stderr: &str);
} }
impl<I, S> ObserversTuple<I, S> for () { impl<S> ObserversTuple<S> for ()
fn pre_exec_all(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { where
S: UsesInput,
{
fn pre_exec_all(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(()) Ok(())
} }
fn post_exec_all( fn post_exec_all(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_input: &I, _input: &S::Input,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
} }
fn pre_exec_child_all(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec_child_all(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(()) Ok(())
} }
fn post_exec_child_all( fn post_exec_child_all(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_input: &I, _input: &S::Input,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
@ -192,12 +210,13 @@ impl<I, S> ObserversTuple<I, S> for () {
fn observe_stderr(&mut self, stderr: &str) {} fn observe_stderr(&mut self, stderr: &str) {}
} }
impl<Head, Tail, I, S> ObserversTuple<I, S> for (Head, Tail) impl<Head, Tail, S> ObserversTuple<S> for (Head, Tail)
where where
Head: Observer<I, S>, Head: Observer<S>,
Tail: ObserversTuple<I, S>, Tail: ObserversTuple<S>,
S: UsesInput,
{ {
fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> { fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.0.pre_exec(state, input)?; self.0.pre_exec(state, input)?;
self.1.pre_exec_all(state, input) self.1.pre_exec_all(state, input)
} }
@ -205,14 +224,14 @@ where
fn post_exec_all( fn post_exec_all(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &I, input: &S::Input,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.0.post_exec(state, input, exit_kind)?; self.0.post_exec(state, input, exit_kind)?;
self.1.post_exec_all(state, input, exit_kind) self.1.post_exec_all(state, input, exit_kind)
} }
fn pre_exec_child_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> { fn pre_exec_child_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.0.pre_exec_child(state, input)?; self.0.pre_exec_child(state, input)?;
self.1.pre_exec_child_all(state, input) self.1.pre_exec_child_all(state, input)
} }
@ -220,7 +239,7 @@ where
fn post_exec_child_all( fn post_exec_child_all(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &I, input: &S::Input,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.0.post_exec_child(state, input, exit_kind)?; self.0.post_exec_child(state, input, exit_kind)?;
@ -286,8 +305,11 @@ impl TimeObserver {
} }
} }
impl<I, S> Observer<I, S> for TimeObserver { impl<S> Observer<S> for TimeObserver
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { where
S: UsesInput,
{
fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.last_runtime = None; self.last_runtime = None;
self.start_time = current_time(); self.start_time = current_time();
Ok(()) Ok(())
@ -296,7 +318,7 @@ impl<I, S> Observer<I, S> for TimeObserver {
fn post_exec( fn post_exec(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_input: &I, _input: &S::Input,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.last_runtime = current_time().checked_sub(self.start_time); self.last_runtime = current_time().checked_sub(self.start_time);
@ -348,11 +370,12 @@ where
} }
} }
impl<'a, I, S, T> Observer<I, S> for ListObserver<'a, T> impl<'a, S, T> Observer<S> for ListObserver<'a, T>
where where
S: UsesInput,
T: Debug + Serialize + serde::de::DeserializeOwned, T: Debug + Serialize + serde::de::DeserializeOwned,
{ {
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.list.as_mut().clear(); self.list.as_mut().clear();
Ok(()) Ok(())
} }
@ -433,7 +456,7 @@ pub mod pybind {
} }
} }
impl Observer<BytesInput, PythonStdState> for PyObjectObserver { impl Observer<PythonStdState> for PyObjectObserver {
fn flush(&mut self) -> Result<(), Error> { fn flush(&mut self) -> Result<(), Error> {
Python::with_gil(|py| -> PyResult<()> { Python::with_gil(|py| -> PyResult<()> {
self.inner.call_method0(py, "flush")?; self.inner.call_method0(py, "flush")?;
@ -827,11 +850,9 @@ pub mod pybind {
} }
} }
impl Observer<BytesInput, PythonStdState> for PythonObserver { impl Observer<PythonStdState> for PythonObserver {
fn flush(&mut self) -> Result<(), Error> { fn flush(&mut self) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, o, { unwrap_me_mut!(self.wrapper, o, { Observer::<PythonStdState>::flush(o) })
Observer::<BytesInput, PythonStdState>::flush(o)
})
} }
fn pre_exec( fn pre_exec(
@ -904,7 +925,7 @@ pub mod pybind {
} }
} }
impl ObserversTuple<BytesInput, PythonStdState> for PythonObserversTuple { impl ObserversTuple<PythonStdState> for PythonObserversTuple {
fn pre_exec_all( fn pre_exec_all(
&mut self, &mut self,
state: &mut PythonStdState, state: &mut PythonStdState,

View File

@ -67,7 +67,7 @@ impl<'de, I: 'static + Debug, S: 'static + Debug> Deserialize<'de> for Observers
} }
} }
impl<I: 'static + Debug, S: 'static + Debug> ObserversTuple<I, S> for ObserversOwnedMap<I, S> { impl<I: 'static + Debug, S: 'static + Debug> ObserversTuple<S> for ObserversOwnedMap<I, S> {
fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> { fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
self.map self.map
.for_each_mut(&mut |_, ob| ob.pre_exec(state, input)) .for_each_mut(&mut |_, ob| ob.pre_exec(state, input))

View File

@ -17,7 +17,7 @@ use super::ObserverWithHashField;
use crate::{ use crate::{
bolts::{ownedref::OwnedRefMut, tuples::Named}, bolts::{ownedref::OwnedRefMut, tuples::Named},
executors::ExitKind, executors::ExitKind,
inputs::Input, inputs::UsesInput,
observers::Observer, observers::Observer,
Error, Error,
}; };
@ -97,11 +97,16 @@ impl<'a> ObserverWithHashField for BacktraceObserver<'a> {
} }
} }
impl<'a, I, S> Observer<I, S> for BacktraceObserver<'a> impl<'a, S> Observer<S> for BacktraceObserver<'a>
where where
I: Input + Debug, S: UsesInput,
{ {
fn post_exec(&mut self, _state: &mut S, _input: &I, exit_kind: &ExitKind) -> Result<(), Error> { fn post_exec(
&mut self,
_state: &mut S,
_input: &S::Input,
exit_kind: &ExitKind,
) -> Result<(), Error> {
if self.harness_type == HarnessType::InProcess { if self.harness_type == HarnessType::InProcess {
if exit_kind == &ExitKind::Crash { if exit_kind == &ExitKind::Crash {
self.update_hash(collect_backtrace()); self.update_hash(collect_backtrace());
@ -115,7 +120,7 @@ where
fn post_exec_child( fn post_exec_child(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_input: &I, _input: &S::Input,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
if self.harness_type == HarnessType::Child { if self.harness_type == HarnessType::Child {
@ -240,18 +245,18 @@ impl Default for AsanBacktraceObserver {
} }
} }
impl<I, S> Observer<I, S> for AsanBacktraceObserver impl<S> Observer<S> for AsanBacktraceObserver
where where
I: Debug, S: UsesInput,
{ {
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(()) Ok(())
} }
fn post_exec( fn post_exec(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_input: &I, _input: &S::Input,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())

View File

@ -6,7 +6,7 @@ use alloc::string::String;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{bolts::tuples::Named, observers::Observer}; use crate::{bolts::tuples::Named, inputs::UsesInput, observers::Observer};
/// An observer that captures stdout of a target. /// An observer that captures stdout of a target.
/// Only works for supported executors. /// Only works for supported executors.
@ -27,7 +27,10 @@ impl StdOutObserver {
} }
} }
impl<I, S> Observer<I, S> for StdOutObserver { impl<S> Observer<S> for StdOutObserver
where
S: UsesInput,
{
#[inline] #[inline]
fn observes_stdout(&mut self) -> bool { fn observes_stdout(&mut self) -> bool {
true true
@ -63,7 +66,10 @@ impl StdErrObserver {
} }
} }
impl<I, S> Observer<I, S> for StdErrObserver { impl<S> Observer<S> for StdErrObserver
where
S: UsesInput,
{
#[inline] #[inline]
fn observes_stderr(&mut self) -> bool { fn observes_stderr(&mut self) -> bool {
true true

View File

@ -1,6 +1,7 @@
//! Coverage accounting corpus scheduler, more details at <https://www.ndss-symposium.org/wp-content/uploads/2020/02/24422-paper.pdf> //! Coverage accounting corpus scheduler, more details at <https://www.ndss-symposium.org/wp-content/uploads/2020/02/24422-paper.pdf>
use alloc::vec::Vec; use alloc::vec::Vec;
use core::fmt::Debug;
use hashbrown::HashMap; use hashbrown::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -9,12 +10,12 @@ use crate::{
bolts::{rands::Rand, AsMutSlice, AsSlice, HasLen, HasRefCnt}, bolts::{rands::Rand, AsMutSlice, AsSlice, HasLen, HasRefCnt},
corpus::{Corpus, Testcase}, corpus::{Corpus, Testcase},
feedbacks::MapIndexesMetadata, feedbacks::MapIndexesMetadata,
inputs::Input, inputs::UsesInput,
schedulers::{ schedulers::{
minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB}, minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB},
LenTimeMulTestcaseScore, Scheduler, LenTimeMulTestcaseScore, Scheduler,
}, },
state::{HasCorpus, HasMetadata, HasRand}, state::{HasCorpus, HasMetadata, HasRand, UsesState},
Error, Error,
}; };
@ -93,42 +94,58 @@ impl TopAccountingMetadata {
/// A minimizer scheduler using coverage accounting /// A minimizer scheduler using coverage accounting
#[derive(Debug)] #[derive(Debug)]
pub struct CoverageAccountingScheduler<'a, CS, I, S> pub struct CoverageAccountingScheduler<'a, CS>
where where
CS: Scheduler<I, S>, CS: UsesState,
I: Input + HasLen, CS::State: Debug,
S: HasCorpus<I> + HasMetadata + HasRand,
{ {
accounting_map: &'a [u32], accounting_map: &'a [u32],
skip_non_favored_prob: u64, skip_non_favored_prob: u64,
inner: MinimizerScheduler<CS, LenTimeMulTestcaseScore<I, S>, I, MapIndexesMetadata, S>, inner: MinimizerScheduler<
CS,
LenTimeMulTestcaseScore<<CS as UsesState>::State>,
MapIndexesMetadata,
>,
} }
impl<'a, CS, I, S> Scheduler<I, S> for CoverageAccountingScheduler<'a, CS, I, S> impl<'a, CS> UsesState for CoverageAccountingScheduler<'a, CS>
where where
CS: Scheduler<I, S>, CS: UsesState,
I: Input + HasLen, CS::State: Debug,
S: HasCorpus<I> + HasMetadata + HasRand,
{ {
fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> { type State = CS::State;
}
impl<'a, CS> Scheduler for CoverageAccountingScheduler<'a, CS>
where
CS: Scheduler,
CS::State: HasCorpus + HasMetadata + HasRand + Debug,
<CS::State as UsesInput>::Input: HasLen,
{
fn on_add(&self, state: &mut Self::State, idx: usize) -> Result<(), Error> {
self.update_accounting_score(state, idx)?; self.update_accounting_score(state, idx)?;
self.inner.on_add(state, idx) self.inner.on_add(state, idx)
} }
fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error> { fn on_replace(
&self,
state: &mut Self::State,
idx: usize,
testcase: &Testcase<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
self.inner.on_replace(state, idx, testcase) self.inner.on_replace(state, idx, testcase)
} }
fn on_remove( fn on_remove(
&self, &self,
state: &mut S, state: &mut Self::State,
idx: usize, idx: usize,
testcase: &Option<Testcase<I>>, testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.inner.on_remove(state, idx, testcase) self.inner.on_remove(state, idx, testcase)
} }
fn next(&self, state: &mut S) -> Result<usize, Error> { fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
if state if state
.metadata() .metadata()
.get::<TopAccountingMetadata>() .get::<TopAccountingMetadata>()
@ -154,16 +171,16 @@ where
} }
} }
impl<'a, CS, I, S> CoverageAccountingScheduler<'a, CS, I, S> impl<'a, CS> CoverageAccountingScheduler<'a, CS>
where where
CS: Scheduler<I, S>, CS: Scheduler,
I: Input + HasLen, CS::State: HasCorpus + HasMetadata + HasRand + Debug,
S: HasCorpus<I> + HasMetadata + HasRand, <CS::State as UsesInput>::Input: HasLen,
{ {
/// Update the `Corpus` score /// Update the `Corpus` score
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
#[allow(clippy::cast_possible_wrap)] #[allow(clippy::cast_possible_wrap)]
pub fn update_accounting_score(&self, state: &mut S, idx: usize) -> Result<(), Error> { pub fn update_accounting_score(&self, state: &mut CS::State, idx: usize) -> Result<(), Error> {
let mut indexes = vec![]; let mut indexes = vec![];
let mut new_favoreds = vec![]; let mut new_favoreds = vec![];
{ {
@ -243,7 +260,7 @@ where
/// Cull the `Corpus` /// Cull the `Corpus`
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn accounting_cull(&self, state: &mut S) -> Result<(), Error> { pub fn accounting_cull(&self, state: &mut CS::State) -> Result<(), Error> {
let top_rated = match state.metadata().get::<TopAccountingMetadata>() { let top_rated = match state.metadata().get::<TopAccountingMetadata>() {
None => return Ok(()), None => return Ok(()),
Some(val) => val, Some(val) => val,
@ -263,7 +280,7 @@ where
/// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`] /// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`]
/// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`]. /// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
pub fn new(state: &mut S, base: CS, accounting_map: &'a [u32]) -> Self { pub fn new(state: &mut CS::State, base: CS, accounting_map: &'a [u32]) -> Self {
match state.metadata().get::<TopAccountingMetadata>() { match state.metadata().get::<TopAccountingMetadata>() {
Some(meta) => { Some(meta) => {
if meta.max_accounting.len() != accounting_map.len() { if meta.max_accounting.len() != accounting_map.len() {
@ -284,7 +301,7 @@ where
/// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`] /// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`]
/// and has a non-default probability to skip non-faved [`Testcase`]s using (`skip_non_favored_prob`). /// and has a non-default probability to skip non-faved [`Testcase`]s using (`skip_non_favored_prob`).
pub fn with_skip_prob( pub fn with_skip_prob(
state: &mut S, state: &mut CS::State,
base: CS, base: CS,
skip_non_favored_prob: u64, skip_non_favored_prob: u64,
accounting_map: &'a [u32], accounting_map: &'a [u32],

View File

@ -11,9 +11,9 @@ use crate::{
bolts::{rands::Rand, serdeany::SerdeAny, AsSlice, HasRefCnt}, bolts::{rands::Rand, serdeany::SerdeAny, AsSlice, HasRefCnt},
corpus::{Corpus, Testcase}, corpus::{Corpus, Testcase},
feedbacks::MapIndexesMetadata, feedbacks::MapIndexesMetadata,
inputs::Input, inputs::UsesInput,
schedulers::{LenTimeMulTestcaseScore, Scheduler, TestcaseScore}, schedulers::{LenTimeMulTestcaseScore, Scheduler, TestcaseScore},
state::{HasCorpus, HasMetadata, HasRand}, state::{HasCorpus, HasMetadata, HasRand, UsesState},
Error, Error,
}; };
@ -61,44 +61,48 @@ impl Default for TopRatedsMetadata {
/// corpus that exercise all the requested features (e.g. all the coverage seen so far) /// corpus that exercise all the requested features (e.g. all the coverage seen so far)
/// prioritizing [`Testcase`]`s` using [`TestcaseScore`] /// prioritizing [`Testcase`]`s` using [`TestcaseScore`]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MinimizerScheduler<CS, F, I, M, S> pub struct MinimizerScheduler<CS, F, M> {
where
CS: Scheduler<I, S>,
F: TestcaseScore<I, S>,
I: Input,
M: AsSlice<usize> + SerdeAny + HasRefCnt,
S: HasCorpus<I> + HasMetadata,
{
base: CS, base: CS,
skip_non_favored_prob: u64, skip_non_favored_prob: u64,
phantom: PhantomData<(F, I, M, S)>, phantom: PhantomData<(F, M)>,
} }
impl<CS, F, I, M, S> Scheduler<I, S> for MinimizerScheduler<CS, F, I, M, S> impl<CS, F, M> UsesState for MinimizerScheduler<CS, F, M>
where where
CS: Scheduler<I, S>, CS: UsesState,
F: TestcaseScore<I, S>, {
I: Input, type State = CS::State;
}
impl<CS, F, M> Scheduler for MinimizerScheduler<CS, F, M>
where
CS: Scheduler,
F: TestcaseScore<CS::State>,
M: AsSlice<usize> + SerdeAny + HasRefCnt, M: AsSlice<usize> + SerdeAny + HasRefCnt,
S: HasCorpus<I> + HasMetadata + HasRand, CS::State: HasCorpus + HasMetadata + HasRand,
{ {
/// Add an entry to the corpus and return its index /// Add an entry to the corpus and return its index
fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> { fn on_add(&self, state: &mut CS::State, idx: usize) -> Result<(), Error> {
self.update_score(state, idx)?; self.update_score(state, idx)?;
self.base.on_add(state, idx) self.base.on_add(state, idx)
} }
/// Replaces the testcase at the given idx /// Replaces the testcase at the given idx
fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error> { fn on_replace(
&self,
state: &mut CS::State,
idx: usize,
testcase: &Testcase<<CS::State as UsesInput>::Input>,
) -> Result<(), Error> {
self.base.on_replace(state, idx, testcase) self.base.on_replace(state, idx, testcase)
} }
/// Removes an entry from the corpus, returning M if M was present. /// Removes an entry from the corpus, returning M if M was present.
fn on_remove( fn on_remove(
&self, &self,
state: &mut S, state: &mut CS::State,
idx: usize, idx: usize,
testcase: &Option<Testcase<I>>, testcase: &Option<Testcase<<CS::State as UsesInput>::Input>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.base.on_remove(state, idx, testcase)?; self.base.on_remove(state, idx, testcase)?;
let mut entries = if let Some(meta) = state.metadata_mut().get_mut::<TopRatedsMetadata>() { let mut entries = if let Some(meta) = state.metadata_mut().get_mut::<TopRatedsMetadata>() {
@ -164,7 +168,7 @@ where
} }
/// Gets the next entry /// Gets the next entry
fn next(&self, state: &mut S) -> Result<usize, Error> { fn next(&self, state: &mut CS::State) -> Result<usize, Error> {
self.cull(state)?; self.cull(state)?;
let mut idx = self.base.next(state)?; let mut idx = self.base.next(state)?;
while { while {
@ -182,18 +186,17 @@ where
} }
} }
impl<CS, F, I, M, S> MinimizerScheduler<CS, F, I, M, S> impl<CS, F, M> MinimizerScheduler<CS, F, M>
where where
CS: Scheduler<I, S>, CS: Scheduler,
F: TestcaseScore<I, S>, F: TestcaseScore<CS::State>,
I: Input,
M: AsSlice<usize> + SerdeAny + HasRefCnt, M: AsSlice<usize> + SerdeAny + HasRefCnt,
S: HasCorpus<I> + HasMetadata + HasRand, CS::State: HasCorpus + HasMetadata + HasRand,
{ {
/// Update the `Corpus` score using the `MinimizerScheduler` /// Update the `Corpus` score using the `MinimizerScheduler`
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
#[allow(clippy::cast_possible_wrap)] #[allow(clippy::cast_possible_wrap)]
pub fn update_score(&self, state: &mut S, idx: usize) -> Result<(), Error> { pub fn update_score(&self, state: &mut CS::State, idx: usize) -> Result<(), Error> {
// Create a new top rated meta if not existing // Create a new top rated meta if not existing
if state.metadata().get::<TopRatedsMetadata>().is_none() { if state.metadata().get::<TopRatedsMetadata>().is_none() {
state.add_metadata(TopRatedsMetadata::new()); state.add_metadata(TopRatedsMetadata::new());
@ -269,7 +272,7 @@ where
/// Cull the `Corpus` using the `MinimizerScheduler` /// Cull the `Corpus` using the `MinimizerScheduler`
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn cull(&self, state: &mut S) -> Result<(), Error> { pub fn cull(&self, state: &mut CS::State) -> Result<(), Error> {
let top_rated = match state.metadata().get::<TopRatedsMetadata>() { let top_rated = match state.metadata().get::<TopRatedsMetadata>() {
None => return Ok(()), None => return Ok(()),
Some(val) => val, Some(val) => val,
@ -324,10 +327,10 @@ where
} }
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`. /// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`.
pub type LenTimeMinimizerScheduler<CS, I, M, S> = pub type LenTimeMinimizerScheduler<CS, M> =
MinimizerScheduler<CS, LenTimeMulTestcaseScore<I, S>, I, M, S>; MinimizerScheduler<CS, LenTimeMulTestcaseScore<<CS as UsesState>::State>, M>;
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s` /// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`
/// that exercise all the entries registered in the [`MapIndexesMetadata`]. /// that exercise all the entries registered in the [`MapIndexesMetadata`].
pub type IndexesLenTimeMinimizerScheduler<CS, I, S> = pub type IndexesLenTimeMinimizerScheduler<CS> =
MinimizerScheduler<CS, LenTimeMulTestcaseScore<I, S>, I, MapIndexesMetadata, S>; MinimizerScheduler<CS, LenTimeMulTestcaseScore<<CS as UsesState>::State>, MapIndexesMetadata>;

View File

@ -1,6 +1,8 @@
//! Schedule the access to the Corpus. //! Schedule the access to the Corpus.
pub mod queue; pub mod queue;
use core::marker::PhantomData;
pub use queue::QueueScheduler; pub use queue::QueueScheduler;
pub mod probabilistic_sampling; pub mod probabilistic_sampling;
@ -28,52 +30,62 @@ pub use powersched::PowerQueueScheduler;
use crate::{ use crate::{
bolts::rands::Rand, bolts::rands::Rand,
corpus::{Corpus, Testcase}, corpus::{Corpus, Testcase},
inputs::Input, inputs::UsesInput,
state::{HasCorpus, HasRand}, state::{HasCorpus, HasRand, UsesState},
Error, Error,
}; };
/// The scheduler define how the fuzzer requests a testcase from the corpus. /// The scheduler define how the fuzzer requests a testcase from the corpus.
/// It has hooks to corpus add/replace/remove to allow complex scheduling algorithms to collect data. /// It has hooks to corpus add/replace/remove to allow complex scheduling algorithms to collect data.
pub trait Scheduler<I, S> pub trait Scheduler: UsesState {
where
I: Input,
{
/// Added an entry to the corpus at the given index /// Added an entry to the corpus at the given index
fn on_add(&self, _state: &mut S, _idx: usize) -> Result<(), Error> { fn on_add(&self, _state: &mut Self::State, _idx: usize) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Replaced the given testcase at the given idx /// Replaced the given testcase at the given idx
fn on_replace(&self, _state: &mut S, _idx: usize, _prev: &Testcase<I>) -> Result<(), Error> { fn on_replace(
&self,
_state: &mut Self::State,
_idx: usize,
_prev: &Testcase<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Removed the given entry from the corpus at the given index /// Removed the given entry from the corpus at the given index
fn on_remove( fn on_remove(
&self, &self,
_state: &mut S, _state: &mut Self::State,
_idx: usize, _idx: usize,
_testcase: &Option<Testcase<I>>, _testcase: &Option<Testcase<<Self::State as UsesInput>::Input>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Gets the next entry /// Gets the next entry
fn next(&self, state: &mut S) -> Result<usize, Error>; fn next(&self, state: &mut Self::State) -> Result<usize, Error>;
} }
/// Feed the fuzzer simpply with a random testcase on request /// Feed the fuzzer simply with a random testcase on request
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RandScheduler; pub struct RandScheduler<S> {
phantom: PhantomData<S>,
}
impl<I, S> Scheduler<I, S> for RandScheduler impl<S> UsesState for RandScheduler<S>
where where
S: HasCorpus<I> + HasRand, S: UsesInput,
I: Input, {
type State = S;
}
impl<S> Scheduler for RandScheduler<S>
where
S: HasCorpus + HasRand,
{ {
/// Gets the next entry at random /// Gets the next entry at random
fn next(&self, state: &mut S) -> Result<usize, Error> { fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
Err(Error::empty("No entries in corpus".to_owned())) Err(Error::empty("No entries in corpus".to_owned()))
} else { } else {
@ -85,15 +97,17 @@ where
} }
} }
impl RandScheduler { impl<S> RandScheduler<S> {
/// Create a new [`RandScheduler`] that just schedules randomly. /// Create a new [`RandScheduler`] that just schedules randomly.
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self Self {
phantom: PhantomData,
}
} }
} }
impl Default for RandScheduler { impl<S> Default for RandScheduler<S> {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
@ -101,4 +115,4 @@ impl Default for RandScheduler {
/// A [`StdScheduler`] uses the default scheduler in `LibAFL` to schedule [`Testcase`]s. /// A [`StdScheduler`] uses the default scheduler in `LibAFL` to schedule [`Testcase`]s.
/// The current `Std` is a [`RandScheduler`], although this may change in the future, if another [`Scheduler`] delivers better results. /// The current `Std` is a [`RandScheduler`], although this may change in the future, if another [`Scheduler`] delivers better results.
pub type StdScheduler = RandScheduler; pub type StdScheduler<S> = RandScheduler<S>;

View File

@ -4,17 +4,18 @@ use alloc::{
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
}; };
use core::time::Duration; use core::{marker::PhantomData, time::Duration};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
corpus::{Corpus, SchedulerTestcaseMetaData}, corpus::{Corpus, SchedulerTestcaseMetaData},
inputs::Input, inputs::UsesInput,
schedulers::Scheduler, schedulers::Scheduler,
state::{HasCorpus, HasMetadata}, state::{HasCorpus, HasMetadata, UsesState},
Error, Error,
}; };
/// The n fuzz size /// The n fuzz size
pub const N_FUZZ_SIZE: usize = 1 << 21; pub const N_FUZZ_SIZE: usize = 1 << 21;
@ -148,17 +149,24 @@ pub enum PowerSchedule {
/// A corpus scheduler using power schedules /// A corpus scheduler using power schedules
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PowerQueueScheduler { pub struct PowerQueueScheduler<S> {
strat: PowerSchedule, strat: PowerSchedule,
phantom: PhantomData<S>,
} }
impl<I, S> Scheduler<I, S> for PowerQueueScheduler impl<S> UsesState for PowerQueueScheduler<S>
where where
S: HasCorpus<I> + HasMetadata, S: UsesInput,
I: Input, {
type State = S;
}
impl<S> Scheduler for PowerQueueScheduler<S>
where
S: HasCorpus + HasMetadata,
{ {
/// Add an entry to the corpus and return its index /// Add an entry to the corpus and return its index
fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> { fn on_add(&self, state: &mut Self::State, idx: usize) -> Result<(), Error> {
if !state.has_metadata::<SchedulerMetadata>() { if !state.has_metadata::<SchedulerMetadata>() {
state.add_metadata::<SchedulerMetadata>(SchedulerMetadata::new(Some(self.strat))); state.add_metadata::<SchedulerMetadata>(SchedulerMetadata::new(Some(self.strat)));
} }
@ -189,7 +197,7 @@ where
Ok(()) Ok(())
} }
fn next(&self, state: &mut S) -> Result<usize, Error> { fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
Err(Error::empty(String::from("No entries in corpus"))) Err(Error::empty(String::from("No entries in corpus")))
} else { } else {
@ -232,10 +240,13 @@ where
} }
} }
impl PowerQueueScheduler { impl<S> PowerQueueScheduler<S> {
/// Create a new [`PowerQueueScheduler`] /// Create a new [`PowerQueueScheduler`]
#[must_use] #[must_use]
pub fn new(strat: PowerSchedule) -> Self { pub fn new(strat: PowerSchedule) -> Self {
PowerQueueScheduler { strat } PowerQueueScheduler {
strat,
phantom: PhantomData,
}
} }
} }

View File

@ -10,21 +10,19 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::rands::Rand, bolts::rands::Rand,
corpus::Corpus, corpus::Corpus,
inputs::Input, inputs::UsesInput,
schedulers::{Scheduler, TestcaseScore}, schedulers::{Scheduler, TestcaseScore},
state::{HasCorpus, HasMetadata, HasRand}, state::{HasCorpus, HasMetadata, HasRand, UsesState},
Error, Error,
}; };
/// Conduct reservoir sampling (probabilistic sampling) over all corpus elements. /// Conduct reservoir sampling (probabilistic sampling) over all corpus elements.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ProbabilitySamplingScheduler<F, I, S> pub struct ProbabilitySamplingScheduler<F, S>
where where
F: TestcaseScore<I, S>, S: UsesInput,
I: Input,
S: HasCorpus<I> + HasMetadata + HasRand,
{ {
phantom: PhantomData<(F, I, S)>, phantom: PhantomData<(F, S)>,
} }
/// A state metadata holding a map of probability of corpus elements. /// A state metadata holding a map of probability of corpus elements.
@ -55,11 +53,10 @@ impl Default for ProbabilityMetadata {
} }
} }
impl<F, I, S> ProbabilitySamplingScheduler<F, I, S> impl<F, S> ProbabilitySamplingScheduler<F, S>
where where
F: TestcaseScore<I, S>, F: TestcaseScore<S>,
I: Input, S: HasCorpus + HasMetadata + HasRand,
S: HasCorpus<I> + HasMetadata + HasRand,
{ {
/// Creates a new [`struct@ProbabilitySamplingScheduler`] /// Creates a new [`struct@ProbabilitySamplingScheduler`]
#[must_use] #[must_use]
@ -90,13 +87,19 @@ where
} }
} }
impl<F, I, S> Scheduler<I, S> for ProbabilitySamplingScheduler<F, I, S> impl<F, S> UsesState for ProbabilitySamplingScheduler<F, S>
where where
F: TestcaseScore<I, S>, S: UsesInput,
I: Input,
S: HasCorpus<I> + HasMetadata + HasRand,
{ {
fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> { type State = S;
}
impl<F, S> Scheduler for ProbabilitySamplingScheduler<F, S>
where
F: TestcaseScore<S>,
S: HasCorpus + HasMetadata + HasRand,
{
fn on_add(&self, state: &mut Self::State, idx: usize) -> Result<(), Error> {
if state.metadata().get::<ProbabilityMetadata>().is_none() { if state.metadata().get::<ProbabilityMetadata>().is_none() {
state.add_metadata(ProbabilityMetadata::new()); state.add_metadata(ProbabilityMetadata::new());
} }
@ -105,7 +108,7 @@ where
/// Gets the next entry /// Gets the next entry
#[allow(clippy::cast_precision_loss)] #[allow(clippy::cast_precision_loss)]
fn next(&self, state: &mut S) -> Result<usize, Error> { fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
Err(Error::empty(String::from("No entries in corpus"))) Err(Error::empty(String::from("No entries in corpus")))
} else { } else {
@ -127,11 +130,10 @@ where
} }
} }
impl<F, I, S> Default for ProbabilitySamplingScheduler<F, I, S> impl<F, S> Default for ProbabilitySamplingScheduler<F, S>
where where
F: TestcaseScore<I, S>, F: TestcaseScore<S>,
I: Input, S: HasCorpus + HasMetadata + HasRand,
S: HasCorpus<I> + HasMetadata + HasRand,
{ {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
@ -146,7 +148,8 @@ mod tests {
use crate::{ use crate::{
bolts::rands::StdRand, bolts::rands::StdRand,
corpus::{Corpus, InMemoryCorpus, Testcase}, corpus::{Corpus, InMemoryCorpus, Testcase},
inputs::{bytes::BytesInput, Input}, feedbacks::ConstFeedback,
inputs::{bytes::BytesInput, Input, UsesInput},
schedulers::{ProbabilitySamplingScheduler, Scheduler, TestcaseScore}, schedulers::{ProbabilitySamplingScheduler, Scheduler, TestcaseScore},
state::{HasCorpus, HasMetadata, StdState}, state::{HasCorpus, HasMetadata, StdState},
Error, Error,
@ -162,18 +165,17 @@ mod tests {
phantom: PhantomData<I>, phantom: PhantomData<I>,
} }
impl<I, S> TestcaseScore<I, S> for UniformDistribution<I> impl<S> TestcaseScore<S> for UniformDistribution<S::Input>
where where
I: Input, S: HasMetadata + HasCorpus,
S: HasMetadata + HasCorpus<I>,
{ {
fn compute(_: &mut Testcase<I>, _state: &S) -> Result<f64, Error> { fn compute(_: &mut Testcase<S::Input>, _state: &S) -> Result<f64, Error> {
Ok(FACTOR) Ok(FACTOR)
} }
} }
pub type UniformProbabilitySamplingScheduler<I, S> = pub type UniformProbabilitySamplingScheduler<S> =
ProbabilitySamplingScheduler<UniformDistribution<I>, I, S>; ProbabilitySamplingScheduler<UniformDistribution<<S as UsesInput>::Input>, S>;
#[test] #[test]
fn test_prob_sampling() { fn test_prob_sampling() {
@ -182,6 +184,9 @@ mod tests {
let scheduler = UniformProbabilitySamplingScheduler::new(); let scheduler = UniformProbabilitySamplingScheduler::new();
let mut feedback = ConstFeedback::new(false);
let mut objective = ConstFeedback::new(false);
let mut corpus = InMemoryCorpus::new(); let mut corpus = InMemoryCorpus::new();
let t1 = Testcase::with_filename(BytesInput::new(vec![0_u8; 4]), "1".into()); let t1 = Testcase::with_filename(BytesInput::new(vec![0_u8; 4]), "1".into());
let t2 = Testcase::with_filename(BytesInput::new(vec![1_u8; 4]), "2".into()); let t2 = Testcase::with_filename(BytesInput::new(vec![1_u8; 4]), "2".into());
@ -189,8 +194,14 @@ mod tests {
let idx1 = corpus.add(t1).unwrap(); let idx1 = corpus.add(t1).unwrap();
let idx2 = corpus.add(t2).unwrap(); let idx2 = corpus.add(t2).unwrap();
let mut state = let mut state = StdState::new(
StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); rand,
corpus,
InMemoryCorpus::new(),
&mut feedback,
&mut objective,
)
.unwrap();
scheduler.on_add(state.borrow_mut(), idx1).unwrap(); scheduler.on_add(state.borrow_mut(), idx1).unwrap();
scheduler.on_add(state.borrow_mut(), idx2).unwrap(); scheduler.on_add(state.borrow_mut(), idx2).unwrap();
let next_idx1 = scheduler.next(&mut state).unwrap(); let next_idx1 = scheduler.next(&mut state).unwrap();

View File

@ -1,20 +1,35 @@
//! The queue corpus scheduler implements an AFL-like queue mechanism //! The queue corpus scheduler implements an AFL-like queue mechanism
use alloc::borrow::ToOwned; use alloc::borrow::ToOwned;
use core::marker::PhantomData;
use crate::{corpus::Corpus, inputs::Input, schedulers::Scheduler, state::HasCorpus, Error}; use crate::{
corpus::Corpus,
inputs::UsesInput,
schedulers::Scheduler,
state::{HasCorpus, UsesState},
Error,
};
/// Walk the corpus in a queue-like fashion /// Walk the corpus in a queue-like fashion
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct QueueScheduler; pub struct QueueScheduler<S> {
phantom: PhantomData<S>,
}
impl<I, S> Scheduler<I, S> for QueueScheduler impl<S> UsesState for QueueScheduler<S>
where where
S: HasCorpus<I>, S: UsesInput,
I: Input, {
type State = S;
}
impl<S> Scheduler for QueueScheduler<S>
where
S: HasCorpus,
{ {
/// Gets the next entry in the queue /// Gets the next entry in the queue
fn next(&self, state: &mut S) -> Result<usize, Error> { fn next(&self, state: &mut Self::State) -> Result<usize, Error> {
if state.corpus().count() == 0 { if state.corpus().count() == 0 {
Err(Error::empty("No entries in corpus".to_owned())) Err(Error::empty("No entries in corpus".to_owned()))
} else { } else {
@ -34,15 +49,17 @@ where
} }
} }
impl QueueScheduler { impl<S> QueueScheduler<S> {
/// Creates a new `QueueScheduler` /// Creates a new `QueueScheduler`
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self Self {
phantom: PhantomData,
}
} }
} }
impl Default for QueueScheduler { impl<S> Default for QueueScheduler<S> {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
@ -57,6 +74,7 @@ mod tests {
use crate::{ use crate::{
bolts::rands::StdRand, bolts::rands::StdRand,
corpus::{Corpus, OnDiskCorpus, Testcase}, corpus::{Corpus, OnDiskCorpus, Testcase},
feedbacks::ConstFeedback,
inputs::bytes::BytesInput, inputs::bytes::BytesInput,
schedulers::{QueueScheduler, Scheduler}, schedulers::{QueueScheduler, Scheduler},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -79,7 +97,10 @@ mod tests {
OnDiskCorpus::<BytesInput>::new(PathBuf::from("target/.test/fancy/objective/path")) OnDiskCorpus::<BytesInput>::new(PathBuf::from("target/.test/fancy/objective/path"))
.unwrap(); .unwrap();
let mut state = StdState::new(rand, q, objective_q, &mut (), &mut ()).unwrap(); let mut feedback = ConstFeedback::new(false);
let mut objective = ConstFeedback::new(false);
let mut state = StdState::new(rand, q, objective_q, &mut feedback, &mut objective).unwrap();
let next_idx = scheduler.next(&mut state).unwrap(); let next_idx = scheduler.next(&mut state).unwrap();
let filename = state let filename = state

View File

@ -6,7 +6,6 @@ use crate::{
bolts::{HasLen, HasRefCnt}, bolts::{HasLen, HasRefCnt},
corpus::{Corpus, SchedulerTestcaseMetaData, Testcase}, corpus::{Corpus, SchedulerTestcaseMetaData, Testcase},
feedbacks::MapIndexesMetadata, feedbacks::MapIndexesMetadata,
inputs::Input,
schedulers::{ schedulers::{
minimizer::{IsFavoredMetadata, TopRatedsMetadata}, minimizer::{IsFavoredMetadata, TopRatedsMetadata},
powersched::{PowerSchedule, SchedulerMetadata}, powersched::{PowerSchedule, SchedulerMetadata},
@ -16,33 +15,28 @@ use crate::{
}; };
/// Compute the favor factor of a [`Testcase`]. Lower is better. /// Compute the favor factor of a [`Testcase`]. Lower is better.
pub trait TestcaseScore<I, S> pub trait TestcaseScore<S>
where where
I: Input, S: HasMetadata + HasCorpus,
S: HasMetadata + HasCorpus<I>,
{ {
/// Computes the favor factor of a [`Testcase`]. Lower is better. /// Computes the favor factor of a [`Testcase`]. Lower is better.
fn compute(entry: &mut Testcase<I>, state: &S) -> Result<f64, Error>; fn compute(entry: &mut Testcase<S::Input>, state: &S) -> Result<f64, Error>;
} }
/// Multiply the testcase size with the execution time. /// Multiply the testcase size with the execution time.
/// This favors small and quick testcases. /// This favors small and quick testcases.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LenTimeMulTestcaseScore<I, S> pub struct LenTimeMulTestcaseScore<S> {
where phantom: PhantomData<S>,
I: Input + HasLen,
S: HasMetadata + HasCorpus<I>,
{
phantom: PhantomData<(I, S)>,
} }
impl<I, S> TestcaseScore<I, S> for LenTimeMulTestcaseScore<I, S> impl<S> TestcaseScore<S> for LenTimeMulTestcaseScore<S>
where where
I: Input + HasLen, S: HasCorpus + HasMetadata,
S: HasMetadata + HasCorpus<I>, S::Input: HasLen,
{ {
#[allow(clippy::cast_precision_loss, clippy::cast_lossless)] #[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
fn compute(entry: &mut Testcase<I>, _state: &S) -> Result<f64, Error> { fn compute(entry: &mut Testcase<S::Input>, _state: &S) -> Result<f64, Error> {
// TODO maybe enforce entry.exec_time().is_some() // TODO maybe enforce entry.exec_time().is_some()
Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as f64 * entry.cached_len()? as f64) Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as f64 * entry.cached_len()? as f64)
} }
@ -56,18 +50,13 @@ const HAVOC_MAX_MULT: f64 = 64.0;
/// The power assigned to each corpus entry /// The power assigned to each corpus entry
/// This result is used for power scheduling /// This result is used for power scheduling
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CorpusPowerTestcaseScore<I, S> pub struct CorpusPowerTestcaseScore<S> {
where phantom: PhantomData<S>,
I: Input + HasLen,
S: HasMetadata + HasCorpus<I>,
{
phantom: PhantomData<(I, S)>,
} }
impl<I, S> TestcaseScore<I, S> for CorpusPowerTestcaseScore<I, S> impl<S> TestcaseScore<S> for CorpusPowerTestcaseScore<S>
where where
I: Input + HasLen, S: HasCorpus + HasMetadata,
S: HasMetadata + HasCorpus<I>,
{ {
/// Compute the `power` we assign to each corpus entry /// Compute the `power` we assign to each corpus entry
#[allow( #[allow(
@ -76,7 +65,7 @@ where
clippy::cast_sign_loss, clippy::cast_sign_loss,
clippy::cast_lossless clippy::cast_lossless
)] )]
fn compute(entry: &mut Testcase<I>, state: &S) -> Result<f64, Error> { fn compute(entry: &mut Testcase<S::Input>, state: &S) -> Result<f64, Error> {
let psmeta = state let psmeta = state
.metadata() .metadata()
.get::<SchedulerMetadata>() .get::<SchedulerMetadata>()
@ -294,22 +283,17 @@ where
/// The weight for each corpus entry /// The weight for each corpus entry
/// This result is used for corpus scheduling /// This result is used for corpus scheduling
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CorpusWeightTestcaseScore<I, S> pub struct CorpusWeightTestcaseScore<S> {
where phantom: PhantomData<S>,
I: Input + HasLen,
S: HasMetadata + HasCorpus<I>,
{
phantom: PhantomData<(I, S)>,
} }
impl<I, S> TestcaseScore<I, S> for CorpusWeightTestcaseScore<I, S> impl<S> TestcaseScore<S> for CorpusWeightTestcaseScore<S>
where where
I: Input + HasLen, S: HasCorpus + HasMetadata,
S: HasMetadata + HasCorpus<I>,
{ {
/// Compute the `weight` used in weighted corpus entry selection algo /// Compute the `weight` used in weighted corpus entry selection algo
#[allow(clippy::cast_precision_loss, clippy::cast_lossless)] #[allow(clippy::cast_precision_loss, clippy::cast_lossless)]
fn compute(entry: &mut Testcase<I>, state: &S) -> Result<f64, Error> { fn compute(entry: &mut Testcase<S::Input>, state: &S) -> Result<f64, Error> {
let mut weight = 1.0; let mut weight = 1.0;
let psmeta = state let psmeta = state
.metadata() .metadata()

View File

@ -12,13 +12,13 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::rands::Rand, bolts::rands::Rand,
corpus::{Corpus, SchedulerTestcaseMetaData, Testcase}, corpus::{Corpus, SchedulerTestcaseMetaData, Testcase},
inputs::Input, inputs::UsesInput,
schedulers::{ schedulers::{
powersched::{PowerSchedule, SchedulerMetadata}, powersched::{PowerSchedule, SchedulerMetadata},
testcase_score::{CorpusWeightTestcaseScore, TestcaseScore}, testcase_score::{CorpusWeightTestcaseScore, TestcaseScore},
Scheduler, Scheduler,
}, },
state::{HasCorpus, HasMetadata, HasRand}, state::{HasCorpus, HasMetadata, HasRand, UsesState},
Error, Error,
}; };
@ -89,27 +89,25 @@ crate::impl_serdeany!(WeightedScheduleMetadata);
/// A corpus scheduler using power schedules with weighted queue item selection algo. /// A corpus scheduler using power schedules with weighted queue item selection algo.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct WeightedScheduler<F, I, S> { pub struct WeightedScheduler<F, S> {
strat: Option<PowerSchedule>, strat: Option<PowerSchedule>,
phantom: PhantomData<(F, I, S)>, phantom: PhantomData<(F, S)>,
} }
impl<F, I, S> Default for WeightedScheduler<F, I, S> impl<F, S> Default for WeightedScheduler<F, S>
where where
F: TestcaseScore<I, S>, F: TestcaseScore<S>,
I: Input, S: HasCorpus + HasMetadata + HasRand,
S: HasCorpus<I> + HasMetadata + HasRand,
{ {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
} }
impl<F, I, S> WeightedScheduler<F, I, S> impl<F, S> WeightedScheduler<F, S>
where where
F: TestcaseScore<I, S>, F: TestcaseScore<S>,
I: Input, S: HasCorpus + HasMetadata + HasRand,
S: HasCorpus<I> + HasMetadata + HasRand,
{ {
/// Create a new [`WeightedScheduler`] without any scheduling strategy /// Create a new [`WeightedScheduler`] without any scheduling strategy
#[must_use] #[must_use]
@ -219,11 +217,17 @@ where
} }
} }
impl<F, I, S> Scheduler<I, S> for WeightedScheduler<F, I, S> impl<F, S> UsesState for WeightedScheduler<F, S>
where where
F: TestcaseScore<I, S>, S: UsesInput,
S: HasCorpus<I> + HasMetadata + HasRand, {
I: Input, type State = S;
}
impl<F, S> Scheduler for WeightedScheduler<F, S>
where
F: TestcaseScore<S>,
S: HasCorpus + HasMetadata + HasRand,
{ {
/// Add an entry to the corpus and return its index /// Add an entry to the corpus and return its index
fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> { fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> {
@ -264,7 +268,12 @@ where
Ok(()) Ok(())
} }
fn on_replace(&self, state: &mut S, idx: usize, _testcase: &Testcase<I>) -> Result<(), Error> { fn on_replace(
&self,
state: &mut S,
idx: usize,
_testcase: &Testcase<S::Input>,
) -> Result<(), Error> {
// Recreate the alias table // Recreate the alias table
self.on_add(state, idx) self.on_add(state, idx)
} }
@ -273,7 +282,7 @@ where
&self, &self,
state: &mut S, state: &mut S,
_idx: usize, _idx: usize,
_testcase: &Option<Testcase<I>>, _testcase: &Option<Testcase<S::Input>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Recreate the alias table // Recreate the alias table
self.create_alias_table(state)?; self.create_alias_table(state)?;
@ -343,4 +352,4 @@ where
} }
/// The standard corpus weight, same as aflpp /// The standard corpus weight, same as aflpp
pub type StdWeightedScheduler<I, S> = WeightedScheduler<CorpusWeightTestcaseScore<I, S>, I, S>; pub type StdWeightedScheduler<S> = WeightedScheduler<CorpusWeightTestcaseScore<S>, S>;

View File

@ -20,11 +20,11 @@ use crate::{
HasObserverName, HasObserverName,
}, },
fuzzer::Evaluator, fuzzer::Evaluator,
inputs::Input, inputs::UsesInput,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
schedulers::powersched::SchedulerMetadata, schedulers::powersched::SchedulerMetadata,
stages::Stage, stages::Stage,
state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasNamedMetadata}, state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasNamedMetadata, UsesState},
Error, Error,
}; };
@ -63,33 +63,33 @@ impl UnstableEntriesMetadata {
/// The calibration stage will measure the average exec time and the target's stability for this input. /// The calibration stage will measure the average exec time and the target's stability for this input.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CalibrationStage<I, O, OT, S> pub struct CalibrationStage<O, OT, S> {
where
I: Input,
O: MapObserver,
OT: ObserversTuple<I, S>,
S: HasCorpus<I> + HasMetadata + HasNamedMetadata,
{
map_observer_name: String, map_observer_name: String,
map_name: String, map_name: String,
stage_max: usize, stage_max: usize,
track_stability: bool, track_stability: bool,
phantom: PhantomData<(I, O, OT, S)>, phantom: PhantomData<(O, OT, S)>,
} }
const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1 const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1
const CAL_STAGE_MAX: usize = 8; // AFL++'s CAL_CYCLES + 1 const CAL_STAGE_MAX: usize = 8; // AFL++'s CAL_CYCLES + 1
impl<E, EM, I, O, OT, S, Z> Stage<E, EM, S, Z> for CalibrationStage<I, O, OT, S> impl<O, OT, S> UsesState for CalibrationStage<O, OT, S>
where where
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, S: UsesInput,
EM: EventFirer<I>, {
I: Input, type State = S;
}
impl<E, EM, O, OT, Z> Stage<E, EM, Z> for CalibrationStage<O, OT, E::State>
where
E: Executor<EM, Z> + HasObservers<Observers = OT>,
EM: EventFirer<State = E::State>,
O: MapObserver, O: MapObserver,
for<'de> <O as MapObserver>::Entry: Serialize + Deserialize<'de> + 'static, for<'de> <O as MapObserver>::Entry: Serialize + Deserialize<'de> + 'static,
OT: ObserversTuple<I, S>, OT: ObserversTuple<E::State>,
S: HasCorpus<I> + HasMetadata + HasClientPerfMonitor + HasNamedMetadata, E::State: HasCorpus + HasMetadata + HasClientPerfMonitor + HasNamedMetadata,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM, State = E::State>,
{ {
#[inline] #[inline]
#[allow(clippy::let_and_return, clippy::too_many_lines)] #[allow(clippy::let_and_return, clippy::too_many_lines)]
@ -97,7 +97,7 @@ where
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut E::State,
mgr: &mut EM, mgr: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -285,16 +285,15 @@ where
} }
} }
impl<I, O, OT, S> CalibrationStage<I, O, OT, S> impl<O, OT, S> CalibrationStage<O, OT, S>
where where
I: Input,
O: MapObserver, O: MapObserver,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
S: HasCorpus<I> + HasMetadata + HasNamedMetadata, S: HasCorpus + HasMetadata + HasNamedMetadata,
{ {
/// Create a new [`CalibrationStage`]. /// Create a new [`CalibrationStage`].
#[must_use] #[must_use]
pub fn new<N, R>(map_feedback: &MapFeedback<I, N, O, R, S, O::Entry>) -> Self pub fn new<N, R>(map_feedback: &MapFeedback<N, O, R, S, O::Entry>) -> Self
where where
O::Entry: O::Entry:
PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
@ -313,7 +312,7 @@ where
/// Create a new [`CalibrationStage`], but without checking stability. /// Create a new [`CalibrationStage`], but without checking stability.
#[must_use] #[must_use]
pub fn ignore_stability<N, R>(map_feedback: &MapFeedback<I, N, O, R, S, O::Entry>) -> Self pub fn ignore_stability<N, R>(map_feedback: &MapFeedback<N, O, R, S, O::Entry>) -> Self
where where
O::Entry: O::Entry:
PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,

View File

@ -11,38 +11,39 @@ use super::{Stage, TracingStage};
use crate::{ use crate::{
corpus::Corpus, corpus::Corpus,
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
inputs::Input, observers::concolic::ConcolicObserver,
observers::{concolic::ConcolicObserver, ObserversTuple},
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata}, state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata},
Error, Error,
}; };
/// Wraps a [`TracingStage`] to add concolic observing. /// Wraps a [`TracingStage`] to add concolic observing.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ConcolicTracingStage<EM, I, OT, S, TE, Z> pub struct ConcolicTracingStage<EM, TE, Z> {
where inner: TracingStage<EM, TE, Z>,
I: Input,
TE: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasExecutions + HasCorpus<I>,
{
inner: TracingStage<EM, I, OT, S, TE, Z>,
observer_name: String, observer_name: String,
} }
impl<E, EM, I, OT, S, TE, Z> Stage<E, EM, S, Z> for ConcolicTracingStage<EM, I, OT, S, TE, Z> impl<EM, TE, Z> UsesState for ConcolicTracingStage<EM, TE, Z>
where where
I: Input, TE: UsesState,
TE: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, {
OT: ObserversTuple<I, S>, type State = TE::State;
S: HasClientPerfMonitor + HasExecutions + HasCorpus<I>, }
impl<E, EM, TE, Z> Stage<E, EM, Z> for ConcolicTracingStage<EM, TE, Z>
where
E: UsesState<State = TE::State>,
EM: UsesState<State = TE::State>,
TE: Executor<EM, Z> + HasObservers,
TE::State: HasClientPerfMonitor + HasExecutions + HasCorpus,
Z: UsesState<State = TE::State>,
{ {
#[inline] #[inline]
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut TE::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -67,15 +68,9 @@ where
} }
} }
impl<EM, I, OT, S, TE, Z> ConcolicTracingStage<EM, I, OT, S, TE, Z> impl<EM, TE, Z> ConcolicTracingStage<EM, TE, Z> {
where
I: Input,
TE: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasExecutions + HasCorpus<I>,
{
/// Creates a new default tracing stage using the given [`Executor`], observing traces from a [`ConcolicObserver`] with the given name. /// Creates a new default tracing stage using the given [`Executor`], observing traces from a [`ConcolicObserver`] with the given name.
pub fn new(inner: TracingStage<EM, I, OT, S, TE, Z>, observer_name: String) -> Self { pub fn new(inner: TracingStage<EM, TE, Z>, observer_name: String) -> Self {
Self { Self {
inner, inner,
observer_name, observer_name,
@ -85,6 +80,7 @@ where
#[cfg(all(feature = "concolic_mutation", feature = "introspection"))] #[cfg(all(feature = "concolic_mutation", feature = "introspection"))]
use crate::monitors::PerfFeature; use crate::monitors::PerfFeature;
use crate::{bolts::tuples::MatchName, state::UsesState};
#[cfg(feature = "concolic_mutation")] #[cfg(feature = "concolic_mutation")]
use crate::{ use crate::{
inputs::HasBytesVec, inputs::HasBytesVec,
@ -340,27 +336,33 @@ fn generate_mutations(iter: impl Iterator<Item = (SymExprRef, SymExpr)>) -> Vec<
/// A mutational stage that uses Z3 to solve concolic constraints attached to the [`crate::corpus::Testcase`] by the [`ConcolicTracingStage`]. /// A mutational stage that uses Z3 to solve concolic constraints attached to the [`crate::corpus::Testcase`] by the [`ConcolicTracingStage`].
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SimpleConcolicMutationalStage<EM, I, S, Z> pub struct SimpleConcolicMutationalStage<Z> {
where _phantom: PhantomData<Z>,
I: Input,
S: HasClientPerfMonitor + HasExecutions + HasCorpus<I>,
{
_phantom: PhantomData<(EM, I, S, Z)>,
} }
#[cfg(feature = "concolic_mutation")] #[cfg(feature = "concolic_mutation")]
impl<E, EM, I, S, Z> Stage<E, EM, S, Z> for SimpleConcolicMutationalStage<EM, I, S, Z> impl<Z> UsesState for SimpleConcolicMutationalStage<Z>
where where
I: Input + HasBytesVec, Z: UsesState,
S: HasClientPerfMonitor + HasExecutions + HasCorpus<I>, {
Z: Evaluator<E, EM, I, S>, type State = Z::State;
}
#[cfg(feature = "concolic_mutation")]
impl<E, EM, Z> Stage<E, EM, Z> for SimpleConcolicMutationalStage<Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM>,
Z::Input: HasBytesVec,
Z::State: HasClientPerfMonitor + HasExecutions + HasCorpus,
{ {
#[inline] #[inline]
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut Z::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -392,11 +394,7 @@ where
} }
} }
impl<EM, I, S, Z> Default for SimpleConcolicMutationalStage<EM, I, S, Z> impl<Z> Default for SimpleConcolicMutationalStage<Z> {
where
I: Input,
S: HasClientPerfMonitor + HasExecutions + HasCorpus<I>,
{
fn default() -> Self { fn default() -> Self {
Self { Self {
_phantom: PhantomData, _phantom: PhantomData,

View File

@ -1,4 +1,4 @@
//! The tracing stage can trace the target and enrich a testcase with metadata, for example for `CmpLog`. //! The tracing stage can trace the target and enrich a [`crate::corpus::Testcase`] with metadata, for example for `CmpLog`.
use alloc::{ use alloc::{
string::{String, ToString}, string::{String, ToString},
@ -16,12 +16,12 @@ use crate::{
corpus::Corpus, corpus::Corpus,
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
feedbacks::map::MapNoveltiesMetadata, feedbacks::map::MapNoveltiesMetadata,
inputs::{GeneralizedInput, GeneralizedItem, HasBytesVec}, inputs::{GeneralizedInput, GeneralizedItem, HasBytesVec, UsesInput},
mark_feature_time, mark_feature_time,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
stages::Stage, stages::Stage,
start_timer, start_timer,
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata}, state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, UsesState},
Error, Error,
}; };
@ -60,23 +60,32 @@ fn find_next_char(list: &[Option<u8>], mut idx: usize, ch: u8) -> usize {
/// A stage that runs a tracer executor /// A stage that runs a tracer executor
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct GeneralizationStage<EM, O, OT, S, Z> pub struct GeneralizationStage<EM, O, OT, Z> {
where
O: MapObserver,
OT: ObserversTuple<GeneralizedInput, S>,
S: HasClientPerfMonitor + HasExecutions + HasMetadata + HasCorpus<GeneralizedInput>,
{
map_observer_name: String, map_observer_name: String,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(EM, O, OT, S, Z)>, phantom: PhantomData<(EM, O, OT, Z)>,
} }
impl<E, EM, O, OT, S, Z> Stage<E, EM, S, Z> for GeneralizationStage<EM, O, OT, S, Z> impl<EM, O, OT, Z> UsesState for GeneralizationStage<EM, O, OT, Z>
where
EM: UsesState,
EM::State: UsesInput<Input = GeneralizedInput>,
{
type State = EM::State;
}
impl<E, EM, O, Z> Stage<E, EM, Z> for GeneralizationStage<EM, O, E::Observers, Z>
where where
O: MapObserver, O: MapObserver,
E: Executor<EM, GeneralizedInput, S, Z> + HasObservers<GeneralizedInput, OT, S>, E: Executor<EM, Z> + HasObservers,
OT: ObserversTuple<GeneralizedInput, S>, E::Observers: ObserversTuple<E::State>,
S: HasClientPerfMonitor + HasExecutions + HasMetadata + HasCorpus<GeneralizedInput>, E::State: UsesInput<Input = GeneralizedInput>
+ HasClientPerfMonitor
+ HasExecutions
+ HasMetadata
+ HasCorpus,
EM: UsesState<State = E::State>,
Z: UsesState<State = E::State>,
{ {
#[inline] #[inline]
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
@ -84,7 +93,7 @@ where
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut E::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -347,11 +356,16 @@ where
} }
} }
impl<EM, O, OT, S, Z> GeneralizationStage<EM, O, OT, S, Z> impl<EM, O, OT, Z> GeneralizationStage<EM, O, OT, Z>
where where
EM: UsesState,
O: MapObserver, O: MapObserver,
OT: ObserversTuple<GeneralizedInput, S>, OT: ObserversTuple<EM::State>,
S: HasClientPerfMonitor + HasExecutions + HasMetadata + HasCorpus<GeneralizedInput>, EM::State: UsesInput<Input = GeneralizedInput>
+ HasClientPerfMonitor
+ HasExecutions
+ HasMetadata
+ HasCorpus,
{ {
/// Create a new [`GeneralizationStage`]. /// Create a new [`GeneralizationStage`].
#[must_use] #[must_use]
@ -375,13 +389,14 @@ where
&self, &self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut EM::State,
manager: &mut EM, manager: &mut EM,
novelties: &[usize], novelties: &[usize],
input: &GeneralizedInput, input: &GeneralizedInput,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
E: Executor<EM, GeneralizedInput, S, Z> + HasObservers<GeneralizedInput, OT, S>, E: Executor<EM, Z> + HasObservers<Observers = OT, State = EM::State>,
Z: UsesState<State = EM::State>,
{ {
start_timer!(state); start_timer!(state);
executor.observers_mut().pre_exec_all(state, input)?; executor.observers_mut().pre_exec_all(state, input)?;
@ -418,7 +433,7 @@ where
&self, &self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut EM::State,
manager: &mut EM, manager: &mut EM,
payload: &mut Vec<Option<u8>>, payload: &mut Vec<Option<u8>>,
novelties: &[usize], novelties: &[usize],
@ -426,7 +441,8 @@ where
split_char: u8, split_char: u8,
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<EM, GeneralizedInput, S, Z> + HasObservers<GeneralizedInput, OT, S>, E: Executor<EM, Z> + HasObservers<Observers = OT, State = EM::State>,
Z: UsesState<State = EM::State>,
{ {
let mut start = 0; let mut start = 0;
while start < payload.len() { while start < payload.len() {
@ -460,7 +476,7 @@ where
&self, &self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut EM::State,
manager: &mut EM, manager: &mut EM,
payload: &mut Vec<Option<u8>>, payload: &mut Vec<Option<u8>>,
novelties: &[usize], novelties: &[usize],
@ -468,7 +484,8 @@ where
closing_char: u8, closing_char: u8,
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<EM, GeneralizedInput, S, Z> + HasObservers<GeneralizedInput, OT, S>, E: Executor<EM, Z> + HasObservers<Observers = OT, State = EM::State>,
Z: UsesState<State = EM::State>,
{ {
let mut index = 0; let mut index = 0;
while index < payload.len() { while index < payload.len() {

View File

@ -48,29 +48,40 @@ use self::push::PushStage;
use crate::{ use crate::{
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter}, events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
inputs::Input, inputs::UsesInput,
observers::ObserversTuple, observers::ObserversTuple,
schedulers::Scheduler, schedulers::Scheduler,
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasRand}, state::{HasClientPerfMonitor, HasExecutions, HasMetadata, HasRand, UsesState},
Error, EvaluatorObservers, ExecutesInput, ExecutionProcessor, HasScheduler, Error, EvaluatorObservers, ExecutesInput, ExecutionProcessor, HasScheduler,
}; };
/// 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, Z>: UsesState
where
E: UsesState<State = Self::State>,
EM: UsesState<State = Self::State>,
Z: UsesState<State = Self::State>,
{
/// Run the stage /// Run the stage
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut Self::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error>; ) -> Result<(), Error>;
} }
/// A tuple holding all `Stages` used for fuzzing. /// A tuple holding all `Stages` used for fuzzing.
pub trait StagesTuple<E, EM, S, Z> { pub trait StagesTuple<E, EM, S, Z>
where
E: UsesState<State = S>,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
S: UsesInput,
{
/// Performs all `Stages` in this tuple /// Performs all `Stages` in this tuple
fn perform_all( fn perform_all(
&mut self, &mut self,
@ -82,7 +93,13 @@ pub trait StagesTuple<E, EM, S, Z> {
) -> Result<(), Error>; ) -> Result<(), Error>;
} }
impl<E, EM, S, Z> StagesTuple<E, EM, S, Z> for () { impl<E, EM, S, Z> StagesTuple<E, EM, S, Z> for ()
where
E: UsesState<State = S>,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
S: UsesInput,
{
fn perform_all( fn perform_all(
&mut self, &mut self,
_: &mut Z, _: &mut Z,
@ -95,16 +112,19 @@ impl<E, EM, S, Z> StagesTuple<E, EM, S, Z> for () {
} }
} }
impl<Head, Tail, E, EM, S, Z> StagesTuple<E, EM, S, Z> for (Head, Tail) impl<Head, Tail, E, EM, Z> StagesTuple<E, EM, Head::State, Z> for (Head, Tail)
where where
Head: Stage<E, EM, S, Z>, Head: Stage<E, EM, Z>,
Tail: StagesTuple<E, EM, S, Z>, Tail: StagesTuple<E, EM, Head::State, Z>,
E: UsesState<State = Head::State>,
EM: UsesState<State = Head::State>,
Z: UsesState<State = Head::State>,
{ {
fn perform_all( fn perform_all(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut Head::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -120,23 +140,35 @@ where
/// A [`Stage`] that will call a closure /// A [`Stage`] that will call a closure
#[derive(Debug)] #[derive(Debug)]
pub struct ClosureStage<CB, E, EM, S, Z> pub struct ClosureStage<CB, E, EM, Z>
where where
CB: FnMut(&mut Z, &mut E, &mut S, &mut EM, usize) -> Result<(), Error>, CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>,
E: UsesState,
{ {
closure: CB, closure: CB,
phantom: PhantomData<(E, EM, S, Z)>, phantom: PhantomData<(E, EM, Z)>,
} }
impl<CB, E, EM, S, Z> Stage<E, EM, S, Z> for ClosureStage<CB, E, EM, S, Z> impl<CB, E, EM, Z> UsesState for ClosureStage<CB, E, EM, Z>
where where
CB: FnMut(&mut Z, &mut E, &mut S, &mut EM, usize) -> Result<(), Error>, CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>,
E: UsesState,
{
type State = E::State;
}
impl<CB, E, EM, Z> Stage<E, EM, Z> for ClosureStage<CB, E, EM, Z>
where
CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>,
E: UsesState,
EM: UsesState<State = E::State>,
Z: UsesState<State = E::State>,
{ {
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut E::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -145,9 +177,10 @@ where
} }
/// A stage that takes a closure /// A stage that takes a closure
impl<CB, E, EM, S, Z> ClosureStage<CB, E, EM, S, Z> impl<CB, E, EM, Z> ClosureStage<CB, E, EM, Z>
where where
CB: FnMut(&mut Z, &mut E, &mut S, &mut EM, usize) -> Result<(), Error>, CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>,
E: UsesState,
{ {
/// Create a new [`ClosureStage`] /// Create a new [`ClosureStage`]
#[must_use] #[must_use]
@ -159,9 +192,10 @@ where
} }
} }
impl<CB, E, EM, S, Z> From<CB> for ClosureStage<CB, E, EM, S, Z> impl<CB, E, EM, Z> From<CB> for ClosureStage<CB, E, EM, Z>
where where
CB: FnMut(&mut Z, &mut E, &mut S, &mut EM, usize) -> Result<(), Error>, CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>,
E: UsesState,
{ {
#[must_use] #[must_use]
fn from(closure: CB) -> Self { fn from(closure: CB) -> Self {
@ -172,30 +206,12 @@ where
/// Allows us to use a [`push::PushStage`] as a normal [`Stage`] /// Allows us to use a [`push::PushStage`] as a normal [`Stage`]
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
#[derive(Debug)] #[derive(Debug)]
pub struct PushStageAdapter<CS, EM, I, OT, PS, S, Z> pub struct PushStageAdapter<CS, EM, OT, PS, Z> {
where
CS: Scheduler<I, S>,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId + ProgressReporter<I>,
I: Input,
OT: ObserversTuple<I, S>,
PS: PushStage<CS, EM, I, OT, S, Z>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasExecutions + HasMetadata,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{
push_stage: PS, push_stage: PS,
phantom: PhantomData<(CS, EM, I, OT, S, Z)>, phantom: PhantomData<(CS, EM, OT, Z)>,
} }
impl<CS, EM, I, OT, PS, S, Z> PushStageAdapter<CS, EM, I, OT, PS, S, Z> impl<CS, EM, OT, PS, Z> PushStageAdapter<CS, EM, OT, PS, Z> {
where
CS: Scheduler<I, S>,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId + ProgressReporter<I>,
I: Input,
OT: ObserversTuple<I, S>,
PS: PushStage<CS, EM, I, OT, S, Z>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasExecutions + HasMetadata,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{
/// Create a new [`PushStageAdapter`], wrapping the given [`PushStage`] /// Create a new [`PushStageAdapter`], wrapping the given [`PushStage`]
/// to be used as a normal [`Stage`] /// to be used as a normal [`Stage`]
#[must_use] #[must_use]
@ -207,25 +223,34 @@ where
} }
} }
impl<CS, E, EM, I, OT, PS, S, Z> Stage<E, EM, S, Z> for PushStageAdapter<CS, EM, I, OT, PS, S, Z> impl<CS, EM, OT, PS, Z> UsesState for PushStageAdapter<CS, EM, OT, PS, Z>
where where
CS: Scheduler<I, S>, CS: UsesState,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, {
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId + ProgressReporter<I>, type State = CS::State;
I: Input, }
OT: ObserversTuple<I, S>,
PS: PushStage<CS, EM, I, OT, S, Z>, impl<CS, E, EM, OT, PS, Z> Stage<E, EM, Z> for PushStageAdapter<CS, EM, OT, PS, Z>
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasExecutions + HasMetadata, where
Z: ExecutesInput<I, OT, S, Z> CS: Scheduler,
+ ExecutionProcessor<I, OT, S> CS::State: HasClientPerfMonitor + HasExecutions + HasMetadata + HasRand,
+ EvaluatorObservers<I, OT, S> E: Executor<EM, Z> + HasObservers<Observers = OT, State = CS::State>,
+ HasScheduler<CS, I, S>, EM: EventFirer<State = CS::State>
+ EventRestarter
+ HasEventManagerId
+ ProgressReporter<State = CS::State>,
OT: ObserversTuple<CS::State>,
PS: PushStage<CS, EM, OT, Z>,
Z: ExecutesInput<E, EM, State = CS::State>
+ ExecutionProcessor<OT, State = CS::State>
+ EvaluatorObservers<OT>
+ HasScheduler<CS>,
{ {
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut CS::State,
event_mgr: &mut EM, event_mgr: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -281,20 +306,19 @@ impl From<bool> for SkippableStageDecision {
/// The [`SkippableStage`] wraps any [`Stage`] so that it can be skipped, according to a condition. /// The [`SkippableStage`] wraps any [`Stage`] so that it can be skipped, according to a condition.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SkippableStage<CD, E, EM, S, ST, Z> pub struct SkippableStage<CD, E, EM, ST, Z> {
where
CD: FnMut(&mut S) -> SkippableStageDecision,
ST: Stage<E, EM, S, Z>,
{
wrapped_stage: ST, wrapped_stage: ST,
condition: CD, condition: CD,
phantom: PhantomData<(E, EM, S, Z)>, phantom: PhantomData<(E, EM, Z)>,
} }
impl<CD, E, EM, S, ST, Z> SkippableStage<CD, E, EM, S, ST, Z> impl<CD, E, EM, ST, Z> SkippableStage<CD, E, EM, ST, Z>
where where
CD: FnMut(&mut S) -> SkippableStageDecision, CD: FnMut(&mut ST::State) -> SkippableStageDecision,
ST: Stage<E, EM, S, Z>, ST: Stage<E, EM, Z>,
E: UsesState<State = ST::State>,
EM: UsesState<State = ST::State>,
Z: UsesState<State = ST::State>,
{ {
/// Create a new [`SkippableStage`] /// Create a new [`SkippableStage`]
pub fn new(wrapped_stage: ST, condition: CD) -> Self { pub fn new(wrapped_stage: ST, condition: CD) -> Self {
@ -306,10 +330,24 @@ where
} }
} }
impl<CD, E, EM, S, ST, Z> Stage<E, EM, S, Z> for SkippableStage<CD, E, EM, S, ST, Z> impl<CD, E, EM, ST, Z> UsesState for SkippableStage<CD, E, EM, ST, Z>
where where
CD: FnMut(&mut S) -> SkippableStageDecision, CD: FnMut(&mut ST::State) -> SkippableStageDecision,
ST: Stage<E, EM, S, Z>, ST: Stage<E, EM, Z>,
E: UsesState<State = ST::State>,
EM: UsesState<State = ST::State>,
Z: UsesState<State = ST::State>,
{
type State = ST::State;
}
impl<CD, E, EM, ST, Z> Stage<E, EM, Z> for SkippableStage<CD, E, EM, ST, Z>
where
CD: FnMut(&mut ST::State) -> SkippableStageDecision,
ST: Stage<E, EM, Z>,
E: UsesState<State = ST::State>,
EM: UsesState<State = ST::State>,
Z: UsesState<State = ST::State>,
{ {
/// Run the stage /// Run the stage
#[inline] #[inline]
@ -317,7 +355,7 @@ where
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut ST::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -344,7 +382,10 @@ pub mod pybind {
executors::pybind::PythonExecutor, executors::pybind::PythonExecutor,
fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper}, fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper},
stages::{mutational::pybind::PythonStdMutationalStage, Stage, StagesTuple}, stages::{mutational::pybind::PythonStdMutationalStage, Stage, StagesTuple},
state::pybind::{PythonStdState, PythonStdStateWrapper}, state::{
pybind::{PythonStdState, PythonStdStateWrapper},
UsesState,
},
Error, Error,
}; };
@ -360,7 +401,11 @@ pub mod pybind {
} }
} }
impl Stage<PythonExecutor, PythonEventManager, PythonStdState, PythonStdFuzzer> for PyObjectStage { impl UsesState for PyObjectStage {
type State = PythonStdState;
}
impl Stage<PythonExecutor, PythonEventManager, PythonStdFuzzer> for PyObjectStage {
#[inline] #[inline]
fn perform( fn perform(
&mut self, &mut self,
@ -444,7 +489,11 @@ pub mod pybind {
} }
} }
impl Stage<PythonExecutor, PythonEventManager, PythonStdState, PythonStdFuzzer> for PythonStage { impl UsesState for PythonStage {
type State = PythonStdState;
}
impl Stage<PythonExecutor, PythonEventManager, PythonStdFuzzer> for PythonStage {
#[inline] #[inline]
#[allow(clippy::let_and_return)] #[allow(clippy::let_and_return)]
fn perform( fn perform(

View File

@ -9,12 +9,11 @@ use crate::{
bolts::rands::Rand, bolts::rands::Rand,
corpus::Corpus, corpus::Corpus,
fuzzer::Evaluator, fuzzer::Evaluator,
inputs::Input,
mark_feature_time, mark_feature_time,
mutators::Mutator, mutators::Mutator,
stages::Stage, stages::Stage,
start_timer, start_timer,
state::{HasClientPerfMonitor, HasCorpus, HasRand}, state::{HasClientPerfMonitor, HasCorpus, HasRand, UsesState},
Error, Error,
}; };
@ -23,12 +22,13 @@ use crate::{
/// 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<E, EM, I, M, S, Z>: Stage<E, EM, S, Z> pub trait MutationalStage<E, EM, M, Z>: Stage<E, EM, Z>
where where
M: Mutator<I, S>, E: UsesState<State = Self::State>,
I: Input, M: Mutator<Self::State>,
S: HasClientPerfMonitor + HasCorpus<I>, EM: UsesState<State = Self::State>,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM, State = Self::State>,
Self::State: HasClientPerfMonitor + HasCorpus,
{ {
/// The mutator registered for this stage /// The mutator registered for this stage
fn mutator(&self) -> &M; fn mutator(&self) -> &M;
@ -37,7 +37,7 @@ where
fn mutator_mut(&mut self) -> &mut M; fn mutator_mut(&mut self) -> &mut M;
/// Gets the number of iterations this mutator should run for. /// Gets the number of iterations this mutator should run for.
fn iterations(&self, state: &mut S, corpus_idx: usize) -> Result<usize, Error>; fn iterations(&self, state: &mut Z::State, corpus_idx: usize) -> Result<usize, Error>;
/// Runs this (mutational) stage for the given testcase /// Runs this (mutational) stage for the given testcase
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
@ -45,7 +45,7 @@ where
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut Z::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -82,24 +82,19 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
/// The default mutational stage /// The default mutational stage
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StdMutationalStage<E, EM, I, M, S, Z> pub struct StdMutationalStage<E, EM, M, Z> {
where
M: Mutator<I, S>,
I: Input,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand,
Z: Evaluator<E, EM, I, S>,
{
mutator: M, mutator: M,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, I, S, Z)>, phantom: PhantomData<(E, EM, Z)>,
} }
impl<E, EM, I, M, S, Z> MutationalStage<E, EM, I, M, S, Z> for StdMutationalStage<E, EM, I, M, S, Z> impl<E, EM, M, Z> MutationalStage<E, EM, M, Z> for StdMutationalStage<E, EM, M, Z>
where where
M: Mutator<I, S>, E: UsesState<State = Z::State>,
I: Input, EM: UsesState<State = Z::State>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand, M: Mutator<Z::State>,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{ {
/// The mutator, added to this stage /// The mutator, added to this stage
#[inline] #[inline]
@ -114,17 +109,29 @@ where
} }
/// Gets the number of iterations as a random number /// Gets the number of iterations as a random number
fn iterations(&self, state: &mut S, _corpus_idx: usize) -> Result<usize, Error> { fn iterations(&self, state: &mut Z::State, _corpus_idx: usize) -> Result<usize, Error> {
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize) Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize)
} }
} }
impl<E, EM, I, M, S, Z> Stage<E, EM, S, Z> for StdMutationalStage<E, EM, I, M, S, Z> impl<E, EM, M, Z> UsesState for StdMutationalStage<E, EM, M, Z>
where where
M: Mutator<I, S>, E: UsesState<State = Z::State>,
I: Input, EM: UsesState<State = Z::State>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand, M: Mutator<Z::State>,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{
type State = Z::State;
}
impl<E, EM, M, Z> Stage<E, EM, Z> for StdMutationalStage<E, EM, M, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
M: Mutator<Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{ {
#[inline] #[inline]
#[allow(clippy::let_and_return)] #[allow(clippy::let_and_return)]
@ -132,7 +139,7 @@ where
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut Z::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -145,12 +152,13 @@ where
} }
} }
impl<E, EM, I, M, S, Z> StdMutationalStage<E, EM, I, M, S, Z> impl<E, EM, M, Z> StdMutationalStage<E, EM, M, Z>
where where
M: Mutator<I, S>, E: UsesState<State = Z::State>,
I: Input, EM: UsesState<State = Z::State>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand, M: Mutator<Z::State>,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand,
{ {
/// Creates a new default mutational stage /// Creates a new default mutational stage
pub fn new(mutator: M) -> Self { pub fn new(mutator: M) -> Self {
@ -171,10 +179,8 @@ pub mod pybind {
events::pybind::PythonEventManager, events::pybind::PythonEventManager,
executors::pybind::PythonExecutor, executors::pybind::PythonExecutor,
fuzzer::pybind::PythonStdFuzzer, fuzzer::pybind::PythonStdFuzzer,
inputs::BytesInput,
mutators::pybind::PythonMutator, mutators::pybind::PythonMutator,
stages::{pybind::PythonStage, StdMutationalStage}, stages::{pybind::PythonStage, StdMutationalStage},
state::pybind::PythonStdState,
}; };
#[pyclass(unsendable, name = "StdMutationalStage")] #[pyclass(unsendable, name = "StdMutationalStage")]
@ -182,14 +188,8 @@ pub mod pybind {
/// Python class for StdMutationalStage /// Python class for StdMutationalStage
pub struct PythonStdMutationalStage { pub struct PythonStdMutationalStage {
/// Rust wrapped StdMutationalStage object /// Rust wrapped StdMutationalStage object
pub inner: StdMutationalStage< pub inner:
PythonExecutor, StdMutationalStage<PythonExecutor, PythonEventManager, PythonMutator, PythonStdFuzzer>,
PythonEventManager,
BytesInput,
PythonMutator,
PythonStdState,
PythonStdFuzzer,
>,
} }
#[pymethods] #[pymethods]

View File

@ -5,26 +5,42 @@ use alloc::{boxed::Box, vec::Vec};
use crate::{ use crate::{
bolts::anymap::AsAny, bolts::anymap::AsAny,
stages::{Stage, StagesTuple}, stages::{Stage, StagesTuple},
state::UsesState,
Error, Error,
}; };
/// Combine `Stage` and `AsAny` /// Combine `Stage` and `AsAny`
pub trait AnyStage<E, EM, S, Z>: Stage<E, EM, S, Z> + AsAny {} pub trait AnyStage<E, EM, Z>: Stage<E, EM, Z> + AsAny
where
E: UsesState<State = Self::State>,
EM: UsesState<State = Self::State>,
Z: UsesState<State = Self::State>,
{
}
/// An owned list of `Observer` trait objects /// An owned list of `Observer` trait objects
#[derive(Default)] #[derive(Default)]
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub struct StagesOwnedList<E, EM, S, Z> { pub struct StagesOwnedList<E, EM, Z>
where
E: UsesState,
{
/// The named trait objects map /// The named trait objects map
pub list: Vec<Box<dyn AnyStage<E, EM, S, Z>>>, #[allow(clippy::type_complexity)]
pub list: Vec<Box<dyn AnyStage<E, EM, Z, State = E::State, Input = E::Input>>>,
} }
impl<E, EM, S, Z> StagesTuple<E, EM, S, Z> for StagesOwnedList<E, EM, S, Z> { impl<E, EM, Z> StagesTuple<E, EM, E::State, Z> for StagesOwnedList<E, EM, Z>
where
E: UsesState,
EM: UsesState<State = E::State>,
Z: UsesState<State = E::State>,
{
fn perform_all( fn perform_all(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut E::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -35,10 +51,14 @@ impl<E, EM, S, Z> StagesTuple<E, EM, S, Z> for StagesOwnedList<E, EM, S, Z> {
} }
} }
impl<E, EM, S, Z> StagesOwnedList<E, EM, S, Z> { impl<E, EM, Z> StagesOwnedList<E, EM, Z>
where
E: UsesState,
{
/// Create a new instance /// Create a new instance
#[must_use] #[must_use]
pub fn new(list: Vec<Box<dyn AnyStage<E, EM, S, Z>>>) -> Self { #[allow(clippy::type_complexity)]
pub fn new(list: Vec<Box<dyn AnyStage<E, EM, Z, Input = E::Input, State = E::State>>>) -> Self {
Self { list } Self { list }
} }
} }

View File

@ -4,49 +4,45 @@ use alloc::string::{String, ToString};
use core::{fmt::Debug, marker::PhantomData}; use core::{fmt::Debug, marker::PhantomData};
use crate::{ use crate::{
bolts::tuples::MatchName,
corpus::{Corpus, SchedulerTestcaseMetaData}, corpus::{Corpus, SchedulerTestcaseMetaData},
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
fuzzer::Evaluator, fuzzer::Evaluator,
inputs::Input,
mutators::Mutator, mutators::Mutator,
observers::{MapObserver, ObserversTuple}, observers::MapObserver,
schedulers::{ schedulers::{
powersched::SchedulerMetadata, testcase_score::CorpusPowerTestcaseScore, TestcaseScore, powersched::SchedulerMetadata, testcase_score::CorpusPowerTestcaseScore, TestcaseScore,
}, },
stages::{MutationalStage, Stage}, stages::{MutationalStage, Stage},
state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand}, state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState},
Error, Error,
}; };
/// The mutational stage using power schedules /// The mutational stage using power schedules
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PowerMutationalStage<E, F, EM, I, M, O, OT, S, Z> pub struct PowerMutationalStage<E, F, EM, M, O, Z> {
where
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
F: TestcaseScore<I, S>,
I: Input,
M: Mutator<I, S>,
O: MapObserver,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata,
Z: Evaluator<E, EM, I, S>,
{
map_observer_name: String, map_observer_name: String,
mutator: M, mutator: M,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(E, F, EM, I, O, OT, S, Z)>, phantom: PhantomData<(E, F, EM, O, Z)>,
} }
impl<E, F, EM, I, M, O, OT, S, Z> MutationalStage<E, EM, I, M, S, Z> impl<E, F, EM, M, O, Z> UsesState for PowerMutationalStage<E, F, EM, M, O, Z>
for PowerMutationalStage<E, F, EM, I, M, O, OT, S, Z>
where where
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, E: UsesState,
F: TestcaseScore<I, S>, {
I: Input, type State = E::State;
M: Mutator<I, S>, }
impl<E, F, EM, M, O, Z> MutationalStage<E, EM, M, Z> for PowerMutationalStage<E, F, EM, M, O, Z>
where
E: Executor<EM, Z> + HasObservers,
EM: UsesState<State = E::State>,
F: TestcaseScore<E::State>,
M: Mutator<E::State>,
O: MapObserver, O: MapObserver,
OT: ObserversTuple<I, S>, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata + HasRand, Z: Evaluator<E, EM, State = E::State>,
Z: Evaluator<E, EM, I, S>,
{ {
/// The mutator, added to this stage /// The mutator, added to this stage
#[inline] #[inline]
@ -62,7 +58,7 @@ where
/// Gets the number of iterations as a random number /// Gets the number of iterations as a random number
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
fn iterations(&self, state: &mut S, corpus_idx: usize) -> Result<usize, Error> { fn iterations(&self, state: &mut E::State, corpus_idx: usize) -> Result<usize, Error> {
// Update handicap // Update handicap
let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut(); let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut();
let score = F::compute(&mut *testcase, state)? as usize; let score = F::compute(&mut *testcase, state)? as usize;
@ -75,7 +71,7 @@ where
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut E::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -129,17 +125,15 @@ where
} }
} }
impl<E, F, EM, I, M, O, OT, S, Z> Stage<E, EM, S, Z> impl<E, F, EM, M, O, Z> Stage<E, EM, Z> for PowerMutationalStage<E, F, EM, M, O, Z>
for PowerMutationalStage<E, F, EM, I, M, O, OT, S, Z>
where where
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, E: Executor<EM, Z> + HasObservers,
F: TestcaseScore<I, S>, EM: UsesState<State = E::State>,
I: Input, F: TestcaseScore<E::State>,
M: Mutator<I, S>, M: Mutator<E::State>,
O: MapObserver, O: MapObserver,
OT: ObserversTuple<I, S>, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata + HasRand, Z: Evaluator<E, EM, State = E::State>,
Z: Evaluator<E, EM, I, S>,
{ {
#[inline] #[inline]
#[allow(clippy::let_and_return)] #[allow(clippy::let_and_return)]
@ -147,7 +141,7 @@ where
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut E::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -156,16 +150,15 @@ where
} }
} }
impl<E, F, EM, I, M, O, OT, S, Z> PowerMutationalStage<E, F, EM, I, M, O, OT, S, Z> impl<E, F, EM, M, O, Z> PowerMutationalStage<E, F, EM, M, O, Z>
where where
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, E: Executor<EM, Z> + HasObservers,
F: TestcaseScore<I, S>, EM: UsesState<State = E::State>,
I: Input, F: TestcaseScore<E::State>,
M: Mutator<I, S>, M: Mutator<E::State>,
O: MapObserver, O: MapObserver,
OT: ObserversTuple<I, S>, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata, Z: Evaluator<E, EM, State = E::State>,
Z: Evaluator<E, EM, I, S>,
{ {
/// Creates a new [`PowerMutationalStage`] /// Creates a new [`PowerMutationalStage`]
pub fn new(mutator: M, map_observer_name: &O) -> Self { pub fn new(mutator: M, map_observer_name: &O) -> Self {
@ -178,5 +171,5 @@ where
} }
/// The standard powerscheduling stage /// The standard powerscheduling stage
pub type StdPowerMutationalStage<E, EM, I, M, O, OT, S, Z> = pub type StdPowerMutationalStage<E, EM, M, O, Z> =
PowerMutationalStage<E, CorpusPowerTestcaseScore<I, S>, EM, I, M, O, OT, S, Z>; PowerMutationalStage<E, CorpusPowerTestcaseScore<<E as UsesState>::State>, EM, M, O, Z>;

View File

@ -19,10 +19,10 @@ use crate::{
bolts::current_time, bolts::current_time,
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter}, events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
executors::ExitKind, executors::ExitKind,
inputs::Input, inputs::UsesInput,
observers::ObserversTuple, observers::ObserversTuple,
schedulers::Scheduler, schedulers::Scheduler,
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasRand}, state::{HasClientPerfMonitor, HasExecutions, HasMetadata, HasRand},
Error, EvaluatorObservers, ExecutionProcessor, HasScheduler, Error, EvaluatorObservers, ExecutionProcessor, HasScheduler,
}; };
@ -32,38 +32,36 @@ const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15);
// The shared state for all [`PushStage`]s // The shared state for all [`PushStage`]s
/// Should be stored inside a `[Rc<RefCell<_>>`] /// Should be stored inside a `[Rc<RefCell<_>>`]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PushStageSharedState<CS, EM, I, OT, S, Z> pub struct PushStageSharedState<CS, EM, OT, Z>
where where
CS: Scheduler<I, S>, CS: Scheduler,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
I: Input, OT: ObserversTuple<CS::State>,
OT: ObserversTuple<I, S>, CS::State: HasClientPerfMonitor + HasRand,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand, Z: ExecutionProcessor<OT, State = CS::State> + EvaluatorObservers<OT> + HasScheduler<CS>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{ {
/// The [`crate::state::State`] /// The [`crate::state::State`]
pub state: S, pub state: CS::State,
/// The [`crate::fuzzer::Fuzzer`] instance /// The [`crate::fuzzer::Fuzzer`] instance
pub fuzzer: Z, pub fuzzer: Z,
/// The [`crate::events::EventManager`] /// The [`crate::events::EventManager`]
pub event_mgr: EM, pub event_mgr: EM,
/// The [`crate::observers::ObserversTuple`] /// The [`crate::observers::ObserversTuple`]
pub observers: OT, pub observers: OT,
phantom: PhantomData<(CS, I, OT, S, Z)>, phantom: PhantomData<(CS, Z)>,
} }
impl<CS, EM, I, OT, S, Z> PushStageSharedState<CS, EM, I, OT, S, Z> impl<CS, EM, OT, Z> PushStageSharedState<CS, EM, OT, Z>
where where
CS: Scheduler<I, S>, CS: Scheduler,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
I: Input, OT: ObserversTuple<CS::State>,
OT: ObserversTuple<I, S>, CS::State: HasClientPerfMonitor + HasRand,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand, Z: ExecutionProcessor<OT, State = CS::State> + EvaluatorObservers<OT> + HasScheduler<CS>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{ {
/// Create a new `PushStageSharedState` that can be used by all [`PushStage`]s /// Create a new `PushStageSharedState` that can be used by all [`PushStage`]s
#[must_use] #[must_use]
pub fn new(fuzzer: Z, state: S, observers: OT, event_mgr: EM) -> Self { pub fn new(fuzzer: Z, state: CS::State, observers: OT, event_mgr: EM) -> Self {
Self { Self {
state, state,
fuzzer, fuzzer,
@ -76,14 +74,13 @@ where
/// Helper class for the [`PushStage`] trait, taking care of borrowing the shared state /// Helper class for the [`PushStage`] trait, taking care of borrowing the shared state
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PushStageHelper<CS, EM, I, OT, S, Z> pub struct PushStageHelper<CS, EM, OT, Z>
where where
CS: Scheduler<I, S>, CS: Scheduler,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
I: Input, OT: ObserversTuple<CS::State>,
OT: ObserversTuple<I, S>, CS::State: HasClientPerfMonitor + HasRand,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand, Z: ExecutionProcessor<OT, State = CS::State> + EvaluatorObservers<OT> + HasScheduler<CS>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{ {
/// If this stage has already been initalized. /// If this stage has already been initalized.
/// This gets reset to `false` after one iteration of the stage is done. /// This gets reset to `false` after one iteration of the stage is done.
@ -92,7 +89,7 @@ where
pub last_monitor_time: Duration, pub last_monitor_time: Duration,
/// The shared state, keeping track of the corpus and the fuzzer /// The shared state, keeping track of the corpus and the fuzzer
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, I, OT, S, Z>>>>, pub shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, OT, Z>>>>,
/// If the last iteration failed /// If the last iteration failed
pub errored: bool, pub errored: bool,
@ -100,27 +97,26 @@ where
pub current_corpus_idx: Option<usize>, pub current_corpus_idx: Option<usize>,
/// The input we just ran /// The input we just ran
pub current_input: Option<I>, // Todo: Get rid of copy pub current_input: Option<<CS::State as UsesInput>::Input>, // Todo: Get rid of copy
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(CS, (), EM, I, OT, S, Z)>, phantom: PhantomData<(CS, EM, OT, Z)>,
exit_kind: Rc<Cell<Option<ExitKind>>>, exit_kind: Rc<Cell<Option<ExitKind>>>,
} }
impl<CS, EM, I, OT, S, Z> PushStageHelper<CS, EM, I, OT, S, Z> impl<CS, EM, OT, Z> PushStageHelper<CS, EM, OT, Z>
where where
CS: Scheduler<I, S>, CS: Scheduler,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
I: Input, OT: ObserversTuple<CS::State>,
OT: ObserversTuple<I, S>, CS::State: HasClientPerfMonitor + HasRand,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand, Z: ExecutionProcessor<OT, State = CS::State> + EvaluatorObservers<OT> + HasScheduler<CS>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{ {
/// Create a new [`PushStageHelper`] /// Create a new [`PushStageHelper`]
#[must_use] #[must_use]
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn new( pub fn new(
shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, I, OT, S, Z>>>>, shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, OT, Z>>>>,
exit_kind_ref: Rc<Cell<Option<ExitKind>>>, exit_kind_ref: Rc<Cell<Option<ExitKind>>>,
) -> Self { ) -> Self {
Self { Self {
@ -137,14 +133,14 @@ where
/// Sets the shared state for this helper (and all other helpers owning the same [`RefCell`]) /// Sets the shared state for this helper (and all other helpers owning the same [`RefCell`])
#[inline] #[inline]
pub fn set_shared_state(&mut self, shared_state: PushStageSharedState<CS, EM, I, OT, S, Z>) { pub fn set_shared_state(&mut self, shared_state: PushStageSharedState<CS, EM, OT, Z>) {
(*self.shared_state.borrow_mut()).replace(shared_state); (*self.shared_state.borrow_mut()).replace(shared_state);
} }
/// Takes the shared state from this helper, replacing it with `None` /// Takes the shared state from this helper, replacing it with `None`
#[inline] #[inline]
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn take_shared_state(&mut self) -> Option<PushStageSharedState<CS, EM, I, OT, S, Z>> { pub fn take_shared_state(&mut self) -> Option<PushStageSharedState<CS, EM, OT, Z>> {
let shared_state_ref = &mut (*self.shared_state).borrow_mut(); let shared_state_ref = &mut (*self.shared_state).borrow_mut();
shared_state_ref.take() shared_state_ref.take()
} }
@ -163,11 +159,7 @@ where
} }
/// Resets this state after a full stage iter. /// Resets this state after a full stage iter.
fn end_of_iter( fn end_of_iter(&mut self, shared_state: PushStageSharedState<CS, EM, OT, Z>, errored: bool) {
&mut self,
shared_state: PushStageSharedState<CS, EM, I, OT, S, Z>,
errored: bool,
) {
self.set_shared_state(shared_state); self.set_shared_state(shared_state);
self.errored = errored; self.errored = errored;
self.current_corpus_idx = None; self.current_corpus_idx = None;
@ -180,19 +172,18 @@ where
/// A push stage is a generator that returns a single testcase for each call. /// A push stage is a generator that returns a single testcase for each call.
/// It's an iterator so we can chain it. /// It's an iterator so we can chain it.
/// After it has finished once, we will call it agan for the next fuzzer round. /// After it has finished once, we will call it agan for the next fuzzer round.
pub trait PushStage<CS, EM, I, OT, S, Z>: Iterator pub trait PushStage<CS, EM, OT, Z>: Iterator
where where
CS: Scheduler<I, S>, CS: Scheduler,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId + ProgressReporter<I>, CS::State: HasClientPerfMonitor + HasRand + HasExecutions + HasMetadata,
I: Input, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter,
OT: ObserversTuple<I, S>, OT: ObserversTuple<CS::State>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasExecutions + HasMetadata, Z: ExecutionProcessor<OT, State = CS::State> + EvaluatorObservers<OT> + HasScheduler<CS>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{ {
/// Gets the [`PushStageHelper`] /// Gets the [`PushStageHelper`]
fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, I, OT, S, Z>; fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, OT, Z>;
/// Gets the [`PushStageHelper`] (mutable) /// Gets the [`PushStageHelper`] (mutable)
fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<CS, EM, I, OT, S, Z>; fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<CS, EM, OT, Z>;
/// Set the current corpus index this stage works on /// Set the current corpus index this stage works on
fn set_current_corpus_idx(&mut self, corpus_idx: usize) { fn set_current_corpus_idx(&mut self, corpus_idx: usize) {
@ -206,7 +197,7 @@ where
fn init( fn init(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut S, _state: &mut CS::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -219,20 +210,20 @@ where
fn pre_exec( fn pre_exec(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut S, _state: &mut CS::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Option<Result<I, Error>>; ) -> Option<Result<<CS::State as UsesInput>::Input, Error>>;
/// Called after the execution of a testcase finished. /// Called after the execution of a testcase finished.
#[inline] #[inline]
fn post_exec( fn post_exec(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut S, _state: &mut CS::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
_input: I, _input: <CS::State as UsesInput>::Input,
_exit_kind: ExitKind, _exit_kind: ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
Ok(()) Ok(())
@ -243,7 +234,7 @@ where
fn deinit( fn deinit(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut S, _state: &mut CS::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -251,7 +242,7 @@ where
} }
/// This is the default implementation for `next` for this stage /// This is the default implementation for `next` for this stage
fn next_std(&mut self) -> Option<Result<I, Error>> { fn next_std(&mut self) -> Option<Result<<CS::State as UsesInput>::Input, Error>> {
let mut shared_state = { let mut shared_state = {
let shared_state_ref = &mut (*self.push_stage_helper_mut().shared_state).borrow_mut(); let shared_state_ref = &mut (*self.push_stage_helper_mut().shared_state).borrow_mut();
shared_state_ref.take().unwrap() shared_state_ref.take().unwrap()

View File

@ -2,7 +2,10 @@
//! For the current input, it will perform a range of random mutations, and then run them in the executor. //! For the current input, it will perform a range of random mutations, and then run them in the executor.
use alloc::rc::Rc; use alloc::rc::Rc;
use core::cell::{Cell, RefCell}; use core::{
cell::{Cell, RefCell},
fmt::Debug,
};
use super::{PushStage, PushStageHelper, PushStageSharedState}; use super::{PushStage, PushStageHelper, PushStageSharedState};
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
@ -12,7 +15,7 @@ use crate::{
corpus::Corpus, corpus::Corpus,
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter}, events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
executors::ExitKind, executors::ExitKind,
inputs::Input, inputs::UsesInput,
mark_feature_time, mark_feature_time,
mutators::Mutator, mutators::Mutator,
observers::ObserversTuple, observers::ObserversTuple,
@ -34,15 +37,14 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
/// ///
/// The default mutational push stage /// The default mutational push stage
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StdMutationalPushStage<CS, EM, I, M, OT, S, Z> pub struct StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler<I, S>, CS: Scheduler,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
I: Input, M: Mutator<CS::State>,
M: Mutator<I, S>, OT: ObserversTuple<CS::State>,
OT: ObserversTuple<I, S>, CS::State: HasClientPerfMonitor + HasRand + Clone + Debug,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand, Z: ExecutionProcessor<OT, State = CS::State> + EvaluatorObservers<OT> + HasScheduler<CS>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{ {
current_corpus_idx: Option<usize>, current_corpus_idx: Option<usize>,
testcases_to_do: usize, testcases_to_do: usize,
@ -52,22 +54,21 @@ where
mutator: M, mutator: M,
psh: PushStageHelper<CS, EM, I, OT, S, Z>, psh: PushStageHelper<CS, EM, OT, Z>,
} }
impl<CS, EM, I, M, OT, S, Z> StdMutationalPushStage<CS, EM, I, M, OT, S, Z> impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler<I, S>, CS: Scheduler,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
I: Input, M: Mutator<CS::State>,
M: Mutator<I, S>, OT: ObserversTuple<CS::State>,
OT: ObserversTuple<I, S>, CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand, Z: ExecutionProcessor<OT, State = CS::State> + EvaluatorObservers<OT> + HasScheduler<CS>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{ {
/// Gets the number of iterations as a random number /// 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 #[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> { fn iterations(&self, state: &mut CS::State, _corpus_idx: usize) -> Result<usize, Error> {
Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize) Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize)
} }
@ -77,22 +78,31 @@ where
} }
} }
impl<CS, EM, I, M, OT, S, Z> PushStage<CS, EM, I, OT, S, Z> impl<CS, EM, M, OT, Z> PushStage<CS, EM, OT, Z> for StdMutationalPushStage<CS, EM, M, OT, Z>
for StdMutationalPushStage<CS, EM, I, M, OT, S, Z>
where where
CS: Scheduler<I, S>, CS: Scheduler,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId + ProgressReporter<I>, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter,
I: Input, M: Mutator<CS::State>,
M: Mutator<I, S>, OT: ObserversTuple<CS::State>,
OT: ObserversTuple<I, S>, CS::State:
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasExecutions + HasMetadata, HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>, Z: ExecutionProcessor<OT, State = CS::State> + EvaluatorObservers<OT> + HasScheduler<CS>,
{ {
#[inline]
fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, OT, Z> {
&self.psh
}
#[inline]
fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<CS, EM, OT, Z> {
&mut self.psh
}
/// Creates a new default mutational stage /// Creates a new default mutational stage
fn init( fn init(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut CS::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -108,25 +118,13 @@ where
Ok(()) Ok(())
} }
#[inline]
fn deinit(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_event_mgr: &mut EM,
_observers: &mut OT,
) -> Result<(), Error> {
self.current_corpus_idx = None;
Ok(())
}
fn pre_exec( fn pre_exec(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
state: &mut S, state: &mut CS::State,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Option<Result<I, Error>> { ) -> Option<Result<<CS::State as UsesInput>::Input, Error>> {
if self.testcases_done >= self.testcases_to_do { if self.testcases_done >= self.testcases_to_do {
// finished with this cicle. // finished with this cicle.
return None; return None;
@ -159,10 +157,10 @@ where
fn post_exec( fn post_exec(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut CS::State,
event_mgr: &mut EM, event_mgr: &mut EM,
observers: &mut OT, observers: &mut OT,
last_input: I, last_input: <CS::State as UsesInput>::Input,
exit_kind: ExitKind, exit_kind: ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
// todo: isintersting, etc. // todo: isintersting, etc.
@ -179,49 +177,50 @@ where
} }
#[inline] #[inline]
fn push_stage_helper(&self) -> &PushStageHelper<CS, EM, I, OT, S, Z> { fn deinit(
&self.psh &mut self,
} _fuzzer: &mut Z,
_state: &mut CS::State,
#[inline] _event_mgr: &mut EM,
fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<CS, EM, I, OT, S, Z> { _observers: &mut OT,
&mut self.psh ) -> Result<(), Error> {
self.current_corpus_idx = None;
Ok(())
} }
} }
impl<CS, EM, I, M, OT, S, Z> Iterator for StdMutationalPushStage<CS, EM, I, M, OT, S, Z> impl<CS, EM, M, OT, Z> Iterator for StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler<I, S>, CS: Scheduler,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId + ProgressReporter<I>, EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = CS::State>,
I: Input, M: Mutator<CS::State>,
M: Mutator<I, S>, OT: ObserversTuple<CS::State>,
OT: ObserversTuple<I, S>, CS::State:
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasExecutions + HasMetadata, HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>, Z: ExecutionProcessor<OT, State = CS::State> + EvaluatorObservers<OT> + HasScheduler<CS>,
{ {
type Item = Result<I, Error>; type Item = Result<<CS::State as UsesInput>::Input, Error>;
fn next(&mut self) -> Option<Result<I, Error>> { fn next(&mut self) -> Option<Result<<CS::State as UsesInput>::Input, Error>> {
self.next_std() self.next_std()
} }
} }
impl<CS, EM, I, M, OT, S, Z> StdMutationalPushStage<CS, EM, I, M, OT, S, Z> impl<CS, EM, M, OT, Z> StdMutationalPushStage<CS, EM, M, OT, Z>
where where
CS: Scheduler<I, S>, CS: Scheduler,
EM: EventFirer<I> + EventRestarter<S> + HasEventManagerId, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId,
I: Input, M: Mutator<CS::State>,
M: Mutator<I, S>, OT: ObserversTuple<CS::State>,
OT: ObserversTuple<I, S>, CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand, Z: ExecutionProcessor<OT, State = CS::State> + EvaluatorObservers<OT> + HasScheduler<CS>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S> + HasScheduler<CS, I, S>,
{ {
/// Creates a new default mutational stage /// Creates a new default mutational stage
#[must_use] #[must_use]
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn new( pub fn new(
mutator: M, mutator: M,
shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, I, OT, S, Z>>>>, shared_state: Rc<RefCell<Option<PushStageSharedState<CS, EM, OT, Z>>>>,
exit_kind: Rc<Cell<Option<ExitKind>>>, exit_kind: Rc<Cell<Option<ExitKind>>>,
stage_idx: i32, stage_idx: i32,
) -> Self { ) -> Self {

View File

@ -12,9 +12,9 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
fuzzer::Evaluator, fuzzer::Evaluator,
inputs::Input, inputs::{Input, UsesInput},
stages::Stage, stages::Stage,
state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand}, state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState},
Error, Error,
}; };
@ -37,32 +37,33 @@ impl SyncFromDiskMetadata {
/// A stage that loads testcases from disk to sync with other fuzzers such as AFL++ /// A stage that loads testcases from disk to sync with other fuzzers such as AFL++
#[derive(Debug)] #[derive(Debug)]
pub struct SyncFromDiskStage<CB, E, EM, I, S, Z> pub struct SyncFromDiskStage<CB, E, EM, Z> {
where
CB: FnMut(&mut Z, &mut S, &Path) -> Result<I, Error>,
I: Input,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasMetadata,
Z: Evaluator<E, EM, I, S>,
{
sync_dir: PathBuf, sync_dir: PathBuf,
load_callback: CB, load_callback: CB,
#[allow(clippy::type_complexity)] phantom: PhantomData<(E, EM, Z)>,
phantom: PhantomData<(E, EM, I, S, Z)>,
} }
impl<CB, E, EM, I, S, Z> Stage<E, EM, S, Z> for SyncFromDiskStage<CB, E, EM, I, S, Z> impl<CB, E, EM, Z> UsesState for SyncFromDiskStage<CB, E, EM, Z>
where where
CB: FnMut(&mut Z, &mut S, &Path) -> Result<I, Error>, E: UsesState,
I: Input, {
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasMetadata, type State = E::State;
Z: Evaluator<E, EM, I, S>, }
impl<CB, E, EM, Z> Stage<E, EM, Z> for SyncFromDiskStage<CB, E, EM, Z>
where
CB: FnMut(&mut Z, &mut Z::State, &Path) -> Result<<Z::State as UsesInput>::Input, Error>,
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
{ {
#[inline] #[inline]
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut Z::State,
manager: &mut EM, manager: &mut EM,
_corpus_idx: usize, _corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -94,12 +95,13 @@ where
} }
} }
impl<CB, E, EM, I, S, Z> SyncFromDiskStage<CB, E, EM, I, S, Z> impl<CB, E, EM, Z> SyncFromDiskStage<CB, E, EM, Z>
where where
CB: FnMut(&mut Z, &mut S, &Path) -> Result<I, Error>, CB: FnMut(&mut Z, &mut Z::State, &Path) -> Result<<Z::State as UsesInput>::Input, Error>,
I: Input, E: UsesState<State = Z::State>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasMetadata, EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
{ {
/// Creates a new [`SyncFromDiskStage`] /// Creates a new [`SyncFromDiskStage`]
#[must_use] #[must_use]
@ -117,7 +119,7 @@ where
last: &Option<SystemTime>, last: &Option<SystemTime>,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut Z::State,
manager: &mut EM, manager: &mut EM,
) -> Result<Option<SystemTime>, Error> { ) -> Result<Option<SystemTime>, Error> {
let mut max_time = None; let mut max_time = None;
@ -157,23 +159,29 @@ where
} }
/// Function type when the callback in `SyncFromDiskStage` is not a lambda /// Function type when the callback in `SyncFromDiskStage` is not a lambda
pub type SyncFromDiskFunction<I, S, Z> = fn(&mut Z, &mut S, &Path) -> Result<I, Error>; pub type SyncFromDiskFunction<S, Z> =
fn(&mut Z, &mut S, &Path) -> Result<<S as UsesInput>::Input, Error>;
impl<E, EM, I, S, Z> SyncFromDiskStage<SyncFromDiskFunction<I, S, Z>, E, EM, I, S, Z> impl<E, EM, Z> SyncFromDiskStage<SyncFromDiskFunction<Z::State, Z>, E, EM, Z>
where where
I: Input, E: UsesState<State = Z::State>,
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasMetadata, EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM, I, S>, Z: Evaluator<E, EM>,
Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
{ {
/// Creates a new [`SyncFromDiskStage`] invoking `Input::from_file` to load inputs /// Creates a new [`SyncFromDiskStage`] invoking `Input::from_file` to load inputs
#[must_use] #[must_use]
pub fn with_from_file(sync_dir: PathBuf) -> Self { pub fn with_from_file(sync_dir: PathBuf) -> Self {
fn load_callback<Z, S, I: Input>(_: &mut Z, _: &mut S, p: &Path) -> Result<I, Error> { fn load_callback<S: UsesInput, Z>(
I::from_file(p) _: &mut Z,
_: &mut S,
p: &Path,
) -> Result<S::Input, Error> {
Input::from_file(p)
} }
Self { Self {
sync_dir, sync_dir,
load_callback: load_callback::<_, _, I>, load_callback: load_callback::<_, _>,
phantom: PhantomData, phantom: PhantomData,
} }
} }

View File

@ -17,36 +17,36 @@ use crate::{
events::EventFirer, events::EventFirer,
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
feedbacks::{Feedback, FeedbackFactory, HasObserverName}, feedbacks::{Feedback, FeedbackFactory, HasObserverName},
inputs::Input, inputs::UsesInput,
mark_feature_time, mark_feature_time,
mutators::Mutator, mutators::Mutator,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
schedulers::Scheduler, schedulers::Scheduler,
stages::Stage, stages::Stage,
start_timer, start_timer,
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMaxSize}, state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMaxSize, UsesState},
Error, ExecutesInput, ExecutionProcessor, HasFeedback, HasScheduler, Error, ExecutesInput, ExecutionProcessor, HasFeedback, HasScheduler,
}; };
/// Mutational stage which minimizes corpus entries. /// Mutational stage which minimizes corpus entries.
/// ///
/// You must provide at least one mutator that actually reduces size. /// You must provide at least one mutator that actually reduces size.
pub trait TMinMutationalStage<CS, E, EM, F1, F2, I, M, OT, S, Z>: pub trait TMinMutationalStage<CS, E, EM, F1, F2, M, OT, Z>:
Stage<E, EM, S, Z> + FeedbackFactory<F2, I, S, OT> Stage<E, EM, Z> + FeedbackFactory<F2, CS::State, OT>
where where
CS: Scheduler<I, S>, Self::State: HasCorpus + HasExecutions + HasMaxSize + HasClientPerfMonitor,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, <Self::State as UsesInput>::Input: HasLen + Hash,
EM: EventFirer<I>, CS: Scheduler<State = Self::State>,
F1: Feedback<I, S>, E: Executor<EM, Z> + HasObservers<Observers = OT, State = Self::State>,
F2: Feedback<I, S>, EM: EventFirer<State = Self::State>,
I: Input + Hash + HasLen, F1: Feedback<Self::State>,
M: Mutator<I, S>, F2: Feedback<Self::State>,
OT: ObserversTuple<I, S>, M: Mutator<Self::State>,
S: HasClientPerfMonitor + HasCorpus<I> + HasExecutions + HasMaxSize, OT: ObserversTuple<CS::State>,
Z: ExecutionProcessor<I, OT, S> Z: ExecutionProcessor<OT, State = Self::State>
+ ExecutesInput<I, OT, S, Z> + ExecutesInput<E, EM>
+ HasFeedback<F1, I, S> + HasFeedback<F1>
+ HasScheduler<CS, I, S>, + HasScheduler<CS>,
{ {
/// The mutator registered for this stage /// The mutator registered for this stage
fn mutator(&self) -> &M; fn mutator(&self) -> &M;
@ -55,7 +55,7 @@ where
fn mutator_mut(&mut self) -> &mut M; fn mutator_mut(&mut self) -> &mut M;
/// Gets the number of iterations this mutator should run for. /// Gets the number of iterations this mutator should run for.
fn iterations(&self, state: &mut S, corpus_idx: usize) -> Result<usize, Error>; fn iterations(&self, state: &mut CS::State, corpus_idx: usize) -> Result<usize, Error>;
/// Runs this (mutational) stage for new objectives /// Runs this (mutational) stage for new objectives
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
@ -63,7 +63,7 @@ where
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut CS::State,
manager: &mut EM, manager: &mut EM,
base_corpus_idx: usize, base_corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -165,41 +165,47 @@ where
/// The default corpus entry minimising mutational stage /// The default corpus entry minimising mutational stage
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StdTMinMutationalStage<CS, E, EM, F1, F2, FF, I, M, S, T, Z> pub struct StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z> {
where
I: Input + HasLen,
M: Mutator<I, S>,
{
mutator: M, mutator: M,
factory: FF, factory: FF,
runs: usize, runs: usize,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(CS, E, EM, F1, F2, I, S, T, Z)>, phantom: PhantomData<(CS, E, EM, F1, F2, OT, Z)>,
} }
impl<CS, E, EM, F1, F2, FF, I, M, OT, S, Z> Stage<E, EM, S, Z> impl<CS, E, EM, F1, F2, FF, M, OT, Z> UsesState
for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, I, M, S, OT, Z> for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
where where
CS: Scheduler<I, S>, CS: Scheduler,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, M: Mutator<CS::State>,
EM: EventFirer<I>, Z: ExecutionProcessor<OT, State = CS::State>,
F1: Feedback<I, S>, {
F2: Feedback<I, S>, type State = CS::State;
FF: FeedbackFactory<F2, I, S, OT>, }
I: Input + Hash + HasLen,
M: Mutator<I, S>, impl<CS, E, EM, F1, F2, FF, M, OT, Z> Stage<E, EM, Z>
OT: ObserversTuple<I, S>, for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
S: HasClientPerfMonitor + HasCorpus<I> + HasExecutions + HasMaxSize, where
Z: ExecutionProcessor<I, OT, S> CS: Scheduler,
+ ExecutesInput<I, OT, S, Z> CS::State: HasCorpus + HasExecutions + HasMaxSize + HasClientPerfMonitor,
+ HasFeedback<F1, I, S> <CS::State as UsesInput>::Input: HasLen + Hash,
+ HasScheduler<CS, I, S>, E: Executor<EM, Z> + HasObservers<Observers = OT, State = CS::State>,
EM: EventFirer<State = CS::State>,
F1: Feedback<CS::State>,
F2: Feedback<CS::State>,
FF: FeedbackFactory<F2, CS::State, OT>,
M: Mutator<CS::State>,
OT: ObserversTuple<CS::State>,
Z: ExecutionProcessor<OT, State = CS::State>
+ ExecutesInput<E, EM>
+ HasFeedback<F1>
+ HasScheduler<CS>,
{ {
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut CS::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -212,37 +218,36 @@ where
} }
} }
impl<CS, E, EM, F1, F2, FF, I, M, S, T, Z> FeedbackFactory<F2, I, S, T> impl<CS, E, EM, F1, F2, FF, M, OT, Z> FeedbackFactory<F2, Z::State, OT>
for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, I, M, S, T, Z> for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
where where
F2: Feedback<I, S>, F2: Feedback<Z::State>,
FF: FeedbackFactory<F2, I, S, T>, FF: FeedbackFactory<F2, Z::State, OT>,
I: Input + HasLen, Z: UsesState,
M: Mutator<I, S>, Z::State: HasClientPerfMonitor,
S: HasClientPerfMonitor,
{ {
fn create_feedback(&self, ctx: &T) -> F2 { fn create_feedback(&self, ctx: &OT) -> F2 {
self.factory.create_feedback(ctx) self.factory.create_feedback(ctx)
} }
} }
impl<CS, E, EM, F1, F2, FF, I, M, OT, S, Z> TMinMutationalStage<CS, E, EM, F1, F2, I, M, OT, S, Z> impl<CS, E, EM, F1, F2, FF, M, OT, Z> TMinMutationalStage<CS, E, EM, F1, F2, M, OT, Z>
for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, I, M, S, OT, Z> for StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
where where
CS: Scheduler<I, S>, CS: Scheduler,
E: HasObservers<I, OT, S> + Executor<EM, I, S, Z>, E: HasObservers<Observers = OT, State = CS::State> + Executor<EM, Z>,
EM: EventFirer<I>, EM: EventFirer<State = CS::State>,
F1: Feedback<I, S>, F1: Feedback<CS::State>,
F2: Feedback<I, S>, F2: Feedback<CS::State>,
FF: FeedbackFactory<F2, I, S, OT>, FF: FeedbackFactory<F2, CS::State, OT>,
I: Input + HasLen + Hash, <CS::State as UsesInput>::Input: HasLen + Hash,
M: Mutator<I, S>, M: Mutator<CS::State>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<CS::State>,
S: HasClientPerfMonitor + HasCorpus<I> + HasExecutions + HasMaxSize, CS::State: HasClientPerfMonitor + HasCorpus + HasExecutions + HasMaxSize,
Z: ExecutionProcessor<I, OT, S> Z: ExecutionProcessor<OT, State = CS::State>
+ ExecutesInput<I, OT, S, Z> + ExecutesInput<E, EM>
+ HasFeedback<F1, I, S> + HasFeedback<F1>
+ HasScheduler<CS, I, S>, + HasScheduler<CS>,
{ {
/// The mutator, added to this stage /// The mutator, added to this stage
#[inline] #[inline]
@ -257,16 +262,16 @@ where
} }
/// Gets the number of iterations from a fixed number of runs /// Gets the number of iterations from a fixed number of runs
fn iterations(&self, _state: &mut S, _corpus_idx: usize) -> Result<usize, Error> { fn iterations(&self, _state: &mut CS::State, _corpus_idx: usize) -> Result<usize, Error> {
Ok(self.runs) Ok(self.runs)
} }
} }
impl<CS, E, EM, F1, F2, FF, I, M, S, T, Z> impl<CS, E, EM, F1, F2, FF, M, OT, Z> StdTMinMutationalStage<CS, E, EM, F1, F2, FF, M, OT, Z>
StdTMinMutationalStage<CS, E, EM, F1, F2, FF, I, M, S, T, Z>
where where
I: Input + HasLen, CS: Scheduler,
M: Mutator<I, S>, M: Mutator<CS::State>,
Z: ExecutionProcessor<OT, State = CS::State>,
{ {
/// Creates a new minimising mutational stage that will minimize provided corpus entries /// Creates a new minimising mutational stage that will minimize provided corpus entries
pub fn new(mutator: M, factory: FF, runs: usize) -> Self { pub fn new(mutator: M, factory: FF, runs: usize) -> Self {
@ -282,14 +287,14 @@ where
/// A feedback which checks if the hash of the currently observed map is equal to the original hash /// A feedback which checks if the hash of the currently observed map is equal to the original hash
/// provided /// provided
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MapEqualityFeedback<M> { pub struct MapEqualityFeedback<M, S> {
name: String, name: String,
obs_name: String, obs_name: String,
orig_hash: u64, orig_hash: u64,
phantom: PhantomData<M>, phantom: PhantomData<(M, S)>,
} }
impl<M> MapEqualityFeedback<M> { impl<M, S> MapEqualityFeedback<M, S> {
/// Create a new map equality feedback -- can be used with feedback logic /// Create a new map equality feedback -- can be used with feedback logic
#[must_use] #[must_use]
pub fn new(name: &str, obs_name: &str, orig_hash: u64) -> Self { pub fn new(name: &str, obs_name: &str, orig_hash: u64) -> Self {
@ -302,35 +307,34 @@ impl<M> MapEqualityFeedback<M> {
} }
} }
impl<M> Named for MapEqualityFeedback<M> { impl<M, S> Named for MapEqualityFeedback<M, S> {
fn name(&self) -> &str { fn name(&self) -> &str {
&self.name &self.name
} }
} }
impl<M> HasObserverName for MapEqualityFeedback<M> { impl<M, S> HasObserverName for MapEqualityFeedback<M, S> {
fn observer_name(&self) -> &str { fn observer_name(&self) -> &str {
&self.obs_name &self.obs_name
} }
} }
impl<I, M, S> Feedback<I, S> for MapEqualityFeedback<M> impl<M, S> Feedback<S> for MapEqualityFeedback<M, S>
where where
I: Input, M: MapObserver + Debug,
M: MapObserver, S: UsesInput + HasClientPerfMonitor + Debug,
S: HasClientPerfMonitor,
{ {
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &<S as UsesInput>::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
let obs = observers let obs = observers
.match_name::<M>(self.observer_name()) .match_name::<M>(self.observer_name())
@ -341,12 +345,12 @@ where
/// A feedback factory for ensuring that the maps for minimized inputs are the same /// A feedback factory for ensuring that the maps for minimized inputs are the same
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MapEqualityFactory<M> { pub struct MapEqualityFactory<M, S> {
obs_name: String, obs_name: String,
phantom: PhantomData<M>, phantom: PhantomData<(M, S)>,
} }
impl<M> MapEqualityFactory<M> impl<M, S> MapEqualityFactory<M, S>
where where
M: MapObserver, M: MapObserver,
{ {
@ -359,20 +363,19 @@ where
} }
} }
impl<M> HasObserverName for MapEqualityFactory<M> { impl<M, S> HasObserverName for MapEqualityFactory<M, S> {
fn observer_name(&self) -> &str { fn observer_name(&self) -> &str {
&self.obs_name &self.obs_name
} }
} }
impl<I, M, OT, S> FeedbackFactory<MapEqualityFeedback<M>, I, S, OT> for MapEqualityFactory<M> impl<M, OT, S> FeedbackFactory<MapEqualityFeedback<M, S>, S, OT> for MapEqualityFactory<M, S>
where where
I: Input,
M: MapObserver, M: MapObserver,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
S: HasClientPerfMonitor, S: UsesInput + HasClientPerfMonitor + Debug,
{ {
fn create_feedback(&self, observers: &OT) -> MapEqualityFeedback<M> { fn create_feedback(&self, observers: &OT) -> MapEqualityFeedback<M, S> {
let obs = observers let obs = observers
.match_name::<M>(self.observer_name()) .match_name::<M>(self.observer_name())
.expect("Should have been provided valid observer name."); .expect("Should have been provided valid observer name.");

View File

@ -7,42 +7,43 @@ use crate::monitors::PerfFeature;
use crate::{ use crate::{
corpus::Corpus, corpus::Corpus,
executors::{Executor, HasObservers, ShadowExecutor}, executors::{Executor, HasObservers, ShadowExecutor},
inputs::Input,
mark_feature_time, mark_feature_time,
observers::ObserversTuple, observers::ObserversTuple,
stages::Stage, stages::Stage,
start_timer, start_timer,
state::{HasClientPerfMonitor, HasCorpus, HasExecutions}, state::{HasClientPerfMonitor, HasCorpus, HasExecutions, State, UsesState},
Error, Error,
}; };
/// A stage that runs a tracer executor /// A stage that runs a tracer executor
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct TracingStage<EM, I, OT, S, TE, Z> pub struct TracingStage<EM, TE, Z> {
where
I: Input,
TE: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasExecutions + HasCorpus<I>,
{
tracer_executor: TE, tracer_executor: TE,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(EM, I, OT, S, TE, Z)>, phantom: PhantomData<(EM, TE, Z)>,
} }
impl<E, EM, I, OT, S, TE, Z> Stage<E, EM, S, Z> for TracingStage<EM, I, OT, S, TE, Z> impl<EM, TE, Z> UsesState for TracingStage<EM, TE, Z>
where where
I: Input, TE: UsesState,
TE: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, {
OT: ObserversTuple<I, S>, type State = TE::State;
S: HasClientPerfMonitor + HasExecutions + HasCorpus<I>, }
impl<E, EM, TE, Z> Stage<E, EM, Z> for TracingStage<EM, TE, Z>
where
E: UsesState<State = TE::State>,
TE: Executor<EM, Z> + HasObservers,
TE::State: HasClientPerfMonitor + HasExecutions + HasCorpus,
EM: UsesState<State = TE::State>,
Z: UsesState<State = TE::State>,
{ {
#[inline] #[inline]
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
_executor: &mut E, _executor: &mut E,
state: &mut S, state: &mut TE::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -79,13 +80,7 @@ where
} }
} }
impl<EM, I, OT, S, TE, Z> TracingStage<EM, I, OT, S, TE, Z> impl<EM, TE, Z> TracingStage<EM, TE, Z> {
where
I: Input,
TE: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasExecutions + HasCorpus<I>,
{
/// Creates a new default stage /// Creates a new default stage
pub fn new(tracer_executor: TE) -> Self { pub fn new(tracer_executor: TE) -> Self {
Self { Self {
@ -102,26 +97,32 @@ where
/// A stage that runs the shadow executor using also the shadow observers /// A stage that runs the shadow executor using also the shadow observers
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ShadowTracingStage<E, EM, I, OT, S, SOT, Z> { pub struct ShadowTracingStage<E, EM, SOT, Z> {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, I, OT, S, SOT, Z)>, phantom: PhantomData<(E, EM, SOT, Z)>,
} }
impl<E, EM, I, OT, S, SOT, Z> Stage<ShadowExecutor<E, I, S, SOT>, EM, S, Z> impl<E, EM, SOT, Z> UsesState for ShadowTracingStage<E, EM, SOT, Z>
for ShadowTracingStage<E, EM, I, OT, S, SOT, Z>
where where
I: Input, E: UsesState,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, {
OT: ObserversTuple<I, S>, type State = E::State;
SOT: ObserversTuple<I, S>, }
S: HasClientPerfMonitor + HasExecutions + HasCorpus<I> + Debug,
impl<E, EM, SOT, Z> Stage<ShadowExecutor<E, SOT>, EM, Z> for ShadowTracingStage<E, EM, SOT, Z>
where
E: Executor<EM, Z> + HasObservers,
EM: UsesState<State = E::State>,
SOT: ObserversTuple<E::State>,
Z: UsesState<State = E::State>,
E::State: State + HasClientPerfMonitor + HasExecutions + HasCorpus + Debug,
{ {
#[inline] #[inline]
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut ShadowExecutor<E, I, S, SOT>, executor: &mut ShadowExecutor<E, SOT>,
state: &mut S, state: &mut E::State,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -160,16 +161,16 @@ where
} }
} }
impl<E, EM, I, OT, S, SOT, Z> ShadowTracingStage<E, EM, I, OT, S, SOT, Z> impl<E, EM, SOT, Z> ShadowTracingStage<E, EM, SOT, Z>
where where
I: Input, E: Executor<EM, Z> + HasObservers,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>, E::State: State + HasClientPerfMonitor + HasExecutions + HasCorpus,
OT: ObserversTuple<I, S>, EM: UsesState<State = E::State>,
SOT: ObserversTuple<I, S>, SOT: ObserversTuple<E::State>,
S: HasClientPerfMonitor + HasExecutions + HasCorpus<I>, Z: UsesState<State = E::State>,
{ {
/// Creates a new default stage /// Creates a new default stage
pub fn new(_executor: &mut ShadowExecutor<E, I, S, SOT>) -> Self { pub fn new(_executor: &mut ShadowExecutor<E, SOT>) -> Self {
Self { Self {
phantom: PhantomData, phantom: PhantomData,
} }

View File

@ -19,7 +19,7 @@ use crate::{
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::{Evaluator, ExecuteInputResult}, fuzzer::{Evaluator, ExecuteInputResult},
generators::Generator, generators::Generator,
inputs::Input, inputs::{Input, UsesInput},
monitors::ClientPerfMonitor, monitors::ClientPerfMonitor,
Error, Error,
}; };
@ -29,13 +29,28 @@ pub const DEFAULT_MAX_SIZE: usize = 1_048_576;
/// The [`State`] of the fuzzer. /// The [`State`] of the fuzzer.
/// Contains all important information about the current run. /// Contains all important information about the current run.
/// Will be used to restart the fuzzing process at any timme. /// Will be used to restart the fuzzing process at any time.
pub trait State: Serialize + DeserializeOwned {} pub trait State: UsesInput + Serialize + DeserializeOwned {}
/// Structs which implement this trait are aware of the state. This is used for type enforcement.
pub trait UsesState: UsesInput<Input = <Self::State as UsesInput>::Input> {
/// The state known by this type.
type State: UsesInput;
}
// blanket impl which automatically defines UsesInput for anything that implements UsesState
impl<KS> UsesInput for KS
where
KS: UsesState,
{
type Input = <KS::State as UsesInput>::Input;
}
/// Trait for elements offering a corpus /// Trait for elements offering a corpus
pub trait HasCorpus<I: Input> { pub trait HasCorpus: UsesInput {
/// The associated type implementing [`Corpus`]. /// The associated type implementing [`Corpus`].
type Corpus: Corpus<I>; type Corpus: Corpus<Input = <Self as UsesInput>::Input>;
/// The testcase corpus /// The testcase corpus
fn corpus(&self) -> &Self::Corpus; fn corpus(&self) -> &Self::Corpus;
/// The testcase corpus (mutable) /// The testcase corpus (mutable)
@ -51,9 +66,10 @@ pub trait HasMaxSize {
} }
/// Trait for elements offering a corpus of solutions /// Trait for elements offering a corpus of solutions
pub trait HasSolutions<I: Input> { pub trait HasSolutions: UsesInput {
/// The associated type implementing [`Corpus`] for solutions /// The associated type implementing [`Corpus`] for solutions
type Solutions: Corpus<I>; type Solutions: Corpus<Input = <Self as UsesInput>::Input>;
/// The solutions corpus /// The solutions corpus
fn solutions(&self) -> &Self::Solutions; fn solutions(&self) -> &Self::Solutions;
/// The solutions corpus (mutable) /// The solutions corpus (mutable)
@ -151,14 +167,12 @@ pub trait HasStartTime {
/// The state a fuzz run. /// The state a fuzz run.
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "C: serde::Serialize + for<'a> serde::Deserialize<'a>")] #[serde(bound = "
pub struct StdState<C, I, R, SC> C: serde::Serialize + for<'a> serde::Deserialize<'a>,
where SC: serde::Serialize + for<'a> serde::Deserialize<'a>,
C: Corpus<I>, R: serde::Serialize + for<'a> serde::Deserialize<'a>
I: Input, ")]
R: Rand, pub struct StdState<I, C, R, SC> {
SC: Corpus<I>,
{
/// RNG instance /// RNG instance
rand: R, rand: R,
/// How many times the executor ran the harness/target /// How many times the executor ran the harness/target
@ -178,25 +192,28 @@ where
/// Performance statistics for this fuzzer /// Performance statistics for this fuzzer
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
introspection_monitor: ClientPerfMonitor, introspection_monitor: ClientPerfMonitor,
phantom: PhantomData<I>, phantom: PhantomData<I>,
} }
impl<C, I, R, SC> State for StdState<C, I, R, SC> impl<I, C, R, SC> UsesInput for StdState<I, C, R, SC>
where where
C: Corpus<I>,
I: Input, I: Input,
{
type Input = I;
}
impl<I, C, R, SC> State for StdState<I, C, R, SC>
where
C: Corpus<Input = Self::Input>,
R: Rand, R: Rand,
SC: Corpus<I>, SC: Corpus<Input = Self::Input>,
Self: UsesInput,
{ {
} }
impl<C, I, R, SC> HasRand for StdState<C, I, R, SC> impl<I, C, R, SC> HasRand for StdState<I, C, R, SC>
where where
C: Corpus<I>,
I: Input,
R: Rand, R: Rand,
SC: Corpus<I>,
{ {
type Rand = R; type Rand = R;
@ -213,34 +230,31 @@ where
} }
} }
impl<C, I, R, SC> HasCorpus<I> for StdState<C, I, R, SC> impl<I, C, R, SC> HasCorpus for StdState<I, C, R, SC>
where where
C: Corpus<I>,
I: Input, I: Input,
C: Corpus<Input = <Self as UsesInput>::Input>,
R: Rand, R: Rand,
SC: Corpus<I>,
{ {
type Corpus = C; type Corpus = C;
/// Returns the corpus /// Returns the corpus
#[inline] #[inline]
fn corpus(&self) -> &C { fn corpus(&self) -> &Self::Corpus {
&self.corpus &self.corpus
} }
/// Returns the mutable corpus /// Returns the mutable corpus
#[inline] #[inline]
fn corpus_mut(&mut self) -> &mut C { fn corpus_mut(&mut self) -> &mut Self::Corpus {
&mut self.corpus &mut self.corpus
} }
} }
impl<C, I, R, SC> HasSolutions<I> for StdState<C, I, R, SC> impl<I, C, R, SC> HasSolutions for StdState<I, C, R, SC>
where where
C: Corpus<I>,
I: Input, I: Input,
R: Rand, SC: Corpus<Input = <Self as UsesInput>::Input>,
SC: Corpus<I>,
{ {
type Solutions = SC; type Solutions = SC;
@ -257,13 +271,7 @@ where
} }
} }
impl<C, I, R, SC> HasMetadata for StdState<C, I, R, SC> impl<I, C, R, SC> HasMetadata for StdState<I, C, R, SC> {
where
C: Corpus<I>,
I: Input,
R: Rand,
SC: Corpus<I>,
{
/// Get all the metadata into an [`hashbrown::HashMap`] /// Get all the metadata into an [`hashbrown::HashMap`]
#[inline] #[inline]
fn metadata(&self) -> &SerdeAnyMap { fn metadata(&self) -> &SerdeAnyMap {
@ -277,13 +285,7 @@ where
} }
} }
impl<C, I, R, SC> HasNamedMetadata for StdState<C, I, R, SC> impl<I, C, R, SC> HasNamedMetadata for StdState<I, C, R, SC> {
where
C: Corpus<I>,
I: Input,
R: Rand,
SC: Corpus<I>,
{
/// Get all the metadata into an [`hashbrown::HashMap`] /// Get all the metadata into an [`hashbrown::HashMap`]
#[inline] #[inline]
fn named_metadata(&self) -> &NamedSerdeAnyMap { fn named_metadata(&self) -> &NamedSerdeAnyMap {
@ -297,13 +299,7 @@ where
} }
} }
impl<C, I, R, SC> HasExecutions for StdState<C, I, R, SC> impl<I, C, R, SC> HasExecutions for StdState<I, C, R, SC> {
where
C: Corpus<I>,
I: Input,
R: Rand,
SC: Corpus<I>,
{
/// The executions counter /// The executions counter
#[inline] #[inline]
fn executions(&self) -> &usize { fn executions(&self) -> &usize {
@ -317,13 +313,7 @@ where
} }
} }
impl<C, I, R, SC> HasMaxSize for StdState<C, I, R, SC> impl<I, C, R, SC> HasMaxSize for StdState<I, C, R, SC> {
where
C: Corpus<I>,
I: Input,
R: Rand,
SC: Corpus<I>,
{
fn max_size(&self) -> usize { fn max_size(&self) -> usize {
self.max_size self.max_size
} }
@ -333,13 +323,7 @@ where
} }
} }
impl<C, I, R, SC> HasStartTime for StdState<C, I, R, SC> impl<I, C, R, SC> HasStartTime for StdState<I, C, R, SC> {
where
C: Corpus<I>,
I: Input,
R: Rand,
SC: Corpus<I>,
{
/// The starting time /// The starting time
#[inline] #[inline]
fn start_time(&self) -> &Duration { fn start_time(&self) -> &Duration {
@ -354,12 +338,12 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<C, I, R, SC> StdState<C, I, R, SC> impl<C, I, R, SC> StdState<I, C, R, SC>
where where
C: Corpus<I>,
I: Input, I: Input,
C: Corpus<Input = <Self as UsesInput>::Input>,
R: Rand, R: Rand,
SC: Corpus<I>, SC: Corpus<Input = <Self as UsesInput>::Input>,
{ {
/// Loads inputs from a directory. /// Loads inputs from a directory.
/// If `forced` is `true`, the value will be loaded, /// If `forced` is `true`, the value will be loaded,
@ -374,7 +358,9 @@ where
loader: &mut dyn FnMut(&mut Z, &mut Self, &Path) -> Result<I, Error>, loader: &mut dyn FnMut(&mut Z, &mut Self, &Path) -> Result<I, Error>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
Z: Evaluator<E, EM, I, Self>, E: UsesState<State = Self>,
EM: UsesState<State = Self>,
Z: Evaluator<E, EM, State = Self>,
{ {
for entry in fs::read_dir(in_dir)? { for entry in fs::read_dir(in_dir)? {
let entry = entry?; let entry = entry?;
@ -417,8 +403,9 @@ where
forced: bool, forced: bool,
) -> Result<(), Error> ) -> Result<(), Error>
where where
Z: Evaluator<E, EM, I, Self>, E: UsesState<State = Self>,
EM: EventFirer<I>, EM: EventFirer<State = Self>,
Z: Evaluator<E, EM, State = Self>,
{ {
for in_dir in in_dirs { for in_dir in in_dirs {
self.load_from_directory( self.load_from_directory(
@ -435,7 +422,7 @@ where
Event::Log { Event::Log {
severity_level: LogSeverity::Debug, severity_level: LogSeverity::Debug,
message: format!("Loaded {} initial testcases.", self.corpus().count()), // get corpus count message: format!("Loaded {} initial testcases.", self.corpus().count()), // get corpus count
phantom: PhantomData, phantom: PhantomData::<I>,
}, },
)?; )?;
Ok(()) Ok(())
@ -452,8 +439,9 @@ where
in_dirs: &[PathBuf], in_dirs: &[PathBuf],
) -> Result<(), Error> ) -> Result<(), Error>
where where
Z: Evaluator<E, EM, I, Self>, E: UsesState<State = Self>,
EM: EventFirer<I>, EM: EventFirer<State = Self>,
Z: Evaluator<E, EM, State = Self>,
{ {
self.load_initial_inputs_internal(fuzzer, executor, manager, in_dirs, true) self.load_initial_inputs_internal(fuzzer, executor, manager, in_dirs, true)
} }
@ -467,19 +455,20 @@ where
in_dirs: &[PathBuf], in_dirs: &[PathBuf],
) -> Result<(), Error> ) -> Result<(), Error>
where where
Z: Evaluator<E, EM, I, Self>, E: UsesState<State = Self>,
EM: EventFirer<I>, EM: EventFirer<State = Self>,
Z: Evaluator<E, EM, State = Self>,
{ {
self.load_initial_inputs_internal(fuzzer, executor, manager, in_dirs, false) self.load_initial_inputs_internal(fuzzer, executor, manager, in_dirs, false)
} }
} }
impl<C, I, R, SC> StdState<C, I, R, SC> impl<C, I, R, SC> StdState<I, C, R, SC>
where where
C: Corpus<I>,
I: Input, I: Input,
C: Corpus<Input = <Self as UsesInput>::Input>,
R: Rand, R: Rand,
SC: Corpus<I>, SC: Corpus<Input = <Self as UsesInput>::Input>,
{ {
fn generate_initial_internal<G, E, EM, Z>( fn generate_initial_internal<G, E, EM, Z>(
&mut self, &mut self,
@ -491,9 +480,10 @@ where
forced: bool, forced: bool,
) -> Result<(), Error> ) -> Result<(), Error>
where where
G: Generator<I, Self>, E: UsesState<State = Self>,
Z: Evaluator<E, EM, I, Self>, EM: EventFirer<State = Self>,
EM: EventFirer<I>, G: Generator<<Self as UsesInput>::Input, Self>,
Z: Evaluator<E, EM, State = Self>,
{ {
let mut added = 0; let mut added = 0;
for _ in 0..num { for _ in 0..num {
@ -529,9 +519,10 @@ where
num: usize, num: usize,
) -> Result<(), Error> ) -> Result<(), Error>
where where
G: Generator<I, Self>, E: UsesState<State = Self>,
Z: Evaluator<E, EM, I, Self>, EM: EventFirer<State = Self>,
EM: EventFirer<I>, G: Generator<<Self as UsesInput>::Input, Self>,
Z: Evaluator<E, EM, State = Self>,
{ {
self.generate_initial_internal(fuzzer, executor, generator, manager, num, true) self.generate_initial_internal(fuzzer, executor, generator, manager, num, true)
} }
@ -546,9 +537,10 @@ where
num: usize, num: usize,
) -> Result<(), Error> ) -> Result<(), Error>
where where
G: Generator<I, Self>, E: UsesState<State = Self>,
Z: Evaluator<E, EM, I, Self>, EM: EventFirer<State = Self>,
EM: EventFirer<I>, G: Generator<<Self as UsesInput>::Input, Self>,
Z: Evaluator<E, EM, State = Self>,
{ {
self.generate_initial_internal(fuzzer, executor, generator, manager, num, false) self.generate_initial_internal(fuzzer, executor, generator, manager, num, false)
} }
@ -562,8 +554,8 @@ where
objective: &mut O, objective: &mut O,
) -> Result<Self, Error> ) -> Result<Self, Error>
where where
F: Feedback<I, Self>, F: Feedback<Self>,
O: Feedback<I, Self>, O: Feedback<Self>,
{ {
let mut state = Self { let mut state = Self {
rand, rand,
@ -585,13 +577,7 @@ where
} }
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
impl<C, I, R, SC> HasClientPerfMonitor for StdState<C, I, R, SC> impl<I, C, R, SC> HasClientPerfMonitor for StdState<I, C, R, SC> {
where
C: Corpus<I>,
I: Input,
R: Rand,
SC: Corpus<I>,
{
fn introspection_monitor(&self) -> &ClientPerfMonitor { fn introspection_monitor(&self) -> &ClientPerfMonitor {
&self.introspection_monitor &self.introspection_monitor
} }
@ -602,13 +588,7 @@ where
} }
#[cfg(not(feature = "introspection"))] #[cfg(not(feature = "introspection"))]
impl<C, I, R, SC> HasClientPerfMonitor for StdState<C, I, R, SC> impl<I, C, R, SC> HasClientPerfMonitor for StdState<I, C, R, SC> {
where
C: Corpus<I>,
I: Input,
R: Rand,
SC: Corpus<I>,
{
fn introspection_monitor(&self) -> &ClientPerfMonitor { fn introspection_monitor(&self) -> &ClientPerfMonitor {
unimplemented!() unimplemented!()
} }
@ -618,6 +598,67 @@ where
} }
} }
#[cfg(test)]
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct NopState<I> {
phantom: PhantomData<I>,
}
#[cfg(test)]
impl<I> NopState<I> {
/// Create a new State that does nothing (for tests)
#[must_use]
pub fn new() -> Self {
NopState {
phantom: PhantomData,
}
}
}
#[cfg(test)]
impl<I> UsesInput for NopState<I>
where
I: Input,
{
type Input = I;
}
#[cfg(test)]
impl<I> HasExecutions for NopState<I> {
fn executions(&self) -> &usize {
unimplemented!()
}
fn executions_mut(&mut self) -> &mut usize {
unimplemented!()
}
}
#[cfg(test)]
impl<I> HasMetadata for NopState<I> {
fn metadata(&self) -> &SerdeAnyMap {
unimplemented!()
}
fn metadata_mut(&mut self) -> &mut SerdeAnyMap {
unimplemented!()
}
}
#[cfg(test)]
impl<I> HasClientPerfMonitor for NopState<I> {
fn introspection_monitor(&self) -> &ClientPerfMonitor {
unimplemented!()
}
fn introspection_monitor_mut(&mut self) -> &mut ClientPerfMonitor {
unimplemented!()
}
}
#[cfg(test)]
impl<I> State for NopState<I> where I: Input {}
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)] #[allow(missing_docs)]
/// `State` Python bindings /// `State` Python bindings
@ -643,7 +684,7 @@ pub mod pybind {
}; };
/// `StdState` with fixed generics /// `StdState` with fixed generics
pub type PythonStdState = StdState<PythonCorpus, BytesInput, PythonRand, PythonCorpus>; pub type PythonStdState = StdState<BytesInput, PythonCorpus, PythonRand, PythonCorpus>;
#[pyclass(unsendable, name = "StdState")] #[pyclass(unsendable, name = "StdState")]
#[derive(Debug)] #[derive(Debug)]

View File

@ -1,5 +1,5 @@
//! Errors that can be caught by the `libafl_frida` address sanitizer. //! Errors that can be caught by the `libafl_frida` address sanitizer.
use std::io::Write; use std::{fmt::Debug, io::Write, marker::PhantomData};
use backtrace::Backtrace; use backtrace::Backtrace;
use capstone::{arch::BuildsCapstone, Capstone}; use capstone::{arch::BuildsCapstone, Capstone};
@ -13,7 +13,7 @@ use libafl::{
events::EventFirer, events::EventFirer,
executors::ExitKind, executors::ExitKind,
feedbacks::Feedback, feedbacks::Feedback,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, UsesInput},
observers::{Observer, ObserversTuple}, observers::{Observer, ObserversTuple},
state::{HasClientPerfMonitor, HasMetadata}, state::{HasClientPerfMonitor, HasMetadata},
Error, SerdeAny, Error, SerdeAny,
@ -551,8 +551,11 @@ pub struct AsanErrorsObserver {
errors: OwnedPtr<Option<AsanErrors>>, errors: OwnedPtr<Option<AsanErrors>>,
} }
impl<I, S> Observer<I, S> for AsanErrorsObserver { impl<S> Observer<S> for AsanErrorsObserver
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { where
S: UsesInput,
{
fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
unsafe { unsafe {
if ASAN_ERRORS.is_some() { if ASAN_ERRORS.is_some() {
ASAN_ERRORS.as_mut().unwrap().clear(); ASAN_ERRORS.as_mut().unwrap().clear();
@ -607,27 +610,28 @@ impl AsanErrorsObserver {
/// A feedback reporting potential [`struct@AsanErrors`] from an `AsanErrorsObserver` /// A feedback reporting potential [`struct@AsanErrors`] from an `AsanErrorsObserver`
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct AsanErrorsFeedback { pub struct AsanErrorsFeedback<S> {
errors: Option<AsanErrors>, errors: Option<AsanErrors>,
phantom: PhantomData<S>,
} }
impl<I, S> Feedback<I, S> for AsanErrorsFeedback impl<S> Feedback<S> for AsanErrorsFeedback<S>
where where
I: Input + HasTargetBytes, S: UsesInput + Debug + HasClientPerfMonitor,
S: HasClientPerfMonitor, S::Input: HasTargetBytes,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>( fn is_interesting<EM, OT>(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &I, _input: &S::Input,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I>, EM: EventFirer<State = S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
let observer = observers let observer = observers
.match_name::<AsanErrorsObserver>("AsanErrors") .match_name::<AsanErrorsObserver>("AsanErrors")
@ -645,7 +649,11 @@ where
} }
} }
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<I>) -> Result<(), Error> { fn append_metadata(
&mut self,
_state: &mut S,
testcase: &mut Testcase<S::Input>,
) -> Result<(), Error> {
if let Some(errors) = &self.errors { if let Some(errors) = &self.errors {
testcase.add_metadata(errors.clone()); testcase.add_metadata(errors.clone());
} }
@ -653,28 +661,31 @@ where
Ok(()) Ok(())
} }
fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.errors = None; self.errors = None;
Ok(()) Ok(())
} }
} }
impl Named for AsanErrorsFeedback { impl<S> Named for AsanErrorsFeedback<S> {
#[inline] #[inline]
fn name(&self) -> &str { fn name(&self) -> &str {
"AsanErrors" "AsanErrors"
} }
} }
impl AsanErrorsFeedback { impl<S> AsanErrorsFeedback<S> {
/// Create a new `AsanErrorsFeedback` /// Create a new `AsanErrorsFeedback`
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { errors: None } Self {
errors: None,
phantom: PhantomData,
}
} }
} }
impl Default for AsanErrorsFeedback { impl<S> Default for AsanErrorsFeedback<S> {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }

View File

@ -6,11 +6,15 @@ use frida_gum::{
Gum, MemoryRange, NativePointer, Gum, MemoryRange, NativePointer,
}; };
#[cfg(windows)] #[cfg(windows)]
use libafl::executors::inprocess::{HasInProcessHandlers, InProcessHandlers}; use libafl::{
executors::inprocess::{HasInProcessHandlers, InProcessHandlers},
state::{HasClientPerfMonitor, HasSolutions},
};
use libafl::{ use libafl::{
executors::{Executor, ExitKind, HasObservers, InProcessExecutor}, executors::{Executor, ExitKind, HasObservers, InProcessExecutor},
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, UsesInput},
observers::ObserversTuple, observers::{ObserversTuple, UsesObservers},
state::UsesState,
Error, Error,
}; };
@ -21,13 +25,14 @@ use crate::helper::{FridaInstrumentationHelper, FridaRuntimeTuple};
use crate::windows_hooks::initialize; use crate::windows_hooks::initialize;
/// The [`FridaInProcessExecutor`] is an [`Executor`] that executes the target in the same process, usinig [`frida`](https://frida.re/) for binary-only instrumentation. /// The [`FridaInProcessExecutor`] is an [`Executor`] that executes the target in the same process, usinig [`frida`](https://frida.re/) for binary-only instrumentation.
pub struct FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S> pub struct FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input + HasTargetBytes, S::Input: HasTargetBytes,
OT: ObserversTuple<I, S>, S: UsesInput,
OT: ObserversTuple<S>,
{ {
base: InProcessExecutor<'a, H, I, OT, S>, base: InProcessExecutor<'a, H, OT, S>,
/// Frida's dynamic rewriting engine /// Frida's dynamic rewriting engine
stalker: Stalker<'a>, stalker: Stalker<'a>,
/// User provided callback for instrumentation /// User provided callback for instrumentation
@ -36,11 +41,12 @@ where
_phantom: PhantomData<&'b u8>, _phantom: PhantomData<&'b u8>,
} }
impl<'a, 'b, 'c, H, I, OT, RT, S> Debug for FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S> impl<'a, 'b, 'c, H, OT, RT, S> Debug for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input + HasTargetBytes, S: UsesInput,
OT: ObserversTuple<I, S>, S::Input: HasTargetBytes,
OT: ObserversTuple<S>,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("FridaInProcessExecutor") f.debug_struct("FridaInProcessExecutor")
@ -51,22 +57,25 @@ where
} }
} }
impl<'a, 'b, 'c, EM, H, I, OT, RT, S, Z> Executor<EM, I, S, Z> impl<'a, 'b, 'c, EM, H, OT, RT, S, Z> Executor<EM, Z>
for FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S> for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where where
H: FnMut(&I) -> ExitKind, EM: UsesState<State = S>,
I: Input + HasTargetBytes, H: FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<I, S>, S: UsesInput,
S::Input: HasTargetBytes,
OT: ObserversTuple<S>,
RT: FridaRuntimeTuple, RT: FridaRuntimeTuple,
Z: UsesState<State = S>,
{ {
/// Instruct the target about the input and run /// Instruct the target about the input and run
#[inline] #[inline]
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
self.helper.pre_exec(input)?; self.helper.pre_exec(input)?;
if self.helper.stalker_enabled() { if self.helper.stalker_enabled() {
@ -94,12 +103,32 @@ where
} }
} }
impl<'a, 'b, 'c, H, I, OT, RT, S> HasObservers<I, OT, S> impl<'a, 'b, 'c, H, OT, RT, S> UsesObservers for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
for FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input + HasTargetBytes, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, S: UsesInput,
S::Input: HasTargetBytes,
{
type Observers = OT;
}
impl<'a, 'b, 'c, H, OT, RT, S> UsesState for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where
H: FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<S>,
S: UsesInput,
S::Input: HasTargetBytes,
{
type State = S;
}
impl<'a, 'b, 'c, H, OT, RT, S> HasObservers for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where
H: FnMut(&S::Input) -> ExitKind,
S::Input: HasTargetBytes,
S: UsesInput,
OT: ObserversTuple<S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
@ -112,17 +141,18 @@ where
} }
} }
impl<'a, 'b, 'c, H, I, OT, S, RT> FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S> impl<'a, 'b, 'c, H, OT, S, RT> FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input + HasTargetBytes, S: UsesInput,
OT: ObserversTuple<I, S>, S::Input: HasTargetBytes,
OT: ObserversTuple<S>,
RT: FridaRuntimeTuple, RT: FridaRuntimeTuple,
{ {
/// Creates a new [`FridaInProcessExecutor`] /// Creates a new [`FridaInProcessExecutor`]
pub fn new( pub fn new(
gum: &'a Gum, gum: &'a Gum,
base: InProcessExecutor<'a, H, I, OT, S>, base: InProcessExecutor<'a, H, OT, S>,
helper: &'c mut FridaInstrumentationHelper<'b, RT>, helper: &'c mut FridaInstrumentationHelper<'b, RT>,
) -> Self { ) -> Self {
let mut stalker = Stalker::new(gum); let mut stalker = Stalker::new(gum);
@ -162,12 +192,13 @@ where
} }
#[cfg(windows)] #[cfg(windows)]
impl<'a, 'b, 'c, H, I, OT, RT, S> HasInProcessHandlers impl<'a, 'b, 'c, H, OT, RT, S> HasInProcessHandlers
for FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S> for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input + HasTargetBytes, S: UsesInput + HasClientPerfMonitor + HasSolutions,
OT: ObserversTuple<I, S>, S::Input: HasTargetBytes,
OT: ObserversTuple<S>,
RT: FridaRuntimeTuple, RT: FridaRuntimeTuple,
{ {
/// the timeout handler /// the timeout handler

View File

@ -3,8 +3,9 @@ use std::{fmt::Debug, marker::PhantomData};
use libafl::{ use libafl::{
bolts::AsSlice, bolts::AsSlice,
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, UsesInput},
observers::ObserversTuple, observers::{ObserversTuple, UsesObservers},
state::{State, UsesState},
Error, Error,
}; };
use libnyx::NyxReturnValue; use libnyx::NyxReturnValue;
@ -12,16 +13,16 @@ use libnyx::NyxReturnValue;
use crate::helper::NyxHelper; use crate::helper::NyxHelper;
/// executor for nyx standalone mode /// executor for nyx standalone mode
pub struct NyxExecutor<'a, I, S, OT> { pub struct NyxExecutor<'a, S, OT> {
/// implement nyx function /// implement nyx function
pub helper: &'a mut NyxHelper, pub helper: &'a mut NyxHelper,
/// observers /// observers
observers: OT, observers: OT,
/// phantom data to keep generic type <I,S> /// phantom data to keep generic type <I,S>
phantom: PhantomData<(I, S)>, phantom: PhantomData<S>,
} }
impl<'a, I, S, OT> Debug for NyxExecutor<'a, I, S, OT> { impl<'a, S, OT> Debug for NyxExecutor<'a, S, OT> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NyxInprocessExecutor") f.debug_struct("NyxInprocessExecutor")
.field("helper", &self.helper) .field("helper", &self.helper)
@ -29,17 +30,35 @@ impl<'a, I, S, OT> Debug for NyxExecutor<'a, I, S, OT> {
} }
} }
impl<'a, EM, I, S, Z, OT> Executor<EM, I, S, Z> for NyxExecutor<'a, I, S, OT> impl<'a, S, OT> UsesState for NyxExecutor<'a, S, OT>
where where
I: Input + HasTargetBytes, S: UsesInput,
{
type State = S;
}
impl<'a, S, OT> UsesObservers for NyxExecutor<'a, S, OT>
where
OT: ObserversTuple<S>,
S: UsesInput,
{
type Observers = OT;
}
impl<'a, EM, S, Z, OT> Executor<EM, Z> for NyxExecutor<'a, S, OT>
where
EM: UsesState<State = S>,
S: UsesInput,
S::Input: HasTargetBytes,
Z: UsesState<State = S>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
_state: &mut S, _state: &mut Self::State,
_mgr: &mut EM, _mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<libafl::executors::ExitKind, libafl::Error> { ) -> Result<ExitKind, Error> {
let input_owned = input.target_bytes(); let input_owned = input.target_bytes();
let input = input_owned.as_slice(); let input = input_owned.as_slice();
self.helper.nyx_process.set_input(input, input.len() as u32); self.helper.nyx_process.set_input(input, input.len() as u32);
@ -68,7 +87,7 @@ where
} }
} }
impl<'a, I, S, OT> NyxExecutor<'a, I, S, OT> { impl<'a, S, OT> NyxExecutor<'a, S, OT> {
pub fn new(helper: &'a mut NyxHelper, observers: OT) -> Result<Self, Error> { pub fn new(helper: &'a mut NyxHelper, observers: OT) -> Result<Self, Error> {
Ok(Self { Ok(Self {
helper, helper,
@ -83,10 +102,10 @@ impl<'a, I, S, OT> NyxExecutor<'a, I, S, OT> {
} }
} }
impl<'a, I, S, OT> HasObservers<I, OT, S> for NyxExecutor<'a, I, S, OT> impl<'a, S, OT> HasObservers for NyxExecutor<'a, S, OT>
where where
I: Input, S: State,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
{ {
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
&self.observers &self.observers

View File

@ -1,6 +1,6 @@
use std::{env, fs, ptr}; use std::{env, fs, ptr};
use libafl::{inputs::Input, state::HasMetadata}; use libafl::{inputs::UsesInput, state::HasMetadata};
use num_enum::{IntoPrimitive, TryFromPrimitive}; use num_enum::{IntoPrimitive, TryFromPrimitive};
use crate::{ use crate::{
@ -407,52 +407,51 @@ impl Default for QemuAsanHelper {
} }
} }
impl<I, S> QemuHelper<I, S> for QemuAsanHelper impl<S> QemuHelper<S> for QemuAsanHelper
where where
I: Input, S: UsesInput + HasMetadata,
S: HasMetadata,
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = false; const HOOKS_DO_SIDE_EFFECTS: bool = false;
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>) fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
hooks.reads( hooks.reads(
Some(gen_readwrite_asan::<I, QT, S>), Some(gen_readwrite_asan::<QT, S>),
Some(trace_read1_asan::<I, QT, S>), Some(trace_read1_asan::<QT, S>),
Some(trace_read2_asan::<I, QT, S>), Some(trace_read2_asan::<QT, S>),
Some(trace_read4_asan::<I, QT, S>), Some(trace_read4_asan::<QT, S>),
Some(trace_read8_asan::<I, QT, S>), Some(trace_read8_asan::<QT, S>),
Some(trace_read_n_asan::<I, QT, S>), Some(trace_read_n_asan::<QT, S>),
); );
hooks.writes( hooks.writes(
Some(gen_readwrite_asan::<I, QT, S>), Some(gen_readwrite_asan::<QT, S>),
Some(trace_write1_asan::<I, QT, S>), Some(trace_write1_asan::<QT, S>),
Some(trace_write2_asan::<I, QT, S>), Some(trace_write2_asan::<QT, S>),
Some(trace_write4_asan::<I, QT, S>), Some(trace_write4_asan::<QT, S>),
Some(trace_write8_asan::<I, QT, S>), Some(trace_write8_asan::<QT, S>),
Some(trace_write_n_asan::<I, QT, S>), Some(trace_write_n_asan::<QT, S>),
); );
hooks.syscalls(qasan_fake_syscall::<I, QT, S>); hooks.syscalls(qasan_fake_syscall::<QT, S>);
} }
fn post_exec(&mut self, _emulator: &Emulator, _input: &I) { fn post_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {
self.reset(); self.reset();
} }
} }
pub fn gen_readwrite_asan<I, QT, S>( pub fn gen_readwrite_asan<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
pc: GuestAddr, pc: GuestAddr,
_size: usize, _size: usize,
) -> Option<u64> ) -> Option<u64>
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
if h.must_instrument(pc.into()) { if h.must_instrument(pc.into()) {
@ -461,142 +460,142 @@ where
None None
} }
} }
pub fn trace_read1_asan<I, QT, S>( pub fn trace_read1_asan<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let emulator = hooks.emulator().clone(); let emulator = hooks.emulator().clone();
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.read_1(&emulator, addr); h.read_1(&emulator, addr);
} }
pub fn trace_read2_asan<I, QT, S>( pub fn trace_read2_asan<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let emulator = hooks.emulator().clone(); let emulator = hooks.emulator().clone();
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.read_2(&emulator, addr); h.read_2(&emulator, addr);
} }
pub fn trace_read4_asan<I, QT, S>( pub fn trace_read4_asan<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let emulator = hooks.emulator().clone(); let emulator = hooks.emulator().clone();
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.read_4(&emulator, addr); h.read_4(&emulator, addr);
} }
pub fn trace_read8_asan<I, QT, S>( pub fn trace_read8_asan<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let emulator = hooks.emulator().clone(); let emulator = hooks.emulator().clone();
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.read_8(&emulator, addr); h.read_8(&emulator, addr);
} }
pub fn trace_read_n_asan<I, QT, S>( pub fn trace_read_n_asan<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
size: usize, size: usize,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let emulator = hooks.emulator().clone(); let emulator = hooks.emulator().clone();
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.read_n(&emulator, addr, size); h.read_n(&emulator, addr, size);
} }
pub fn trace_write1_asan<I, QT, S>( pub fn trace_write1_asan<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let emulator = hooks.emulator().clone(); let emulator = hooks.emulator().clone();
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.write_1(&emulator, addr); h.write_1(&emulator, addr);
} }
pub fn trace_write2_asan<I, QT, S>( pub fn trace_write2_asan<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let emulator = hooks.emulator().clone(); let emulator = hooks.emulator().clone();
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.write_2(&emulator, addr); h.write_2(&emulator, addr);
} }
pub fn trace_write4_asan<I, QT, S>( pub fn trace_write4_asan<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let emulator = hooks.emulator().clone(); let emulator = hooks.emulator().clone();
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.write_4(&emulator, addr); h.write_4(&emulator, addr);
} }
pub fn trace_write8_asan<I, QT, S>( pub fn trace_write8_asan<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let emulator = hooks.emulator().clone(); let emulator = hooks.emulator().clone();
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
h.write_8(&emulator, addr); h.write_8(&emulator, addr);
} }
pub fn trace_write_n_asan<I, QT, S>( pub fn trace_write_n_asan<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
size: usize, size: usize,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let emulator = hooks.emulator().clone(); let emulator = hooks.emulator().clone();
let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuAsanHelper>().unwrap();
@ -604,8 +603,8 @@ pub fn trace_write_n_asan<I, QT, S>(
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn qasan_fake_syscall<I, QT, S>( pub fn qasan_fake_syscall<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
sys_num: i32, sys_num: i32,
a0: u64, a0: u64,
@ -618,8 +617,8 @@ pub fn qasan_fake_syscall<I, QT, S>(
_a7: u64, _a7: u64,
) -> SyscallHookResult ) -> SyscallHookResult
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
if sys_num == QASAN_FAKESYS_NR { if sys_num == QASAN_FAKESYS_NR {
let emulator = hooks.emulator().clone(); let emulator = hooks.emulator().clone();

View File

@ -1,5 +1,5 @@
use capstone::prelude::*; use capstone::prelude::*;
use libafl::inputs::Input; use libafl::inputs::UsesInput;
use crate::{ use crate::{
capstone, capstone,
@ -46,33 +46,33 @@ impl Default for QemuCallTracerHelper {
} }
} }
impl<I, S> QemuHelper<I, S> for QemuCallTracerHelper impl<S> QemuHelper<S> for QemuCallTracerHelper
where where
I: Input, S: UsesInput,
{ {
fn init_hooks<'a, QT>(&self, hooks: &QemuHooks<'a, I, QT, S>) fn init_hooks<'a, QT>(&self, hooks: &QemuHooks<'a, QT, S>)
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
hooks.blocks(Some(gen_blocks_calls::<I, QT, S>), None); hooks.blocks(Some(gen_blocks_calls::<QT, S>), None);
} }
fn pre_exec(&mut self, _emulator: &Emulator, _input: &I) { fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {
self.reset(); self.reset();
} }
} }
/*pub fn on_call<I, QT, S>(hooks: &mut QemuHooks<'_, I, QT, S>, _state: Option<&mut S>, pc: GuestAddr) /*pub fn on_call<QT, S>(hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, pc: GuestAddr)
where where
I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
}*/ }*/
pub fn on_ret<I, QT, S>(hooks: &mut QemuHooks<'_, I, QT, S>, _state: Option<&mut S>, _pc: GuestAddr) pub fn on_ret<QT, S>(hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _pc: GuestAddr)
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
#[cfg(cpu_target = "x86_64")] #[cfg(cpu_target = "x86_64")]
let ret_addr = { let ret_addr = {
@ -113,14 +113,14 @@ where
} }
} }
pub fn gen_blocks_calls<I, QT, S>( pub fn gen_blocks_calls<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
pc: GuestAddr, pc: GuestAddr,
) -> Option<u64> ) -> Option<u64>
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let emu = hooks.emulator(); let emu = hooks.emulator();
if let Some(h) = hooks.helpers().match_first_type::<QemuCallTracerHelper>() { if let Some(h) = hooks.helpers().match_first_type::<QemuCallTracerHelper>() {
@ -155,7 +155,7 @@ where
capstone::InsnGroupType::CS_GRP_CALL => { capstone::InsnGroupType::CS_GRP_CALL => {
// hooks.instruction_closure(insn.address() as GuestAddr, on_call, false); // hooks.instruction_closure(insn.address() as GuestAddr, on_call, false);
let call_len = insn.bytes().len() as GuestAddr; let call_len = insn.bytes().len() as GuestAddr;
let call_cb = move |hooks: &mut QemuHooks<'_, I, QT, S>, _, pc| { let call_cb = move |hooks: &mut QemuHooks<'_, QT, S>, _, pc| {
// eprintln!("CALL @ 0x{:#x}", pc + call_len); // eprintln!("CALL @ 0x{:#x}", pc + call_len);
if let Some(h) = hooks if let Some(h) = hooks
.helpers_mut() .helpers_mut()

View File

@ -1,5 +1,5 @@
use hashbrown::HashMap; use hashbrown::HashMap;
use libafl::{inputs::Input, state::HasMetadata}; use libafl::{inputs::UsesInput, state::HasMetadata};
pub use libafl_targets::{ pub use libafl_targets::{
cmplog::__libafl_targets_cmplog_instructions, CmpLogMap, CmpLogObserver, CMPLOG_MAP, cmplog::__libafl_targets_cmplog_instructions, CmpLogMap, CmpLogObserver, CMPLOG_MAP,
CMPLOG_MAP_H, CMPLOG_MAP_PTR, CMPLOG_MAP_SIZE, CMPLOG_MAP_W, CMPLOG_MAP_H, CMPLOG_MAP_PTR, CMPLOG_MAP_SIZE, CMPLOG_MAP_W,
@ -53,17 +53,16 @@ impl Default for QemuCmpLogHelper {
} }
} }
impl<I, S> QemuHelper<I, S> for QemuCmpLogHelper impl<S> QemuHelper<S> for QemuCmpLogHelper
where where
I: Input, S: UsesInput + HasMetadata,
S: HasMetadata,
{ {
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>) fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
hooks.cmps_raw( hooks.cmps_raw(
Some(gen_unique_cmp_ids::<I, QT, S>), Some(gen_unique_cmp_ids::<QT, S>),
Some(trace_cmp1_cmplog), Some(trace_cmp1_cmplog),
Some(trace_cmp2_cmplog), Some(trace_cmp2_cmplog),
Some(trace_cmp4_cmplog), Some(trace_cmp4_cmplog),
@ -95,19 +94,19 @@ impl Default for QemuCmpLogChildHelper {
} }
} }
impl<I, S> QemuHelper<I, S> for QemuCmpLogChildHelper impl<S> QemuHelper<S> for QemuCmpLogChildHelper
where where
I: Input, S: UsesInput,
S: HasMetadata, S: HasMetadata,
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = false; const HOOKS_DO_SIDE_EFFECTS: bool = false;
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>) fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
hooks.cmps_raw( hooks.cmps_raw(
Some(gen_hashed_cmp_ids::<I, QT, S>), Some(gen_hashed_cmp_ids::<QT, S>),
Some(trace_cmp1_cmplog), Some(trace_cmp1_cmplog),
Some(trace_cmp2_cmplog), Some(trace_cmp2_cmplog),
Some(trace_cmp4_cmplog), Some(trace_cmp4_cmplog),
@ -116,16 +115,16 @@ where
} }
} }
pub fn gen_unique_cmp_ids<I, QT, S>( pub fn gen_unique_cmp_ids<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
state: Option<&mut S>, state: Option<&mut S>,
pc: GuestAddr, pc: GuestAddr,
_size: usize, _size: usize,
) -> Option<u64> ) -> Option<u64>
where where
S: HasMetadata, S: HasMetadata,
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
if let Some(h) = hooks.match_helper_mut::<QemuCmpLogHelper>() { if let Some(h) = hooks.match_helper_mut::<QemuCmpLogHelper>() {
if !h.must_instrument(pc.into()) { if !h.must_instrument(pc.into()) {
@ -148,16 +147,16 @@ where
})) }))
} }
pub fn gen_hashed_cmp_ids<I, QT, S>( pub fn gen_hashed_cmp_ids<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
pc: GuestAddr, pc: GuestAddr,
_size: usize, _size: usize,
) -> Option<u64> ) -> Option<u64>
where where
S: HasMetadata, S: HasMetadata,
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
if let Some(h) = hooks.match_helper_mut::<QemuCmpLogChildHelper>() { if let Some(h) = hooks.match_helper_mut::<QemuCmpLogChildHelper>() {
if !h.must_instrument(pc.into()) { if !h.must_instrument(pc.into()) {

View File

@ -1,7 +1,7 @@
use std::{cell::UnsafeCell, cmp::max}; use std::{cell::UnsafeCell, cmp::max};
use hashbrown::{hash_map::Entry, HashMap}; use hashbrown::{hash_map::Entry, HashMap};
use libafl::{inputs::Input, state::HasMetadata}; use libafl::{inputs::UsesInput, state::HasMetadata};
pub use libafl_targets::{ pub use libafl_targets::{
edges_max_num, EDGES_MAP, EDGES_MAP_PTR, EDGES_MAP_PTR_SIZE, EDGES_MAP_SIZE, MAX_EDGES_NUM, edges_max_num, EDGES_MAP, EDGES_MAP_PTR, EDGES_MAP_PTR_SIZE, EDGES_MAP_SIZE, MAX_EDGES_NUM,
}; };
@ -66,25 +66,21 @@ impl Default for QemuEdgeCoverageHelper {
} }
} }
impl<I, S> QemuHelper<I, S> for QemuEdgeCoverageHelper impl<S> QemuHelper<S> for QemuEdgeCoverageHelper
where where
I: Input, S: UsesInput + HasMetadata,
S: HasMetadata,
{ {
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>) fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
if self.use_hitcounts { if self.use_hitcounts {
hooks.edges_raw( hooks.edges_raw(
Some(gen_unique_edge_ids::<I, QT, S>), Some(gen_unique_edge_ids::<QT, S>),
Some(trace_edge_hitcount), Some(trace_edge_hitcount),
); );
} else { } else {
hooks.edges_raw( hooks.edges_raw(Some(gen_unique_edge_ids::<QT, S>), Some(trace_edge_single));
Some(gen_unique_edge_ids::<I, QT, S>),
Some(trace_edge_single),
);
} }
} }
} }
@ -126,25 +122,25 @@ impl Default for QemuEdgeCoverageChildHelper {
} }
} }
impl<I, S> QemuHelper<I, S> for QemuEdgeCoverageChildHelper impl<S> QemuHelper<S> for QemuEdgeCoverageChildHelper
where where
I: Input, S: UsesInput,
S: HasMetadata, S: HasMetadata,
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = false; const HOOKS_DO_SIDE_EFFECTS: bool = false;
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>) fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
if self.use_hitcounts { if self.use_hitcounts {
hooks.edges_raw( hooks.edges_raw(
Some(gen_hashed_edge_ids::<I, QT, S>), Some(gen_hashed_edge_ids::<QT, S>),
Some(trace_edge_hitcount_ptr), Some(trace_edge_hitcount_ptr),
); );
} else { } else {
hooks.edges_raw( hooks.edges_raw(
Some(gen_hashed_edge_ids::<I, QT, S>), Some(gen_hashed_edge_ids::<QT, S>),
Some(trace_edge_single_ptr), Some(trace_edge_single_ptr),
); );
} }
@ -153,16 +149,16 @@ where
thread_local!(static PREV_LOC : UnsafeCell<u64> = UnsafeCell::new(0)); thread_local!(static PREV_LOC : UnsafeCell<u64> = UnsafeCell::new(0));
pub fn gen_unique_edge_ids<I, QT, S>( pub fn gen_unique_edge_ids<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
state: Option<&mut S>, state: Option<&mut S>,
src: GuestAddr, src: GuestAddr,
dest: GuestAddr, dest: GuestAddr,
) -> Option<u64> ) -> Option<u64>
where where
S: HasMetadata, S: HasMetadata,
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
if let Some(h) = hooks.helpers().match_first_type::<QemuEdgeCoverageHelper>() { if let Some(h) = hooks.helpers().match_first_type::<QemuEdgeCoverageHelper>() {
if !h.must_instrument(src.into()) && !h.must_instrument(dest.into()) { if !h.must_instrument(src.into()) && !h.must_instrument(dest.into()) {
@ -213,15 +209,15 @@ pub extern "C" fn trace_edge_single(id: u64, _data: u64) {
} }
} }
pub fn gen_hashed_edge_ids<I, QT, S>( pub fn gen_hashed_edge_ids<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
src: GuestAddr, src: GuestAddr,
dest: GuestAddr, dest: GuestAddr,
) -> Option<u64> ) -> Option<u64>
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
if let Some(h) = hooks if let Some(h) = hooks
.helpers() .helpers()
@ -250,28 +246,28 @@ pub extern "C" fn trace_edge_single_ptr(id: u64, _data: u64) {
} }
} }
pub fn gen_addr_block_ids<I, QT, S>( pub fn gen_addr_block_ids<QT, S>(
_hooks: &mut QemuHooks<'_, I, QT, S>, _hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
pc: GuestAddr, pc: GuestAddr,
) -> Option<u64> ) -> Option<u64>
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
// GuestAddress is u32 for 32 bit guests // GuestAddress is u32 for 32 bit guests
#[allow(clippy::unnecessary_cast)] #[allow(clippy::unnecessary_cast)]
Some(pc as u64) Some(pc as u64)
} }
pub fn gen_hashed_block_ids<I, QT, S>( pub fn gen_hashed_block_ids<QT, S>(
_hooks: &mut QemuHooks<'_, I, QT, S>, _hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
pc: GuestAddr, pc: GuestAddr,
) -> Option<u64> ) -> Option<u64>
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
// GuestAddress is u32 for 32 bit guests // GuestAddress is u32 for 32 bit guests
#[allow(clippy::unnecessary_cast)] #[allow(clippy::unnecessary_cast)]

View File

@ -244,8 +244,10 @@ extern "C" {
static mut libafl_start_vcpu: extern "C" fn(cpu: CPUStatePtr); static mut libafl_start_vcpu: extern "C" fn(cpu: CPUStatePtr);
/*
fn libafl_save_qemu_snapshot(name: *const u8); fn libafl_save_qemu_snapshot(name: *const u8);
fn libafl_load_qemu_snapshot(name: *const u8); fn libafl_load_qemu_snapshot(name: *const u8);
*/
} }
#[cfg(not(feature = "usermode"))] #[cfg(not(feature = "usermode"))]

View File

@ -2,40 +2,41 @@
use core::fmt::{self, Debug, Formatter}; use core::fmt::{self, Debug, Formatter};
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
use libafl::bolts::shmem::ShMemProvider; use libafl::{
#[cfg(feature = "fork")] bolts::shmem::ShMemProvider, events::EventManager, executors::InProcessForkExecutor,
use libafl::executors::InProcessForkExecutor; state::HasMetadata,
};
use libafl::{ use libafl::{
events::{EventFirer, EventRestarter}, events::{EventFirer, EventRestarter},
executors::{Executor, ExitKind, HasObservers, InProcessExecutor}, executors::{Executor, ExitKind, HasObservers, InProcessExecutor},
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::Input, inputs::UsesInput,
observers::ObserversTuple, observers::{ObserversTuple, UsesObservers},
state::{HasClientPerfMonitor, HasSolutions}, state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions, State, UsesState},
Error, Error,
}; };
pub use crate::emu::SyscallHookResult; pub use crate::emu::SyscallHookResult;
use crate::{emu::Emulator, helper::QemuHelperTuple, hooks::QemuHooks}; use crate::{emu::Emulator, helper::QemuHelperTuple, hooks::QemuHooks};
pub struct QemuExecutor<'a, H, I, OT, QT, S> pub struct QemuExecutor<'a, H, OT, QT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
hooks: &'a mut QemuHooks<'a, I, QT, S>, hooks: &'a mut QemuHooks<'a, QT, S>,
inner: InProcessExecutor<'a, H, I, OT, S>, inner: InProcessExecutor<'a, H, OT, S>,
} }
impl<'a, H, I, OT, QT, S> Debug for QemuExecutor<'a, H, I, OT, QT, S> impl<'a, H, OT, QT, S> Debug for QemuExecutor<'a, H, OT, QT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("QemuExecutor") f.debug_struct("QemuExecutor")
@ -45,15 +46,15 @@ where
} }
} }
impl<'a, H, I, OT, QT, S> QemuExecutor<'a, H, I, OT, QT, S> impl<'a, H, OT, QT, S> QemuExecutor<'a, H, OT, QT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
pub fn new<EM, OF, Z>( pub fn new<EM, OF, Z>(
hooks: &'a mut QemuHooks<'a, I, QT, S>, hooks: &'a mut QemuHooks<'a, QT, S>,
harness_fn: &'a mut H, harness_fn: &'a mut H,
observers: OT, observers: OT,
fuzzer: &mut Z, fuzzer: &mut Z,
@ -61,10 +62,10 @@ where
event_mgr: &mut EM, event_mgr: &mut EM,
) -> Result<Self, Error> ) -> Result<Self, Error>
where where
EM: EventFirer<I> + EventRestarter<S>, EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<I, S>, OF: Feedback<S>,
S: HasSolutions<I> + HasClientPerfMonitor, S: State + HasExecutions + HasCorpus + HasSolutions + HasClientPerfMonitor,
Z: HasObjective<I, OF, S>, Z: HasObjective<OF, State = S>,
{ {
Ok(Self { Ok(Self {
hooks, hooks,
@ -72,19 +73,19 @@ where
}) })
} }
pub fn inner(&self) -> &InProcessExecutor<'a, H, I, OT, S> { pub fn inner(&self) -> &InProcessExecutor<'a, H, OT, S> {
&self.inner &self.inner
} }
pub fn inner_mut(&mut self) -> &mut InProcessExecutor<'a, H, I, OT, S> { pub fn inner_mut(&mut self) -> &mut InProcessExecutor<'a, H, OT, S> {
&mut self.inner &mut self.inner
} }
pub fn hooks(&self) -> &QemuHooks<'a, I, QT, S> { pub fn hooks(&self) -> &QemuHooks<'a, QT, S> {
self.hooks self.hooks
} }
pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, I, QT, S> { pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, QT, S> {
self.hooks self.hooks
} }
@ -93,19 +94,21 @@ where
} }
} }
impl<'a, EM, H, I, OT, QT, S, Z> Executor<EM, I, S, Z> for QemuExecutor<'a, H, I, OT, QT, S> impl<'a, EM, H, OT, QT, S, Z> Executor<EM, Z> for QemuExecutor<'a, H, OT, QT, S>
where where
H: FnMut(&I) -> ExitKind, EM: UsesState<State = S>,
I: Input, H: FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<I, S>, S: UsesInput,
QT: QemuHelperTuple<I, S>, OT: ObserversTuple<S>,
QT: QemuHelperTuple<S>,
Z: UsesState<State = S>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
let emu = Emulator::new_empty(); let emu = Emulator::new_empty();
self.hooks.helpers_mut().pre_exec_all(&emu, input); self.hooks.helpers_mut().pre_exec_all(&emu, input);
@ -115,12 +118,32 @@ where
} }
} }
impl<'a, H, I, OT, QT, S> HasObservers<I, OT, S> for QemuExecutor<'a, H, I, OT, QT, S> impl<'a, H, OT, QT, S> UsesState for QemuExecutor<'a, H, OT, QT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, QT: QemuHelperTuple<S>,
QT: QemuHelperTuple<I, S>, S: UsesInput,
{
type State = S;
}
impl<'a, H, OT, QT, S> UsesObservers for QemuExecutor<'a, H, OT, QT, S>
where
H: FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<S>,
QT: QemuHelperTuple<S>,
S: UsesInput,
{
type Observers = OT;
}
impl<'a, H, OT, QT, S> HasObservers for QemuExecutor<'a, H, OT, QT, S>
where
H: FnMut(&S::Input) -> ExitKind,
S: UsesInput,
OT: ObserversTuple<S>,
QT: QemuHelperTuple<S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
@ -134,25 +157,25 @@ where
} }
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
pub struct QemuForkExecutor<'a, H, I, OT, QT, S, SP> pub struct QemuForkExecutor<'a, H, OT, QT, S, SP>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
SP: ShMemProvider, SP: ShMemProvider,
{ {
hooks: &'a mut QemuHooks<'a, I, QT, S>, hooks: &'a mut QemuHooks<'a, QT, S>,
inner: InProcessForkExecutor<'a, H, I, OT, S, SP>, inner: InProcessForkExecutor<'a, H, OT, S, SP>,
} }
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
impl<'a, H, I, OT, QT, S, SP> Debug for QemuForkExecutor<'a, H, I, OT, QT, S, SP> impl<'a, H, OT, QT, S, SP> Debug for QemuForkExecutor<'a, H, OT, QT, S, SP>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
SP: ShMemProvider, SP: ShMemProvider,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
@ -164,16 +187,16 @@ where
} }
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
impl<'a, H, I, OT, QT, S, SP> QemuForkExecutor<'a, H, I, OT, QT, S, SP> impl<'a, H, OT, QT, S, SP> QemuForkExecutor<'a, H, OT, QT, S, SP>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input, S: UsesInput,
OT: ObserversTuple<I, S>, OT: ObserversTuple<S>,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
SP: ShMemProvider, SP: ShMemProvider,
{ {
pub fn new<EM, OF, Z>( pub fn new<EM, OF, Z>(
hooks: &'a mut QemuHooks<'a, I, QT, S>, hooks: &'a mut QemuHooks<'a, QT, S>,
harness_fn: &'a mut H, harness_fn: &'a mut H,
observers: OT, observers: OT,
fuzzer: &mut Z, fuzzer: &mut Z,
@ -182,10 +205,10 @@ where
shmem_provider: SP, shmem_provider: SP,
) -> Result<Self, Error> ) -> Result<Self, Error>
where where
EM: EventFirer<I> + EventRestarter<S>, EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<I, S>, OF: Feedback<S>,
S: HasSolutions<I> + HasClientPerfMonitor, S: HasSolutions + HasClientPerfMonitor,
Z: HasObjective<I, OF, S>, Z: HasObjective<OF, State = S>,
{ {
assert!(!QT::HOOKS_DO_SIDE_EFFECTS, "When using QemuForkExecutor, the hooks must not do any side effect as they will happen in the child process and then discarded"); assert!(!QT::HOOKS_DO_SIDE_EFFECTS, "When using QemuForkExecutor, the hooks must not do any side effect as they will happen in the child process and then discarded");
@ -202,19 +225,19 @@ where
}) })
} }
pub fn inner(&self) -> &InProcessForkExecutor<'a, H, I, OT, S, SP> { pub fn inner(&self) -> &InProcessForkExecutor<'a, H, OT, S, SP> {
&self.inner &self.inner
} }
pub fn inner_mut(&mut self) -> &mut InProcessForkExecutor<'a, H, I, OT, S, SP> { pub fn inner_mut(&mut self) -> &mut InProcessForkExecutor<'a, H, OT, S, SP> {
&mut self.inner &mut self.inner
} }
pub fn hooks(&self) -> &QemuHooks<'a, I, QT, S> { pub fn hooks(&self) -> &QemuHooks<'a, QT, S> {
self.hooks self.hooks
} }
pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, I, QT, S> { pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, QT, S> {
self.hooks self.hooks
} }
@ -224,21 +247,22 @@ where
} }
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
impl<'a, EM, H, I, OT, QT, S, Z, SP> Executor<EM, I, S, Z> impl<'a, EM, H, OT, QT, S, Z, SP> Executor<EM, Z> for QemuForkExecutor<'a, H, OT, QT, S, SP>
for QemuForkExecutor<'a, H, I, OT, QT, S, SP>
where where
H: FnMut(&I) -> ExitKind, EM: EventManager<InProcessForkExecutor<'a, H, OT, S, SP>, Z, State = S>,
I: Input, H: FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<I, S>, S: UsesInput + HasClientPerfMonitor + HasMetadata + HasExecutions,
QT: QemuHelperTuple<I, S>, OT: ObserversTuple<S>,
QT: QemuHelperTuple<S>,
SP: ShMemProvider, SP: ShMemProvider,
Z: UsesState<State = S>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut Self::State,
mgr: &mut EM, mgr: &mut EM,
input: &I, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
let emu = Emulator::new_empty(); let emu = Emulator::new_empty();
self.hooks.helpers_mut().pre_exec_all(&emu, input); self.hooks.helpers_mut().pre_exec_all(&emu, input);
@ -249,12 +273,36 @@ where
} }
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
impl<'a, H, I, OT, QT, S, SP> HasObservers<I, OT, S> for QemuForkExecutor<'a, H, I, OT, QT, S, SP> impl<'a, H, OT, QT, S, SP> UsesObservers for QemuForkExecutor<'a, H, OT, QT, S, SP>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&S::Input) -> ExitKind,
I: Input, OT: ObserversTuple<S>,
OT: ObserversTuple<I, S>, QT: QemuHelperTuple<S>,
QT: QemuHelperTuple<I, S>, S: UsesInput,
SP: ShMemProvider,
{
type Observers = OT;
}
#[cfg(feature = "fork")]
impl<'a, H, OT, QT, S, SP> UsesState for QemuForkExecutor<'a, H, OT, QT, S, SP>
where
H: FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<S>,
QT: QemuHelperTuple<S>,
S: UsesInput,
SP: ShMemProvider,
{
type State = S;
}
#[cfg(feature = "fork")]
impl<'a, H, OT, QT, S, SP> HasObservers for QemuForkExecutor<'a, H, OT, QT, S, SP>
where
H: FnMut(&S::Input) -> ExitKind,
S: UsesInput,
OT: ObserversTuple<S>,
QT: QemuHelperTuple<S>,
SP: ShMemProvider, SP: ShMemProvider,
{ {
#[inline] #[inline]

View File

@ -1,82 +1,82 @@
use core::{fmt::Debug, ops::Range}; use core::{fmt::Debug, ops::Range};
use libafl::{bolts::tuples::MatchFirstType, inputs::Input}; use libafl::{bolts::tuples::MatchFirstType, inputs::UsesInput};
use crate::{emu::Emulator, hooks::QemuHooks}; use crate::{emu::Emulator, hooks::QemuHooks};
/// A helper for `libafl_qemu`. /// A helper for `libafl_qemu`.
// TODO remove 'static when specialization will be stable // TODO remove 'static when specialization will be stable
pub trait QemuHelper<I, S>: 'static + Debug pub trait QemuHelper<S>: 'static + Debug
where where
I: Input, S: UsesInput,
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = true; const HOOKS_DO_SIDE_EFFECTS: bool = true;
fn init_hooks<QT>(&self, _hooks: &QemuHooks<'_, I, QT, S>) fn init_hooks<QT>(&self, _hooks: &QemuHooks<'_, QT, S>)
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
} }
fn pre_exec(&mut self, _emulator: &Emulator, _input: &I) {} fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {}
fn post_exec(&mut self, _emulator: &Emulator, _input: &I) {} fn post_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {}
} }
pub trait QemuHelperTuple<I, S>: MatchFirstType + Debug pub trait QemuHelperTuple<S>: MatchFirstType + Debug
where where
I: Input, S: UsesInput,
{ {
const HOOKS_DO_SIDE_EFFECTS: bool; const HOOKS_DO_SIDE_EFFECTS: bool;
fn init_hooks_all<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>) fn init_hooks_all<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
where where
QT: QemuHelperTuple<I, S>; QT: QemuHelperTuple<S>;
fn pre_exec_all(&mut self, _emulator: &Emulator, input: &I); fn pre_exec_all(&mut self, _emulator: &Emulator, input: &S::Input);
fn post_exec_all(&mut self, _emulator: &Emulator, input: &I); fn post_exec_all(&mut self, _emulator: &Emulator, input: &S::Input);
} }
impl<I, S> QemuHelperTuple<I, S> for () impl<S> QemuHelperTuple<S> for ()
where where
I: Input, S: UsesInput,
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = false; const HOOKS_DO_SIDE_EFFECTS: bool = false;
fn init_hooks_all<QT>(&self, _hooks: &QemuHooks<'_, I, QT, S>) fn init_hooks_all<QT>(&self, _hooks: &QemuHooks<'_, QT, S>)
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
} }
fn pre_exec_all(&mut self, _emulator: &Emulator, _input: &I) {} fn pre_exec_all(&mut self, _emulator: &Emulator, _input: &S::Input) {}
fn post_exec_all(&mut self, _emulator: &Emulator, _input: &I) {} fn post_exec_all(&mut self, _emulator: &Emulator, _input: &S::Input) {}
} }
impl<Head, Tail, I, S> QemuHelperTuple<I, S> for (Head, Tail) impl<Head, Tail, S> QemuHelperTuple<S> for (Head, Tail)
where where
Head: QemuHelper<I, S>, Head: QemuHelper<S>,
Tail: QemuHelperTuple<I, S>, Tail: QemuHelperTuple<S>,
I: Input, S: UsesInput,
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS; const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS;
fn init_hooks_all<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>) fn init_hooks_all<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
self.0.init_hooks(hooks); self.0.init_hooks(hooks);
self.1.init_hooks_all(hooks); self.1.init_hooks_all(hooks);
} }
fn pre_exec_all(&mut self, emulator: &Emulator, input: &I) { fn pre_exec_all(&mut self, emulator: &Emulator, input: &S::Input) {
self.0.pre_exec(emulator, input); self.0.pre_exec(emulator, input);
self.1.pre_exec_all(emulator, input); self.1.pre_exec_all(emulator, input);
} }
fn post_exec_all(&mut self, emulator: &Emulator, input: &I) { fn post_exec_all(&mut self, emulator: &Emulator, input: &S::Input) {
self.0.post_exec(emulator, input); self.0.post_exec(emulator, input);
self.1.post_exec_all(emulator, input); self.1.post_exec_all(emulator, input);
} }

View File

@ -9,7 +9,7 @@ use core::{
ptr::{self, addr_of}, ptr::{self, addr_of},
}; };
use libafl::{executors::inprocess::inprocess_get_state, inputs::Input}; use libafl::{executors::inprocess::inprocess_get_state, inputs::UsesInput};
pub use crate::emu::SyscallHookResult; pub use crate::emu::SyscallHookResult;
use crate::{ use crate::{
@ -40,35 +40,35 @@ type DynamicLenHookCl<QT, S> =
*/ */
static mut QEMU_HOOKS_PTR: *const c_void = ptr::null(); static mut QEMU_HOOKS_PTR: *const c_void = ptr::null();
unsafe fn get_qemu_hooks<'a, I, QT, S>() -> &'a mut QemuHooks<'a, I, QT, S> unsafe fn get_qemu_hooks<'a, QT, S>() -> &'a mut QemuHooks<'a, QT, S>
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
(QEMU_HOOKS_PTR as *mut QemuHooks<'a, I, QT, S>) (QEMU_HOOKS_PTR as *mut QemuHooks<'a, QT, S>)
.as_mut() .as_mut()
.expect("A high-level hook is installed but QemuHooks is not initialized") .expect("A high-level hook is installed but QemuHooks is not initialized")
} }
static mut GENERIC_HOOKS: Vec<Hook> = vec![]; static mut GENERIC_HOOKS: Vec<Hook> = vec![];
extern "C" fn generic_hook_wrapper<I, QT, S>(pc: GuestAddr, index: u64) extern "C" fn generic_hook_wrapper<QT, S>(pc: GuestAddr, index: u64)
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let hook = &mut GENERIC_HOOKS[index as usize]; let hook = &mut GENERIC_HOOKS[index as usize];
match hook { match hook {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, GuestAddr) = let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr) =
transmute(*ptr); transmute(*ptr);
(func)(hooks, inprocess_get_state::<S>(), pc); (func)(hooks, inprocess_get_state::<S>(), pc);
} }
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let func: &mut Box< let func: &mut Box<
dyn FnMut(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, GuestAddr), dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr),
> = transmute(ptr); > = transmute(ptr);
(func)(hooks, inprocess_get_state::<S>(), pc); (func)(hooks, inprocess_get_state::<S>(), pc);
} }
@ -79,18 +79,18 @@ where
static mut EDGE_HOOKS: Vec<(Hook, Hook)> = vec![]; static mut EDGE_HOOKS: Vec<(Hook, Hook)> = vec![];
extern "C" fn gen_edge_hook_wrapper<I, QT, S>(src: GuestAddr, dst: GuestAddr, index: u64) -> u64 extern "C" fn gen_edge_hook_wrapper<QT, S>(src: GuestAddr, dst: GuestAddr, index: u64) -> u64
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let (gen, _) = &mut EDGE_HOOKS[index as usize]; let (gen, _) = &mut EDGE_HOOKS[index as usize];
match gen { match gen {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn( let func: fn(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
GuestAddr, GuestAddr,
GuestAddr, GuestAddr,
@ -100,7 +100,7 @@ where
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let func: &mut Box< let func: &mut Box<
dyn FnMut( dyn FnMut(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
GuestAddr, GuestAddr,
GuestAddr, GuestAddr,
@ -113,21 +113,21 @@ where
} }
} }
extern "C" fn exec_edge_hook_wrapper<I, QT, S>(id: u64, index: u64) extern "C" fn exec_edge_hook_wrapper<QT, S>(id: u64, index: u64)
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let (_, exec) = &mut EDGE_HOOKS[index as usize]; let (_, exec) = &mut EDGE_HOOKS[index as usize];
match exec { match exec {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u64) = transmute(*ptr); let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64) = transmute(*ptr);
(func)(hooks, inprocess_get_state::<S>(), id); (func)(hooks, inprocess_get_state::<S>(), id);
} }
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let func: &mut Box<dyn FnMut(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u64)> = let func: &mut Box<dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64)> =
transmute(ptr); transmute(ptr);
(func)(hooks, inprocess_get_state::<S>(), id); (func)(hooks, inprocess_get_state::<S>(), id);
} }
@ -138,30 +138,23 @@ where
static mut BLOCK_HOOKS: Vec<(Hook, Hook)> = vec![]; static mut BLOCK_HOOKS: Vec<(Hook, Hook)> = vec![];
extern "C" fn gen_block_hook_wrapper<I, QT, S>(pc: GuestAddr, index: u64) -> u64 extern "C" fn gen_block_hook_wrapper<QT, S>(pc: GuestAddr, index: u64) -> u64
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let (gen, _) = &mut BLOCK_HOOKS[index as usize]; let (gen, _) = &mut BLOCK_HOOKS[index as usize];
match gen { match gen {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn( let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr) -> Option<u64> =
&mut QemuHooks<'_, I, QT, S>, transmute(*ptr);
Option<&mut S>,
GuestAddr,
) -> Option<u64> = transmute(*ptr);
(func)(hooks, inprocess_get_state::<S>(), pc).map_or(SKIP_EXEC_HOOK, |id| id) (func)(hooks, inprocess_get_state::<S>(), pc).map_or(SKIP_EXEC_HOOK, |id| id)
} }
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let func: &mut Box< let func: &mut Box<
dyn FnMut( dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr) -> Option<u64>,
&mut QemuHooks<'_, I, QT, S>,
Option<&mut S>,
GuestAddr,
) -> Option<u64>,
> = transmute(ptr); > = transmute(ptr);
(func)(hooks, inprocess_get_state::<S>(), pc).map_or(SKIP_EXEC_HOOK, |id| id) (func)(hooks, inprocess_get_state::<S>(), pc).map_or(SKIP_EXEC_HOOK, |id| id)
} }
@ -170,21 +163,21 @@ where
} }
} }
extern "C" fn exec_block_hook_wrapper<I, QT, S>(id: u64, index: u64) extern "C" fn exec_block_hook_wrapper<QT, S>(id: u64, index: u64)
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let (_, exec) = &mut BLOCK_HOOKS[index as usize]; let (_, exec) = &mut BLOCK_HOOKS[index as usize];
match exec { match exec {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u64) = transmute(*ptr); let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64) = transmute(*ptr);
(func)(hooks, inprocess_get_state::<S>(), id); (func)(hooks, inprocess_get_state::<S>(), id);
} }
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let func: &mut Box<dyn FnMut(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u64)> = let func: &mut Box<dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64)> =
transmute(ptr); transmute(ptr);
(func)(hooks, inprocess_get_state::<S>(), id); (func)(hooks, inprocess_get_state::<S>(), id);
} }
@ -196,18 +189,18 @@ where
static mut READ_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook, Hook)> = vec![]; static mut READ_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook, Hook)> = vec![];
static mut WRITE_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook, Hook)> = vec![]; static mut WRITE_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook, Hook)> = vec![];
extern "C" fn gen_read_hook_wrapper<I, QT, S>(pc: GuestAddr, size: usize, index: u64) -> u64 extern "C" fn gen_read_hook_wrapper<QT, S>(pc: GuestAddr, size: usize, index: u64) -> u64
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let (gen, _, _, _, _, _) = &mut READ_HOOKS[index as usize]; let (gen, _, _, _, _, _) = &mut READ_HOOKS[index as usize];
match gen { match gen {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn( let func: fn(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
GuestAddr, GuestAddr,
usize, usize,
@ -217,7 +210,7 @@ where
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let func: &mut Box< let func: &mut Box<
dyn FnMut( dyn FnMut(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
GuestAddr, GuestAddr,
usize, usize,
@ -230,18 +223,18 @@ where
} }
} }
extern "C" fn gen_write_hook_wrapper<I, QT, S>(pc: GuestAddr, size: usize, index: u64) -> u64 extern "C" fn gen_write_hook_wrapper<QT, S>(pc: GuestAddr, size: usize, index: u64) -> u64
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let (gen, _, _, _, _, _) = &mut WRITE_HOOKS[index as usize]; let (gen, _, _, _, _, _) = &mut WRITE_HOOKS[index as usize];
match gen { match gen {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn( let func: fn(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
GuestAddr, GuestAddr,
usize, usize,
@ -251,7 +244,7 @@ where
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let func: &mut Box< let func: &mut Box<
dyn FnMut( dyn FnMut(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
GuestAddr, GuestAddr,
usize, usize,
@ -266,23 +259,23 @@ where
macro_rules! define_rw_exec_hook { macro_rules! define_rw_exec_hook {
($name:ident, $field:tt, $global:ident) => { ($name:ident, $field:tt, $global:ident) => {
extern "C" fn $name<I, QT, S>(id: u64, addr: GuestAddr, index: u64) extern "C" fn $name<QT, S>(id: u64, addr: GuestAddr, index: u64)
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let exec = &mut $global[index as usize].$field; let exec = &mut $global[index as usize].$field;
match exec { match exec {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u64, GuestAddr) = let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, GuestAddr) =
transmute(*ptr); transmute(*ptr);
(func)(hooks, inprocess_get_state::<S>(), id, addr); (func)(hooks, inprocess_get_state::<S>(), id, addr);
} }
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let func: &mut Box< let func: &mut Box<
dyn FnMut(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u64, GuestAddr), dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, GuestAddr),
> = transmute(ptr); > = transmute(ptr);
(func)(hooks, inprocess_get_state::<S>(), id, addr); (func)(hooks, inprocess_get_state::<S>(), id, addr);
} }
@ -295,18 +288,18 @@ macro_rules! define_rw_exec_hook {
macro_rules! define_rw_exec_hook_n { macro_rules! define_rw_exec_hook_n {
($name:ident, $field:tt, $global:ident) => { ($name:ident, $field:tt, $global:ident) => {
extern "C" fn $name<I, QT, S>(id: u64, addr: GuestAddr, size: usize, index: u64) extern "C" fn $name<QT, S>(id: u64, addr: GuestAddr, size: usize, index: u64)
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let exec = &mut $global[index as usize].$field; let exec = &mut $global[index as usize].$field;
match exec { match exec {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn( let func: fn(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
u64, u64,
GuestAddr, GuestAddr,
@ -317,7 +310,7 @@ macro_rules! define_rw_exec_hook_n {
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let func: &mut Box< let func: &mut Box<
dyn FnMut( dyn FnMut(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
u64, u64,
GuestAddr, GuestAddr,
@ -347,18 +340,18 @@ define_rw_exec_hook_n!(exec_write_n_hook_wrapper, 5, WRITE_HOOKS);
static mut CMP_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook)> = vec![]; static mut CMP_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook)> = vec![];
extern "C" fn gen_cmp_hook_wrapper<I, QT, S>(pc: GuestAddr, size: usize, index: u64) -> u64 extern "C" fn gen_cmp_hook_wrapper<QT, S>(pc: GuestAddr, size: usize, index: u64) -> u64
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let (gen, _, _, _, _) = &mut CMP_HOOKS[index as usize]; let (gen, _, _, _, _) = &mut CMP_HOOKS[index as usize];
match gen { match gen {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn( let func: fn(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
GuestAddr, GuestAddr,
usize, usize,
@ -368,7 +361,7 @@ where
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let func: &mut Box< let func: &mut Box<
dyn FnMut( dyn FnMut(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
GuestAddr, GuestAddr,
usize, usize,
@ -383,18 +376,18 @@ where
macro_rules! define_cmp_exec_hook { macro_rules! define_cmp_exec_hook {
($name:ident, $field:tt, $itype:ty) => { ($name:ident, $field:tt, $itype:ty) => {
extern "C" fn $name<I, QT, S>(id: u64, v0: $itype, v1: $itype, index: u64) extern "C" fn $name<QT, S>(id: u64, v0: $itype, v1: $itype, index: u64)
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let exec = &mut CMP_HOOKS[index as usize].$field; let exec = &mut CMP_HOOKS[index as usize].$field;
match exec { match exec {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn( let func: fn(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
u64, u64,
$itype, $itype,
@ -405,7 +398,7 @@ macro_rules! define_cmp_exec_hook {
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let func: &mut Box< let func: &mut Box<
dyn FnMut( dyn FnMut(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
u64, u64,
$itype, $itype,
@ -429,31 +422,29 @@ define_cmp_exec_hook!(exec_cmp8_hook_wrapper, 4, u64);
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
static mut ON_THREAD_HOOKS: Vec<Hook> = vec![]; static mut ON_THREAD_HOOKS: Vec<Hook> = vec![];
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
extern "C" fn on_thread_hooks_wrapper<I, QT, S>(tid: u32) extern "C" fn on_thread_hooks_wrapper<QT, S>(tid: u32)
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
for hook in &mut ON_THREAD_HOOKS { for hook in &mut ON_THREAD_HOOKS {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
match hook { match hook {
Hook::Function(ptr) => { Hook::Function(ptr) => {
let func: fn(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u32) = let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u32) = transmute(*ptr);
transmute(*ptr);
(func)(hooks, inprocess_get_state::<S>(), tid); (func)(hooks, inprocess_get_state::<S>(), tid);
} }
Hook::Closure(ptr) => { Hook::Closure(ptr) => {
let mut func: Box< let mut func: Box<dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u32)> =
dyn FnMut(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u32), transmute(*ptr);
> = transmute(*ptr);
(func)(hooks, inprocess_get_state::<S>(), tid); (func)(hooks, inprocess_get_state::<S>(), tid);
// Forget the closure so that drop is not called on captured variables. // Forget the closure so that drop is not called on captured variables.
core::mem::forget(func); core::mem::forget(func);
} }
Hook::Once(ptr) => { Hook::Once(ptr) => {
let func: Box<dyn FnOnce(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u32)> = let func: Box<dyn FnOnce(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u32)> =
transmute(*ptr); transmute(*ptr);
(func)(hooks, inprocess_get_state::<S>(), tid); (func)(hooks, inprocess_get_state::<S>(), tid);
*hook = Hook::Empty; *hook = Hook::Empty;
@ -467,7 +458,7 @@ where
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
static mut SYSCALL_HOOKS: Vec<Hook> = vec![]; static mut SYSCALL_HOOKS: Vec<Hook> = vec![];
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
extern "C" fn syscall_hooks_wrapper<I, QT, S>( extern "C" fn syscall_hooks_wrapper<QT, S>(
sys_num: i32, sys_num: i32,
a0: u64, a0: u64,
a1: u64, a1: u64,
@ -479,18 +470,18 @@ extern "C" fn syscall_hooks_wrapper<I, QT, S>(
a7: u64, a7: u64,
) -> SyscallHookResult ) -> SyscallHookResult
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let mut res = SyscallHookResult::new(None); let mut res = SyscallHookResult::new(None);
for hook in &SYSCALL_HOOKS { for hook in &SYSCALL_HOOKS {
match hook { match hook {
Hook::Function(ptr) => { Hook::Function(ptr) => {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
let func: fn( let func: fn(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
i32, i32,
u64, u64,
@ -524,7 +515,7 @@ where
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
let mut func: Box< let mut func: Box<
dyn FnMut( dyn FnMut(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
i32, i32,
u64, u64,
@ -569,7 +560,7 @@ where
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
static mut SYSCALL_POST_HOOKS: Vec<Hook> = vec![]; static mut SYSCALL_POST_HOOKS: Vec<Hook> = vec![];
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
extern "C" fn syscall_after_hooks_wrapper<I, QT, S>( extern "C" fn syscall_after_hooks_wrapper<QT, S>(
result: u64, result: u64,
sys_num: i32, sys_num: i32,
a0: u64, a0: u64,
@ -582,18 +573,18 @@ extern "C" fn syscall_after_hooks_wrapper<I, QT, S>(
a7: u64, a7: u64,
) -> u64 ) -> u64
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
unsafe { unsafe {
let hooks = get_qemu_hooks::<I, QT, S>(); let hooks = get_qemu_hooks::<QT, S>();
let mut res = result; let mut res = result;
for hook in &SYSCALL_POST_HOOKS { for hook in &SYSCALL_POST_HOOKS {
match hook { match hook {
Hook::Function(ptr) => { Hook::Function(ptr) => {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
let func: fn( let func: fn(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
u64, u64,
i32, i32,
@ -625,7 +616,7 @@ where
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
let mut func: Box< let mut func: Box<
dyn FnMut( dyn FnMut(
&mut QemuHooks<'_, I, QT, S>, &mut QemuHooks<'_, QT, S>,
Option<&mut S>, Option<&mut S>,
u64, u64,
i32, i32,
@ -666,20 +657,20 @@ where
static mut HOOKS_IS_INITIALIZED: bool = false; static mut HOOKS_IS_INITIALIZED: bool = false;
pub struct QemuHooks<'a, I, QT, S> pub struct QemuHooks<'a, QT, S>
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
I: Input, S: UsesInput,
{ {
helpers: QT, helpers: QT,
emulator: &'a Emulator, emulator: &'a Emulator,
phantom: PhantomData<(I, S)>, phantom: PhantomData<S>,
} }
impl<'a, I, QT, S> Debug for QemuHooks<'a, I, QT, S> impl<'a, QT, S> Debug for QemuHooks<'a, QT, S>
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("QemuHooks") f.debug_struct("QemuHooks")
@ -689,10 +680,10 @@ where
} }
} }
impl<'a, I, QT, S> QemuHooks<'a, I, QT, S> impl<'a, QT, S> QemuHooks<'a, QT, S>
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
I: Input, S: UsesInput,
{ {
pub fn new(emulator: &'a Emulator, helpers: QT) -> Box<Self> { pub fn new(emulator: &'a Emulator, helpers: QT) -> Box<Self> {
unsafe { unsafe {
@ -754,7 +745,7 @@ where
let index = GENERIC_HOOKS.len(); let index = GENERIC_HOOKS.len();
self.emulator.set_hook( self.emulator.set_hook(
addr, addr,
generic_hook_wrapper::<I, QT, S>, generic_hook_wrapper::<QT, S>,
index as u64, index as u64,
invalidate_block, invalidate_block,
); );
@ -771,7 +762,7 @@ where
let index = GENERIC_HOOKS.len(); let index = GENERIC_HOOKS.len();
self.emulator.set_hook( self.emulator.set_hook(
addr, addr,
generic_hook_wrapper::<I, QT, S>, generic_hook_wrapper::<QT, S>,
index as u64, index as u64,
invalidate_block, invalidate_block,
); );
@ -791,12 +782,12 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_edge_hook_wrapper::<I, QT, S>) Some(gen_edge_hook_wrapper::<QT, S>)
}, },
if execution_hook.is_none() { if execution_hook.is_none() {
None None
} else { } else {
Some(exec_edge_hook_wrapper::<I, QT, S>) Some(exec_edge_hook_wrapper::<QT, S>)
}, },
index as u64, index as u64,
); );
@ -823,12 +814,12 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_edge_hook_wrapper::<I, QT, S>) Some(gen_edge_hook_wrapper::<QT, S>)
}, },
if execution_hook.is_none() { if execution_hook.is_none() {
None None
} else { } else {
Some(exec_edge_hook_wrapper::<I, QT, S>) Some(exec_edge_hook_wrapper::<QT, S>)
}, },
index as u64, index as u64,
); );
@ -851,7 +842,7 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_edge_hook_wrapper::<I, QT, S>) Some(gen_edge_hook_wrapper::<QT, S>)
}, },
execution_hook, execution_hook,
index as u64, index as u64,
@ -876,12 +867,12 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_block_hook_wrapper::<I, QT, S>) Some(gen_block_hook_wrapper::<QT, S>)
}, },
if execution_hook.is_none() { if execution_hook.is_none() {
None None
} else { } else {
Some(exec_block_hook_wrapper::<I, QT, S>) Some(exec_block_hook_wrapper::<QT, S>)
}, },
index as u64, index as u64,
); );
@ -908,12 +899,12 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_block_hook_wrapper::<I, QT, S>) Some(gen_block_hook_wrapper::<QT, S>)
}, },
if execution_hook.is_none() { if execution_hook.is_none() {
None None
} else { } else {
Some(exec_block_hook_wrapper::<I, QT, S>) Some(exec_block_hook_wrapper::<QT, S>)
}, },
index as u64, index as u64,
); );
@ -934,7 +925,7 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_block_hook_wrapper::<I, QT, S>) Some(gen_block_hook_wrapper::<QT, S>)
}, },
execution_hook, execution_hook,
index as u64, index as u64,
@ -967,32 +958,32 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_read_hook_wrapper::<I, QT, S>) Some(gen_read_hook_wrapper::<QT, S>)
}, },
if execution_hook1.is_none() { if execution_hook1.is_none() {
None None
} else { } else {
Some(exec_read1_hook_wrapper::<I, QT, S>) Some(exec_read1_hook_wrapper::<QT, S>)
}, },
if execution_hook2.is_none() { if execution_hook2.is_none() {
None None
} else { } else {
Some(exec_read2_hook_wrapper::<I, QT, S>) Some(exec_read2_hook_wrapper::<QT, S>)
}, },
if execution_hook4.is_none() { if execution_hook4.is_none() {
None None
} else { } else {
Some(exec_read4_hook_wrapper::<I, QT, S>) Some(exec_read4_hook_wrapper::<QT, S>)
}, },
if execution_hook8.is_none() { if execution_hook8.is_none() {
None None
} else { } else {
Some(exec_read8_hook_wrapper::<I, QT, S>) Some(exec_read8_hook_wrapper::<QT, S>)
}, },
if execution_hook_n.is_none() { if execution_hook_n.is_none() {
None None
} else { } else {
Some(exec_read_n_hook_wrapper::<I, QT, S>) Some(exec_read_n_hook_wrapper::<QT, S>)
}, },
index as u64, index as u64,
); );
@ -1037,32 +1028,32 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_read_hook_wrapper::<I, QT, S>) Some(gen_read_hook_wrapper::<QT, S>)
}, },
if execution_hook1.is_none() { if execution_hook1.is_none() {
None None
} else { } else {
Some(exec_read1_hook_wrapper::<I, QT, S>) Some(exec_read1_hook_wrapper::<QT, S>)
}, },
if execution_hook2.is_none() { if execution_hook2.is_none() {
None None
} else { } else {
Some(exec_read2_hook_wrapper::<I, QT, S>) Some(exec_read2_hook_wrapper::<QT, S>)
}, },
if execution_hook4.is_none() { if execution_hook4.is_none() {
None None
} else { } else {
Some(exec_read4_hook_wrapper::<I, QT, S>) Some(exec_read4_hook_wrapper::<QT, S>)
}, },
if execution_hook8.is_none() { if execution_hook8.is_none() {
None None
} else { } else {
Some(exec_read8_hook_wrapper::<I, QT, S>) Some(exec_read8_hook_wrapper::<QT, S>)
}, },
if execution_hook_n.is_none() { if execution_hook_n.is_none() {
None None
} else { } else {
Some(exec_read_n_hook_wrapper::<I, QT, S>) Some(exec_read_n_hook_wrapper::<QT, S>)
}, },
index as u64, index as u64,
); );
@ -1093,7 +1084,7 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_read_hook_wrapper::<I, QT, S>) Some(gen_read_hook_wrapper::<QT, S>)
}, },
execution_hook1, execution_hook1,
execution_hook2, execution_hook2,
@ -1134,32 +1125,32 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_write_hook_wrapper::<I, QT, S>) Some(gen_write_hook_wrapper::<QT, S>)
}, },
if execution_hook1.is_none() { if execution_hook1.is_none() {
None None
} else { } else {
Some(exec_write1_hook_wrapper::<I, QT, S>) Some(exec_write1_hook_wrapper::<QT, S>)
}, },
if execution_hook2.is_none() { if execution_hook2.is_none() {
None None
} else { } else {
Some(exec_write2_hook_wrapper::<I, QT, S>) Some(exec_write2_hook_wrapper::<QT, S>)
}, },
if execution_hook4.is_none() { if execution_hook4.is_none() {
None None
} else { } else {
Some(exec_write4_hook_wrapper::<I, QT, S>) Some(exec_write4_hook_wrapper::<QT, S>)
}, },
if execution_hook8.is_none() { if execution_hook8.is_none() {
None None
} else { } else {
Some(exec_write8_hook_wrapper::<I, QT, S>) Some(exec_write8_hook_wrapper::<QT, S>)
}, },
if execution_hook_n.is_none() { if execution_hook_n.is_none() {
None None
} else { } else {
Some(exec_write_n_hook_wrapper::<I, QT, S>) Some(exec_write_n_hook_wrapper::<QT, S>)
}, },
index as u64, index as u64,
); );
@ -1204,32 +1195,32 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_write_hook_wrapper::<I, QT, S>) Some(gen_write_hook_wrapper::<QT, S>)
}, },
if execution_hook1.is_none() { if execution_hook1.is_none() {
None None
} else { } else {
Some(exec_write1_hook_wrapper::<I, QT, S>) Some(exec_write1_hook_wrapper::<QT, S>)
}, },
if execution_hook2.is_none() { if execution_hook2.is_none() {
None None
} else { } else {
Some(exec_write2_hook_wrapper::<I, QT, S>) Some(exec_write2_hook_wrapper::<QT, S>)
}, },
if execution_hook4.is_none() { if execution_hook4.is_none() {
None None
} else { } else {
Some(exec_write4_hook_wrapper::<I, QT, S>) Some(exec_write4_hook_wrapper::<QT, S>)
}, },
if execution_hook8.is_none() { if execution_hook8.is_none() {
None None
} else { } else {
Some(exec_write8_hook_wrapper::<I, QT, S>) Some(exec_write8_hook_wrapper::<QT, S>)
}, },
if execution_hook_n.is_none() { if execution_hook_n.is_none() {
None None
} else { } else {
Some(exec_write_n_hook_wrapper::<I, QT, S>) Some(exec_write_n_hook_wrapper::<QT, S>)
}, },
index as u64, index as u64,
); );
@ -1260,7 +1251,7 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_write_hook_wrapper::<I, QT, S>) Some(gen_write_hook_wrapper::<QT, S>)
}, },
execution_hook1, execution_hook1,
execution_hook2, execution_hook2,
@ -1298,27 +1289,27 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_cmp_hook_wrapper::<I, QT, S>) Some(gen_cmp_hook_wrapper::<QT, S>)
}, },
if execution_hook1.is_none() { if execution_hook1.is_none() {
None None
} else { } else {
Some(exec_cmp1_hook_wrapper::<I, QT, S>) Some(exec_cmp1_hook_wrapper::<QT, S>)
}, },
if execution_hook2.is_none() { if execution_hook2.is_none() {
None None
} else { } else {
Some(exec_cmp2_hook_wrapper::<I, QT, S>) Some(exec_cmp2_hook_wrapper::<QT, S>)
}, },
if execution_hook4.is_none() { if execution_hook4.is_none() {
None None
} else { } else {
Some(exec_cmp4_hook_wrapper::<I, QT, S>) Some(exec_cmp4_hook_wrapper::<QT, S>)
}, },
if execution_hook8.is_none() { if execution_hook8.is_none() {
None None
} else { } else {
Some(exec_cmp8_hook_wrapper::<I, QT, S>) Some(exec_cmp8_hook_wrapper::<QT, S>)
}, },
index as u64, index as u64,
); );
@ -1357,27 +1348,27 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_cmp_hook_wrapper::<I, QT, S>) Some(gen_cmp_hook_wrapper::<QT, S>)
}, },
if execution_hook1.is_none() { if execution_hook1.is_none() {
None None
} else { } else {
Some(exec_cmp1_hook_wrapper::<I, QT, S>) Some(exec_cmp1_hook_wrapper::<QT, S>)
}, },
if execution_hook2.is_none() { if execution_hook2.is_none() {
None None
} else { } else {
Some(exec_cmp2_hook_wrapper::<I, QT, S>) Some(exec_cmp2_hook_wrapper::<QT, S>)
}, },
if execution_hook4.is_none() { if execution_hook4.is_none() {
None None
} else { } else {
Some(exec_cmp4_hook_wrapper::<I, QT, S>) Some(exec_cmp4_hook_wrapper::<QT, S>)
}, },
if execution_hook8.is_none() { if execution_hook8.is_none() {
None None
} else { } else {
Some(exec_cmp8_hook_wrapper::<I, QT, S>) Some(exec_cmp8_hook_wrapper::<QT, S>)
}, },
index as u64, index as u64,
); );
@ -1406,7 +1397,7 @@ where
if generation_hook.is_none() { if generation_hook.is_none() {
None None
} else { } else {
Some(gen_cmp_hook_wrapper::<I, QT, S>) Some(gen_cmp_hook_wrapper::<QT, S>)
}, },
execution_hook1, execution_hook1,
execution_hook2, execution_hook2,
@ -1432,7 +1423,7 @@ where
ON_THREAD_HOOKS.push(Hook::Function(hook as *const libc::c_void)); ON_THREAD_HOOKS.push(Hook::Function(hook as *const libc::c_void));
} }
self.emulator self.emulator
.set_on_thread_hook(on_thread_hooks_wrapper::<I, QT, S>); .set_on_thread_hook(on_thread_hooks_wrapper::<QT, S>);
} }
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
@ -1444,7 +1435,7 @@ where
ON_THREAD_HOOKS.push(Hook::Closure(transmute(hook))); ON_THREAD_HOOKS.push(Hook::Closure(transmute(hook)));
} }
self.emulator self.emulator
.set_on_thread_hook(on_thread_hooks_wrapper::<I, QT, S>); .set_on_thread_hook(on_thread_hooks_wrapper::<QT, S>);
} }
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
@ -1453,7 +1444,7 @@ where
ON_THREAD_HOOKS.push(Hook::Once(transmute(hook))); ON_THREAD_HOOKS.push(Hook::Once(transmute(hook)));
} }
self.emulator self.emulator
.set_on_thread_hook(on_thread_hooks_wrapper::<I, QT, S>); .set_on_thread_hook(on_thread_hooks_wrapper::<QT, S>);
} }
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
@ -1478,7 +1469,7 @@ where
SYSCALL_HOOKS.push(Hook::Function(hook as *const libc::c_void)); SYSCALL_HOOKS.push(Hook::Function(hook as *const libc::c_void));
} }
self.emulator self.emulator
.set_pre_syscall_hook(syscall_hooks_wrapper::<I, QT, S>); .set_pre_syscall_hook(syscall_hooks_wrapper::<QT, S>);
} }
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
@ -1505,7 +1496,7 @@ where
SYSCALL_HOOKS.push(Hook::Closure(transmute(hook))); SYSCALL_HOOKS.push(Hook::Closure(transmute(hook)));
} }
self.emulator self.emulator
.set_pre_syscall_hook(syscall_hooks_wrapper::<I, QT, S>); .set_pre_syscall_hook(syscall_hooks_wrapper::<QT, S>);
} }
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
@ -1531,7 +1522,7 @@ where
SYSCALL_POST_HOOKS.push(Hook::Function(hook as *const libc::c_void)); SYSCALL_POST_HOOKS.push(Hook::Function(hook as *const libc::c_void));
} }
self.emulator self.emulator
.set_post_syscall_hook(syscall_after_hooks_wrapper::<I, QT, S>); .set_post_syscall_hook(syscall_after_hooks_wrapper::<QT, S>);
} }
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
@ -1559,6 +1550,6 @@ where
SYSCALL_POST_HOOKS.push(Hook::Closure(transmute(hook))); SYSCALL_POST_HOOKS.push(Hook::Closure(transmute(hook)));
} }
self.emulator self.emulator
.set_post_syscall_hook(syscall_after_hooks_wrapper::<I, QT, S>); .set_post_syscall_hook(syscall_after_hooks_wrapper::<QT, S>);
} }
} }

View File

@ -4,7 +4,7 @@ use std::{
sync::Mutex, sync::Mutex,
}; };
use libafl::{inputs::Input, state::HasMetadata}; use libafl::{inputs::UsesInput, state::HasMetadata};
use meminterval::{Interval, IntervalTree}; use meminterval::{Interval, IntervalTree};
use thread_local::ThreadLocal; use thread_local::ThreadLocal;
@ -468,31 +468,30 @@ impl Default for QemuSnapshotHelper {
} }
} }
impl<I, S> QemuHelper<I, S> for QemuSnapshotHelper impl<S> QemuHelper<S> for QemuSnapshotHelper
where where
I: Input, S: UsesInput + HasMetadata,
S: HasMetadata,
{ {
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, I, QT, S>) fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
where where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
hooks.writes( hooks.writes(
None, None,
Some(trace_write1_snapshot::<I, QT, S>), Some(trace_write1_snapshot::<QT, S>),
Some(trace_write2_snapshot::<I, QT, S>), Some(trace_write2_snapshot::<QT, S>),
Some(trace_write4_snapshot::<I, QT, S>), Some(trace_write4_snapshot::<QT, S>),
Some(trace_write8_snapshot::<I, QT, S>), Some(trace_write8_snapshot::<QT, S>),
Some(trace_write_n_snapshot::<I, QT, S>), Some(trace_write_n_snapshot::<QT, S>),
); );
if !self.accurate_unmap { if !self.accurate_unmap {
hooks.syscalls(filter_mmap_snapshot::<I, QT, S>); hooks.syscalls(filter_mmap_snapshot::<QT, S>);
} }
hooks.after_syscalls(trace_mmap_snapshot::<I, QT, S>); hooks.after_syscalls(trace_mmap_snapshot::<QT, S>);
} }
fn pre_exec(&mut self, emulator: &Emulator, _input: &I) { fn pre_exec(&mut self, emulator: &Emulator, _input: &S::Input) {
if self.empty { if self.empty {
self.snapshot(emulator); self.snapshot(emulator);
} else { } else {
@ -501,67 +500,67 @@ where
} }
} }
pub fn trace_write1_snapshot<I, QT, S>( pub fn trace_write1_snapshot<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
h.access(addr, 1); h.access(addr, 1);
} }
pub fn trace_write2_snapshot<I, QT, S>( pub fn trace_write2_snapshot<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
h.access(addr, 2); h.access(addr, 2);
} }
pub fn trace_write4_snapshot<I, QT, S>( pub fn trace_write4_snapshot<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
h.access(addr, 4); h.access(addr, 4);
} }
pub fn trace_write8_snapshot<I, QT, S>( pub fn trace_write8_snapshot<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
h.access(addr, 8); h.access(addr, 8);
} }
pub fn trace_write_n_snapshot<I, QT, S>( pub fn trace_write_n_snapshot<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_id: u64, _id: u64,
addr: GuestAddr, addr: GuestAddr,
size: usize, size: usize,
) where ) where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
h.access(addr, size); h.access(addr, size);
@ -569,8 +568,8 @@ pub fn trace_write_n_snapshot<I, QT, S>(
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub fn filter_mmap_snapshot<I, QT, S>( pub fn filter_mmap_snapshot<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
sys_num: i32, sys_num: i32,
a0: u64, a0: u64,
@ -583,8 +582,8 @@ pub fn filter_mmap_snapshot<I, QT, S>(
_a7: u64, _a7: u64,
) -> SyscallHookResult ) -> SyscallHookResult
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
if i64::from(sys_num) == SYS_munmap { if i64::from(sys_num) == SYS_munmap {
let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap(); let h = hooks.match_helper_mut::<QemuSnapshotHelper>().unwrap();
@ -597,8 +596,8 @@ where
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub fn trace_mmap_snapshot<I, QT, S>( pub fn trace_mmap_snapshot<QT, S>(
hooks: &mut QemuHooks<'_, I, QT, S>, hooks: &mut QemuHooks<'_, QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
result: u64, result: u64,
sys_num: i32, sys_num: i32,
@ -612,8 +611,8 @@ pub fn trace_mmap_snapshot<I, QT, S>(
_a7: u64, _a7: u64,
) -> u64 ) -> u64
where where
I: Input, S: UsesInput,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<S>,
{ {
// NOT A COMPLETE LIST OF MEMORY EFFECTS // NOT A COMPLETE LIST OF MEMORY EFFECTS
match i64::from(sys_num) { match i64::from(sys_num) {

View File

@ -114,7 +114,7 @@ impl<'a, const MAP_SIZE: usize> ForkserverBytesCoverageSugar<'a, MAP_SIZE> {
let monitor = MultiMonitor::new(|s| println!("{s}")); let monitor = MultiMonitor::new(|s| println!("{s}"));
let mut run_client = |state: Option<_>, let mut run_client = |state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _, _>, mut mgr: LlmpRestartingEventManager<_, _>,
_core_id| { _core_id| {
// Coverage map shared between target and fuzzer // Coverage map shared between target and fuzzer
let mut shmem = shmem_provider_client.new_shmem(MAP_SIZE).unwrap(); let mut shmem = shmem_provider_client.new_shmem(MAP_SIZE).unwrap();

Some files were not shown because too many files have changed in this diff Show More