Remove Input associated type (#2854)

* Completely remove Input as an associated type in multiple traits

* Unify usage of Input as generic instead 

* Remove many unused bounds, in particular HasCorpus

* fix multiple generic ordering

* update and fix CONTRIBUTING.md

* update MIGRATION

* use the same generic input type for new / with_max_iterations to make typing easier in most cases.

* Restore libafl_libfuzzer test in CI
This commit is contained in:
Romain Malmain 2025-01-17 14:53:51 +01:00 committed by GitHub
parent d4add04f87
commit f8ad61e14a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
126 changed files with 1614 additions and 1994 deletions

View File

@ -290,7 +290,7 @@ jobs:
- ./fuzzers/structure_aware/forkserver_simple_nautilus - ./fuzzers/structure_aware/forkserver_simple_nautilus
# In-process # In-process
# - ./fuzzers/fuzz_anything/cargo_fuzz # Revive after they fix rustc - ./fuzzers/fuzz_anything/cargo_fuzz
# - ./fuzzers/inprocess/dynamic_analysis # - ./fuzzers/inprocess/dynamic_analysis
- ./fuzzers/inprocess/fuzzbench - ./fuzzers/inprocess/fuzzbench
- ./fuzzers/inprocess/fuzzbench_text - ./fuzzers/inprocess/fuzzbench_text

View File

@ -27,7 +27,7 @@ Before making your pull requests, try to see if your code follows these rules.
- `PhantomData` should have the smallest set of types needed. Try not adding `PhantomData` to your struct unless it is really necessary. Also even when you really need `PhantomData`, try to keep the types `T` used in `PhantomData` as smallest as possible - `PhantomData` should have the smallest set of types needed. Try not adding `PhantomData` to your struct unless it is really necessary. Also even when you really need `PhantomData`, try to keep the types `T` used in `PhantomData` as smallest as possible
- Wherever possible, trait implementations with lifetime specifiers should use '_ lifetime elision. - Wherever possible, trait implementations with lifetime specifiers should use '_ lifetime elision.
- Complex constructors should be replaced with `typed_builder`, or write code in the builder pattern for yourself. - Complex constructors should be replaced with `typed_builder`, or write code in the builder pattern for yourself.
- Remove generic restrictions at the definitions (e.g., we do not need to specify that types impl `Serialize`, `Deserialize`, or `Debug` anymore at the struct definitions). Therefore, try avoiding code like this unless the contraint is really necessary. - Remove generic restrictions at the definitions (e.g., we do not need to specify that types impl `Serialize`, `Deserialize`, or `Debug` anymore at the struct definitions). Therefore, try avoiding code like this unless the constraint is really necessary.
```rust ```rust
pub struct X<A> pub struct X<A>
where where
@ -35,9 +35,8 @@ pub struct X<A>
{ {
fn ... fn ...
} }
``` ```
- Reduce generics to the least restrictive necessary. __Never overspecify the contraints__. There's no automated tool to check the useless constraints, so you have to verify this manually. - Reduce generics to the least restrictive necessary. __Never overspecify the constraints__. There's no automated tool to check the useless constraints, so you have to verify this manually.
```rust ```rust
pub struct X<A> pub struct X<A>
where where
@ -45,17 +44,37 @@ pub struct X<A>
{ {
fn ... fn ...
} }
``` ```
- Traits which have an associated type should refer to the associated type, not the concrete/generic. In other words, you should only have the associated type when you can define a getter to it. For example, in the following code, you can define a associate type.
- Prefer generic to associated types in traits definition as much as possible. They are much easier to use around, and avoid tricky caveats / type repetition in the code. It is also much easier to have unconstrained struct definitions.
Try not to write this:
```rust
pub trait X
{
type A;
fn a(&self) -> Self::A;
}
```
Try to write this instead:
```rust
pub trait X<A>
{
fn a(&self) -> A;
}
```
- Traits which have an associated type (if you have made sure you cannot use a generic instead) should refer to the associated type, not the concrete/generic. In other words, you should only have the associated type when you can define a getter to it. For example, in the following code, you can define a associate type.
```rust ```rust
pub trait X pub trait X
{ {
type A; // <- You should(can) define it as long as you have a getter to it. type A; // <- You should(can) define it as long as you have a getter to it.
fn a(&self) -> A;
}
fn a(&self) -> Self::A;
}
``` ```
- __Ideally__ the types used in the the arguments of methods in traits should have the same as the types defined on the traits. - __Ideally__ the types used in the the arguments of methods in traits should have the same as the types defined on the traits.
```rust ```rust
pub trait X<A, B, C> // <- this trait have 3 generics, A, B, and C pub trait X<A, B, C> // <- this trait have 3 generics, A, B, and C

View File

@ -14,7 +14,9 @@
- Trait restrictions have been simplified - Trait restrictions have been simplified
- The `UsesState` and `UsesInput` traits have been removed in favor of regular Generics. - The `UsesState` and `UsesInput` traits have been removed in favor of regular Generics.
- For the structs/traits that used to use `UsesState`, we bring back the generic for the state. - For the structs/traits that used to use `UsesState`, we bring back the generic for the state.
- For `UsesState`, you can access to the input type through `HasCorpus` and `Corpus` traits - `Input` is now only accessible through generic. `Input` associated types have been definitely removed.
- `HasCorpus` bound has been removed in many places it was unused before.
- `StdMutationalStage::transforming` must now explicitly state the Inputs types. As a result, `StdMutationalStage::transforming` must be written `StdMutationalStage::<_, _, FirstInputType, SecondInputType, _, _, _>::transforming`.
- The `State` trait is now private in favour of individual and more specific traits - The `State` trait is now private in favour of individual and more specific traits
- Restrictions from certain schedulers and stages that required their inner observer to implement `MapObserver` have been lifted in favor of requiring `Hash` - Restrictions from certain schedulers and stages that required their inner observer to implement `MapObserver` have been lifted in favor of requiring `Hash`
- Related: removed `hash_simple` from `MapObserver` - Related: removed `hash_simple` from `MapObserver`

View File

@ -47,17 +47,17 @@ impl<S> CustomExecutor<S> {
} }
} }
impl<EM, S, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z> for CustomExecutor<S> impl<EM, I, S, Z> Executor<EM, I, S, Z> for CustomExecutor<S>
where where
S: HasCorpus + HasExecutions, S: HasCorpus<I> + HasExecutions,
<S::Corpus as Corpus>::Input: HasTargetBytes, I: HasTargetBytes,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
state: &mut S, state: &mut S,
_mgr: &mut EM, _mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
) -> Result<ExitKind, libafl::Error> { ) -> Result<ExitKind, libafl::Error> {
// We need to keep track of the exec count. // We need to keep track of the exec count.
*state.executions_mut() += 1; *state.executions_mut() += 1;

View File

@ -13,7 +13,10 @@ use libafl::{
feedbacks::{CrashFeedback, MaxMapFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
mutators::{StdScheduledMutator, UnicodeCategoryRandMutator, UnicodeSubcategoryRandMutator}, mutators::{
StdScheduledMutator, UnicodeCategoryRandMutator, UnicodeInput,
UnicodeSubcategoryRandMutator,
},
observers::StdMapObserver, observers::StdMapObserver,
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::{mutational::StdMutationalStage, UnicodeIdentificationStage}, stages::{mutational::StdMutationalStage, UnicodeIdentificationStage},
@ -134,7 +137,7 @@ pub fn main() {
)); ));
let mut stages = tuple_list!( let mut stages = tuple_list!(
UnicodeIdentificationStage::new(), UnicodeIdentificationStage::new(),
StdMutationalStage::transforming(mutator) StdMutationalStage::<_, _, UnicodeInput, BytesInput, _, _, _>::transforming(mutator)
); );
fuzzer fuzzer

View File

@ -1,11 +1,10 @@
use std::borrow::Cow; use std::borrow::Cow;
use libafl::{ use libafl::{
corpus::{Corpus, Testcase}, corpus::Testcase,
executors::ExitKind, executors::ExitKind,
feedbacks::{Feedback, MapIndexesMetadata, StateInitializer}, feedbacks::{Feedback, MapIndexesMetadata, StateInitializer},
schedulers::{MinimizerScheduler, TestcaseScore}, schedulers::{MinimizerScheduler, TestcaseScore},
state::HasCorpus,
Error, HasMetadata, Error, HasMetadata,
}; };
use libafl_bolts::{Named, SerdeAny}; use libafl_bolts::{Named, SerdeAny};
@ -20,14 +19,11 @@ pub struct PacketLenMetadata {
pub struct PacketLenTestcaseScore {} pub struct PacketLenTestcaseScore {}
impl<S> TestcaseScore<S> for PacketLenTestcaseScore impl<I, S> TestcaseScore<I, S> for PacketLenTestcaseScore
where where
S: HasMetadata + HasCorpus, S: HasMetadata,
{ {
fn compute( fn compute(_state: &S, entry: &mut Testcase<I>) -> Result<f64, Error> {
_state: &S,
entry: &mut Testcase<<S::Corpus as Corpus>::Input>,
) -> Result<f64, Error> {
Ok(entry Ok(entry
.metadata_map() .metadata_map()
.get::<PacketLenMetadata>() .get::<PacketLenMetadata>()
@ -35,8 +31,8 @@ where
} }
} }
pub type PacketLenMinimizerScheduler<CS, S> = pub type PacketLenMinimizerScheduler<CS, I, S> =
MinimizerScheduler<CS, PacketLenTestcaseScore, MapIndexesMetadata, S>; MinimizerScheduler<CS, PacketLenTestcaseScore, I, MapIndexesMetadata, S>;
#[derive(Serialize, Deserialize, Default, Clone, Debug)] #[derive(Serialize, Deserialize, Default, Clone, Debug)]
pub struct PacketLenFeedback { pub struct PacketLenFeedback {

View File

@ -96,7 +96,7 @@ unsafe fn fuzz(
let shmem_provider = StdShMemProvider::new()?; let shmem_provider = StdShMemProvider::new()?;
let mut run_client = |state: Option<_>, let mut run_client = |state: Option<_>,
mgr: LlmpRestartingEventManager<_, _, _>, mgr: LlmpRestartingEventManager<_, _, _, _>,
client_description: ClientDescription| { client_description: ClientDescription| {
// 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.
@ -104,7 +104,7 @@ unsafe fn fuzz(
if options.asan && options.asan_cores.contains(client_description.core_id()) { if options.asan && options.asan_cores.contains(client_description.core_id()) {
(|state: Option<_>, (|state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>, mut mgr: LlmpRestartingEventManager<_, _, _, _>,
_client_description| { _client_description| {
let gum = Gum::obtain(); let gum = Gum::obtain();
@ -231,7 +231,7 @@ unsafe fn fuzz(
})(state, mgr, client_description) })(state, mgr, client_description)
} else if options.cmplog && options.cmplog_cores.contains(client_description.core_id()) { } else if options.cmplog && options.cmplog_cores.contains(client_description.core_id()) {
(|state: Option<_>, (|state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>, mut mgr: LlmpRestartingEventManager<_, _, _, _>,
_client_description| { _client_description| {
let gum = Gum::obtain(); let gum = Gum::obtain();
@ -367,7 +367,7 @@ unsafe fn fuzz(
})(state, mgr, client_description) })(state, mgr, client_description)
} else { } else {
(|state: Option<_>, (|state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>, mut mgr: LlmpRestartingEventManager<_, _, _, _>,
_client_description| { _client_description| {
let gum = Gum::obtain(); let gum = Gum::obtain();

View File

@ -81,7 +81,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
}; };
let mut run_client = |state: Option<_>, let mut run_client = |state: Option<_>,
mgr: LlmpRestartingEventManager<_, _, _>, mgr: LlmpRestartingEventManager<_, _, _, _>,
client_description: ClientDescription| { client_description: ClientDescription| {
// 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.
@ -100,7 +100,9 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
}; };
// if options.asan && options.asan_cores.contains(client_description.core_id()) { // if options.asan && options.asan_cores.contains(client_description.core_id()) {
(|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _>, _client_description| { (|state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _, _>,
_client_description| {
let gum = Gum::obtain(); let gum = Gum::obtain();
let coverage = CoverageRuntime::new(); let coverage = CoverageRuntime::new();

View File

@ -78,7 +78,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<_, _, _>, mgr: LlmpRestartingEventManager<_, _, _, _>,
client_description: ClientDescription| { client_description: ClientDescription| {
// 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.
@ -98,7 +98,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
if options.asan && options.asan_cores.contains(client_description.core_id()) { if options.asan && options.asan_cores.contains(client_description.core_id()) {
(|state: Option<_>, (|state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>, mut mgr: LlmpRestartingEventManager<_, _, _, _>,
_client_description| { _client_description| {
let gum = Gum::obtain(); let gum = Gum::obtain();
@ -214,7 +214,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
})(state, mgr, client_description) })(state, mgr, client_description)
} else if options.cmplog && options.cmplog_cores.contains(client_description.core_id()) { } else if options.cmplog && options.cmplog_cores.contains(client_description.core_id()) {
(|state: Option<_>, (|state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>, mut mgr: LlmpRestartingEventManager<_, _, _, _>,
_client_description| { _client_description| {
let gum = Gum::obtain(); let gum = Gum::obtain();
@ -344,7 +344,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
})(state, mgr, client_description) })(state, mgr, client_description)
} else { } else {
(|state: Option<_>, (|state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>, mut mgr: LlmpRestartingEventManager<_, _, _, _>,
_client_description| { _client_description| {
let gum = Gum::obtain(); let gum = Gum::obtain();

View File

@ -9,8 +9,7 @@ use clap::{builder::Str, Parser};
use libafl::{ use libafl::{
corpus::{Corpus, InMemoryCorpus}, corpus::{Corpus, InMemoryCorpus},
events::{ events::{
launcher::Launcher, ClientDescription, EventConfig, EventRestarter, launcher::Launcher, ClientDescription, EventConfig, LlmpRestartingEventManager, ManagerExit,
LlmpRestartingEventManager, ManagerExit,
}, },
executors::ExitKind, executors::ExitKind,
fuzzer::StdFuzzer, fuzzer::StdFuzzer,
@ -31,7 +30,7 @@ use libafl_bolts::{
use libafl_qemu::{ use libafl_qemu::{
elf::EasyElf, elf::EasyElf,
modules::{drcov::DrCovModule, utils::filters::StdAddressFilter}, modules::{drcov::DrCovModule, utils::filters::StdAddressFilter},
ArchExtras, CallingConvention, Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExecutor, ArchExtras, CallingConvention, Emulator, GuestAddr, GuestReg, MmapPerms, QemuExecutor,
QemuExitReason, QemuRWError, QemuShutdownCause, Regs, QemuExitReason, QemuRWError, QemuShutdownCause, Regs,
}; };
@ -124,7 +123,7 @@ pub fn fuzz() {
env::remove_var("LD_LIBRARY_PATH"); env::remove_var("LD_LIBRARY_PATH");
let mut run_client = |state: Option<_>, let mut run_client = |state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>, mut mgr: LlmpRestartingEventManager<_, _, _, _>,
client_description: ClientDescription| { client_description: ClientDescription| {
let mut cov_path = options.coverage_path.clone(); let mut cov_path = options.coverage_path.clone();

View File

@ -23,7 +23,7 @@ use crate::{
#[expect(clippy::module_name_repetitions)] #[expect(clippy::module_name_repetitions)]
pub type ClientState = pub type ClientState =
StdState<BytesInput, InMemoryOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>; StdState<InMemoryOnDiskCorpus<BytesInput>, BytesInput, StdRand, OnDiskCorpus<BytesInput>>;
pub struct Client<'a> { pub struct Client<'a> {
options: &'a FuzzerOptions, options: &'a FuzzerOptions,

View File

@ -52,13 +52,15 @@ use typed_builder::TypedBuilder;
use crate::{harness::Harness, options::FuzzerOptions}; use crate::{harness::Harness, options::FuzzerOptions};
pub type ClientState = pub type ClientState =
StdState<BytesInput, InMemoryOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>; StdState<InMemoryOnDiskCorpus<BytesInput>, BytesInput, StdRand, OnDiskCorpus<BytesInput>>;
#[cfg(feature = "simplemgr")] #[cfg(feature = "simplemgr")]
pub type ClientMgr<M> = SimpleEventManager<M, ClientState>; pub type ClientMgr<M> = SimpleEventManager<M, ClientState>;
#[cfg(not(feature = "simplemgr"))] #[cfg(not(feature = "simplemgr"))]
pub type ClientMgr<M> = pub type ClientMgr<M> = MonitorTypedEventManager<
MonitorTypedEventManager<LlmpRestartingEventManager<(), ClientState, StdShMemProvider>, M>; LlmpRestartingEventManager<(), BytesInput, ClientState, StdShMemProvider>,
M,
>;
#[derive(TypedBuilder)] #[derive(TypedBuilder)]
pub struct Instance<'a, M: Monitor> { pub struct Instance<'a, M: Monitor> {
@ -321,7 +323,7 @@ impl<M: Monitor> Instance<'_, M> {
stages: &mut ST, stages: &mut ST,
) -> Result<(), Error> ) -> Result<(), Error>
where where
Z: Fuzzer<E, ClientMgr<M>, ClientState, ST> Z: Fuzzer<E, ClientMgr<M>, BytesInput, ClientState, ST>
+ Evaluator<E, ClientMgr<M>, BytesInput, ClientState>, + Evaluator<E, ClientMgr<M>, BytesInput, ClientState>,
ST: StagesTuple<E, ClientMgr<M>, ClientState, Z>, ST: StagesTuple<E, ClientMgr<M>, ClientState, Z>,
{ {

View File

@ -376,7 +376,7 @@ fn fuzz(
let cb = |_fuzzer: &mut _, let cb = |_fuzzer: &mut _,
_executor: &mut _, _executor: &mut _,
state: &mut StdState<_, InMemoryOnDiskCorpus<_>, _, _>, state: &mut StdState<InMemoryOnDiskCorpus<_>, _, _, _>,
_event_manager: &mut _| _event_manager: &mut _|
-> Result<bool, Error> { -> Result<bool, Error> {
let testcase = state.current_testcase()?; let testcase = state.current_testcase()?;

View File

@ -6,7 +6,6 @@ use std::{
}; };
use libafl::{ use libafl::{
corpus::Corpus,
executors::{Executor, ExitKind, HasObservers, HasTimeout}, executors::{Executor, ExitKind, HasObservers, HasTimeout},
state::HasCorpus, state::HasCorpus,
Error, Error,
@ -253,25 +252,23 @@ fn check_file_found(file: &Path, perm: u32) -> bool {
} }
#[cfg(feature = "nyx")] #[cfg(feature = "nyx")]
pub enum SupportedExecutors<S, OT, FSV, NYX> { pub enum SupportedExecutors<FSV, I, OT, NYX> {
Forkserver(FSV, PhantomData<(S, OT, NYX)>), Forkserver(FSV, PhantomData<(FSV, I, OT)>),
Nyx(NYX), Nyx(NYX),
} }
#[cfg(feature = "nyx")] #[cfg(feature = "nyx")]
impl<S, OT, FSV, NYX, EM, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z> impl<S, I, OT, FSV, NYX, EM, Z> Executor<EM, I, S, Z> for SupportedExecutors<FSV, I, OT, NYX>
for SupportedExecutors<S, OT, FSV, NYX>
where where
S: HasCorpus, NYX: Executor<EM, I, S, Z>,
NYX: Executor<EM, <S::Corpus as Corpus>::Input, S, Z>, FSV: Executor<EM, I, S, Z>,
FSV: Executor<EM, <S::Corpus as Corpus>::Input, S, Z>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut S,
mgr: &mut EM, mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
match self { match self {
Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input), Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input),
@ -282,7 +279,7 @@ where
} }
#[cfg(feature = "nyx")] #[cfg(feature = "nyx")]
impl<S, OT, FSV, NYX> HasObservers for SupportedExecutors<S, OT, FSV, NYX> impl<FSV, I, OT, NYX> HasObservers for SupportedExecutors<FSV, I, OT, NYX>
where where
NYX: HasObservers<Observers = OT>, NYX: HasObservers<Observers = OT>,
FSV: HasObservers<Observers = OT>, FSV: HasObservers<Observers = OT>,
@ -308,7 +305,7 @@ where
} }
#[cfg(feature = "nyx")] #[cfg(feature = "nyx")]
impl<S, OT, FSV, NYX> HasTimeout for SupportedExecutors<S, OT, FSV, NYX> impl<FSV, I, OT, NYX> HasTimeout for SupportedExecutors<FSV, I, OT, NYX>
where where
FSV: HasTimeout, FSV: HasTimeout,
NYX: HasTimeout, NYX: HasTimeout,
@ -330,23 +327,22 @@ where
} }
#[cfg(not(feature = "nyx"))] #[cfg(not(feature = "nyx"))]
pub enum SupportedExecutors<S, OT, FSV> { pub enum SupportedExecutors<FSV, I, OT, S> {
Forkserver(FSV, PhantomData<(S, OT)>), Forkserver(FSV, PhantomData<(I, OT, S)>),
} }
#[cfg(not(feature = "nyx"))] #[cfg(not(feature = "nyx"))]
impl<S, OT, FSV, EM, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z> impl<S, I, OT, FSV, EM, Z> Executor<EM, I, S, Z> for SupportedExecutors<FSV, I, OT, S>
for SupportedExecutors<S, OT, FSV>
where where
S: HasCorpus, S: HasCorpus<I>,
FSV: Executor<EM, <S::Corpus as Corpus>::Input, S, Z>, FSV: Executor<EM, I, S, Z>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut S,
mgr: &mut EM, mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
match self { match self {
Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input), Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input),
@ -355,7 +351,7 @@ where
} }
#[cfg(not(feature = "nyx"))] #[cfg(not(feature = "nyx"))]
impl<S, OT, FSV> HasObservers for SupportedExecutors<S, OT, FSV> impl<FSV, I, OT, S> HasObservers for SupportedExecutors<FSV, I, OT, S>
where where
FSV: HasObservers<Observers = OT>, FSV: HasObservers<Observers = OT>,
{ {
@ -376,7 +372,7 @@ where
} }
#[cfg(not(feature = "nyx"))] #[cfg(not(feature = "nyx"))]
impl<S, OT, FSV> HasTimeout for SupportedExecutors<S, OT, FSV> impl<FSV, I, OT, S> HasTimeout for SupportedExecutors<FSV, I, OT, S>
where where
FSV: HasTimeout, FSV: HasTimeout,
{ {

View File

@ -4,10 +4,9 @@ use std::{
}; };
use libafl::{ use libafl::{
corpus::{Corpus, Testcase}, corpus::Testcase,
executors::ExitKind, executors::ExitKind,
feedbacks::{Feedback, FeedbackFactory, StateInitializer}, feedbacks::{Feedback, FeedbackFactory, StateInitializer},
state::HasCorpus,
}; };
use libafl_bolts::{Error, Named}; use libafl_bolts::{Error, Named};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -53,18 +52,16 @@ impl<F> Named for CustomFilepathToTestcaseFeedback<F> {
impl<F, S> StateInitializer<S> for CustomFilepathToTestcaseFeedback<F> {} impl<F, S> StateInitializer<S> for CustomFilepathToTestcaseFeedback<F> {}
impl<F, EM, OT, S> Feedback<EM, <S::Corpus as Corpus>::Input, OT, S> impl<F, EM, I, OT, S> Feedback<EM, I, OT, S> for CustomFilepathToTestcaseFeedback<F>
for CustomFilepathToTestcaseFeedback<F>
where where
S: HasCorpus, F: FnMut(&mut S, &mut Testcase<I>, &Path) -> Result<(), Error>,
F: FnMut(&mut S, &mut Testcase<<S::Corpus as Corpus>::Input>, &Path) -> Result<(), Error>,
{ {
#[inline] #[inline]
fn is_interesting( fn is_interesting(
&mut self, &mut self,
_state: &mut S, _state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_input: &<S::Corpus as Corpus>::Input, _input: &I,
_observers: &OT, _observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
@ -76,7 +73,7 @@ where
state: &mut S, state: &mut S,
_manager: &mut EM, _manager: &mut EM,
_observers: &OT, _observers: &OT,
testcase: &mut Testcase<<S::Corpus as Corpus>::Input>, testcase: &mut Testcase<I>,
) -> Result<(), Error> { ) -> Result<(), Error> {
(self.func)(state, testcase, &self.out_dir)?; (self.func)(state, testcase, &self.out_dir)?;
Ok(()) Ok(())

View File

@ -52,8 +52,7 @@ impl<I, S> StateInitializer<S> for PersitentRecordFeedback<I> {}
impl<EM, I, OT, S> Feedback<EM, I, OT, S> for PersitentRecordFeedback<I> impl<EM, I, OT, S> Feedback<EM, I, OT, S> for PersitentRecordFeedback<I>
where where
S: HasCorpus, S: HasCorpus<I>,
S::Corpus: Corpus<Input = I>,
I: Input, I: Input,
{ {
#[inline] #[inline]

View File

@ -73,12 +73,13 @@ use crate::{
}; };
pub type LibaflFuzzState = pub type LibaflFuzzState =
StdState<BytesInput, CachedOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>; StdState<CachedOnDiskCorpus<BytesInput>, BytesInput, StdRand, OnDiskCorpus<BytesInput>>;
#[cfg(not(feature = "fuzzbench"))] #[cfg(not(feature = "fuzzbench"))]
type LibaflFuzzManager = CentralizedEventManager< type LibaflFuzzManager = CentralizedEventManager<
LlmpRestartingEventManager<(), LibaflFuzzState, StdShMemProvider>, LlmpRestartingEventManager<(), BytesInput, LibaflFuzzState, StdShMemProvider>,
(), (),
BytesInput,
LibaflFuzzState, LibaflFuzzState,
StdShMemProvider, StdShMemProvider,
>; >;
@ -521,7 +522,7 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
); );
// Run our fuzzer; WITH CmpLog // Run our fuzzer; WITH CmpLog
run_fuzzer_with_stages( run_fuzzer_with_stages::<_, _, BytesInput, _, _, _>(
opt, opt,
&mut fuzzer, &mut fuzzer,
&mut stages, &mut stages,
@ -540,7 +541,7 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
); );
// Run our fuzzer; NO CmpLog // Run our fuzzer; NO CmpLog
run_fuzzer_with_stages( run_fuzzer_with_stages::<_, _, BytesInput, _, _, _>(
opt, opt,
&mut fuzzer, &mut fuzzer,
&mut stages, &mut stages,
@ -648,7 +649,7 @@ pub fn fuzzer_target_mode(opt: &Opt) -> Cow<'static, str> {
#[derive(Debug, Serialize, Deserialize, SerdeAny)] #[derive(Debug, Serialize, Deserialize, SerdeAny)]
pub struct IsInitialCorpusEntryMetadata {} pub struct IsInitialCorpusEntryMetadata {}
pub fn run_fuzzer_with_stages<E, EM, S, ST, Z>( pub fn run_fuzzer_with_stages<E, EM, I, S, ST, Z>(
opt: &Opt, opt: &Opt,
fuzzer: &mut Z, fuzzer: &mut Z,
stages: &mut ST, stages: &mut ST,
@ -657,7 +658,7 @@ pub fn run_fuzzer_with_stages<E, EM, S, ST, Z>(
mgr: &mut EM, mgr: &mut EM,
) -> Result<(), Error> ) -> Result<(), Error>
where where
Z: Fuzzer<E, EM, S, ST>, Z: Fuzzer<E, EM, I, S, ST>,
EM: ProgressReporter<S>, EM: ProgressReporter<S>,
ST: StagesTuple<E, EM, S, Z>, ST: StagesTuple<E, EM, S, Z>,
S: HasLastReportTime + HasExecutions + HasMetadata, S: HasLastReportTime + HasExecutions + HasMetadata,

View File

@ -1,7 +1,6 @@
use libafl::{ use libafl::{
corpus::Corpus,
events::{Event, EventManagerHook}, events::{Event, EventManagerHook},
state::{HasCorpus, Stoppable}, state::Stoppable,
Error, Error,
}; };
use libafl_bolts::ClientId; use libafl_bolts::ClientId;
@ -11,15 +10,15 @@ pub struct LibAflFuzzEventHook {
exit_on_solution: bool, exit_on_solution: bool,
} }
impl<S> EventManagerHook<<S::Corpus as Corpus>::Input, S> for LibAflFuzzEventHook impl<I, S> EventManagerHook<I, S> for LibAflFuzzEventHook
where where
S: HasCorpus + Stoppable, S: Stoppable,
{ {
fn pre_exec( fn pre_exec(
&mut self, &mut self,
state: &mut S, state: &mut S,
_client_id: ClientId, _client_id: ClientId,
event: &Event<<S::Corpus as Corpus>::Input>, event: &Event<I>,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
if self.exit_on_solution && matches!(event, Event::Objective { .. }) { if self.exit_on_solution && matches!(event, Event::Objective { .. }) {
// TODO: dump state // TODO: dump state

View File

@ -13,19 +13,17 @@ pub enum SupportedSchedulers<Q, W> {
Weighted(W, PhantomData<Q>), Weighted(W, PhantomData<Q>),
} }
impl<Q, S, W> RemovableScheduler<<S::Corpus as Corpus>::Input, S> for SupportedSchedulers<Q, W> impl<I, Q, S, W> RemovableScheduler<I, S> for SupportedSchedulers<Q, W>
where where
Q: Scheduler<<S::Corpus as Corpus>::Input, S> Q: Scheduler<I, S> + RemovableScheduler<I, S>,
+ RemovableScheduler<<S::Corpus as Corpus>::Input, S>, W: Scheduler<I, S> + RemovableScheduler<I, S>,
W: Scheduler<<S::Corpus as Corpus>::Input, S> S: HasTestcase<I>,
+ RemovableScheduler<<S::Corpus as Corpus>::Input, S>,
S: HasCorpus + HasTestcase,
{ {
fn on_remove( fn on_remove(
&mut self, &mut self,
state: &mut S, state: &mut S,
id: CorpusId, id: CorpusId,
testcase: &Option<Testcase<<S::Corpus as Corpus>::Input>>, testcase: &Option<Testcase<I>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
match self { match self {
Self::Queue(queue, _) => queue.on_remove(state, id, testcase), Self::Queue(queue, _) => queue.on_remove(state, id, testcase),
@ -33,12 +31,7 @@ where
} }
} }
fn on_replace( fn on_replace(&mut self, state: &mut S, id: CorpusId, prev: &Testcase<I>) -> Result<(), Error> {
&mut self,
state: &mut S,
id: CorpusId,
prev: &Testcase<<S::Corpus as Corpus>::Input>,
) -> Result<(), Error> {
match self { match self {
Self::Queue(queue, _) => queue.on_replace(state, id, prev), Self::Queue(queue, _) => queue.on_replace(state, id, prev),
Self::Weighted(weighted, _) => weighted.on_replace(state, id, prev), Self::Weighted(weighted, _) => weighted.on_replace(state, id, prev),
@ -46,11 +39,11 @@ where
} }
} }
impl<Q, S, W> Scheduler<<S::Corpus as Corpus>::Input, S> for SupportedSchedulers<Q, W> impl<I, Q, S, W> Scheduler<I, S> for SupportedSchedulers<Q, W>
where where
Q: Scheduler<<S::Corpus as Corpus>::Input, S>, Q: Scheduler<I, S>,
W: Scheduler<<S::Corpus as Corpus>::Input, S>, W: Scheduler<I, S>,
S: HasCorpus + HasTestcase, S: HasCorpus<I> + HasTestcase<I>,
{ {
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
match self { match self {
@ -82,12 +75,7 @@ where
Self::Weighted(weighted, _) => weighted.next(state), Self::Weighted(weighted, _) => weighted.next(state),
} }
} }
fn on_evaluation<OTB>( fn on_evaluation<OTB>(&mut self, state: &mut S, input: &I, observers: &OTB) -> Result<(), Error>
&mut self,
state: &mut S,
input: &<S::Corpus as Corpus>::Input,
observers: &OTB,
) -> Result<(), Error>
where where
OTB: MatchName, OTB: MatchName,
{ {

View File

@ -23,7 +23,7 @@ use libafl::{
feedback_or, feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, GeneralizedInputMetadata, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
grimoire::{ grimoire::{
@ -604,7 +604,10 @@ fn fuzz_text(
3, 3,
); );
let grimoire = StdMutationalStage::transforming(grimoire_mutator); let grimoire =
StdMutationalStage::<_, _, GeneralizedInputMetadata, BytesInput, _, _, _>::transforming(
grimoire_mutator,
);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new( let scheduler = IndexesLenTimeMinimizerScheduler::new(

View File

@ -141,7 +141,7 @@ pub extern "C" fn libafl_main() {
let mut secondary_run_client = let mut secondary_run_client =
|state: Option<_>, |state: Option<_>,
mut mgr: CentralizedEventManager<_, _, _, _>, mut mgr: CentralizedEventManager<_, _, _, _, _>,
_client_description: ClientDescription| { _client_description: ClientDescription| {
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = let edges_observer =

View File

@ -219,7 +219,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let orig_size = state.corpus().count(); let orig_size = state.corpus().count();
let msg = "Started distillation...".to_string(); let msg = "Started distillation...".to_string();
<LlmpRestartingEventManager<_, _, _> as EventFirer<BytesInput, _>>::log( <LlmpRestartingEventManager<_, _, _, _> as EventFirer<BytesInput, _>>::log(
&mut restarting_mgr, &mut restarting_mgr,
&mut state, &mut state,
LogSeverity::Info, LogSeverity::Info,
@ -227,7 +227,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
)?; )?;
minimizer.minimize(&mut fuzzer, &mut executor, &mut restarting_mgr, &mut state)?; minimizer.minimize(&mut fuzzer, &mut executor, &mut restarting_mgr, &mut state)?;
let msg = format!("Distilled out {} cases", orig_size - state.corpus().count()); let msg = format!("Distilled out {} cases", orig_size - state.corpus().count());
<LlmpRestartingEventManager<_, _, _> as EventFirer<BytesInput, _>>::log( <LlmpRestartingEventManager<_, _, _, _> as EventFirer<BytesInput, _>>::log(
&mut restarting_mgr, &mut restarting_mgr,
&mut state, &mut state,
LogSeverity::Info, LogSeverity::Info,

View File

@ -162,7 +162,7 @@ pub extern "C" fn libafl_main() {
); );
let mut run_client = |state: Option<_>, let mut run_client = |state: Option<_>,
mut restarting_mgr: LlmpRestartingEventManager<_, _, _>, mut restarting_mgr: LlmpRestartingEventManager<_, _, _, _>,
client_description: ClientDescription| { client_description: ClientDescription| {
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = let edges_observer =

View File

@ -8,7 +8,7 @@ use libafl::{
executors::{inprocess::InProcessExecutor, ExitKind}, executors::{inprocess::InProcessExecutor, ExitKind},
feedbacks::{CrashFeedback, MaxMapFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Evaluator, Fuzzer, StdFuzzer}, fuzzer::{Evaluator, Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, GeneralizedInputMetadata, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
havoc_mutations, scheduled::StdScheduledMutator, GrimoireExtensionMutator, havoc_mutations, scheduled::StdScheduledMutator, GrimoireExtensionMutator,
@ -157,7 +157,9 @@ pub fn main() {
let mut stages = tuple_list!( let mut stages = tuple_list!(
generalization, generalization,
StdMutationalStage::new(mutator), StdMutationalStage::new(mutator),
StdMutationalStage::transforming(grimoire_mutator) StdMutationalStage::<_, _, GeneralizedInputMetadata, BytesInput, _, _, _>::transforming(
grimoire_mutator
)
); );
for input in initial_inputs { for input in initial_inputs {

View File

@ -9,7 +9,7 @@ use libafl_bolts::ClientId;
pub fn main() { pub fn main() {
let mut monitor = TuiMonitor::builder().build(); let mut monitor = TuiMonitor::builder().build();
let client_stats = ClientStats { let _client_stats = ClientStats {
corpus_size: 1024, corpus_size: 1024,
executions: 512, executions: 512,
..ClientStats::default() ..ClientStats::default()

View File

@ -1,7 +1,7 @@
//! The [`CachedOnDiskCorpus`] stores [`Testcase`]s to disk, keeping a subset of them in memory/cache, evicting in a FIFO manner. //! The [`CachedOnDiskCorpus`] stores [`Testcase`]s to disk, keeping a subset of them in memory/cache, evicting in a FIFO manner.
use alloc::{collections::vec_deque::VecDeque, string::String}; use alloc::{collections::vec_deque::VecDeque, string::String};
use core::cell::RefCell; use core::cell::{Ref, RefCell, RefMut};
use std::path::Path; use std::path::Path;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -55,12 +55,11 @@ where
Ok(()) Ok(())
} }
} }
impl<I> Corpus for CachedOnDiskCorpus<I>
impl<I> Corpus<I> for CachedOnDiskCorpus<I>
where where
I: Input, I: Input,
{ {
type Input = I;
/// Returns the number of all enabled entries /// Returns the number of all enabled entries
#[inline] #[inline]
fn count(&self) -> usize { fn count(&self) -> usize {
@ -98,7 +97,7 @@ where
} }
/// Removes an entry from the corpus, returning it if it was present; considers both enabled and disabled testcases. /// Removes an entry from the corpus, returning it if it was present; considers both enabled and disabled testcases.
fn remove(&mut self, id: CorpusId) -> Result<Testcase<Self::Input>, Error> { fn remove(&mut self, id: CorpusId) -> Result<Testcase<I>, Error> {
let testcase = self.inner.remove(id)?; let testcase = self.inner.remove(id)?;
self.cached_indexes.borrow_mut().retain(|e| *e != id); self.cached_indexes.borrow_mut().retain(|e| *e != id);
Ok(testcase) Ok(testcase)
@ -113,7 +112,7 @@ where
} }
/// Get by id; considers both enabled and disabled testcases /// Get by id; considers both enabled and disabled testcases
#[inline] #[inline]
fn get_from_all(&self, id: CorpusId) -> Result<&RefCell<Testcase<Self::Input>>, Error> { fn get_from_all(&self, id: CorpusId) -> Result<&RefCell<Testcase<I>>, Error> {
let testcase = { self.inner.get_from_all(id)? }; let testcase = { self.inner.get_from_all(id)? };
self.cache_testcase(testcase, id)?; self.cache_testcase(testcase, id)?;
Ok(testcase) Ok(testcase)
@ -169,25 +168,25 @@ where
} }
#[inline] #[inline]
fn load_input_into(&self, testcase: &mut Testcase<Self::Input>) -> Result<(), Error> { fn load_input_into(&self, testcase: &mut Testcase<I>) -> Result<(), Error> {
self.inner.load_input_into(testcase) self.inner.load_input_into(testcase)
} }
#[inline] #[inline]
fn store_input_from(&self, testcase: &Testcase<Self::Input>) -> Result<(), Error> { fn store_input_from(&self, testcase: &Testcase<I>) -> Result<(), Error> {
self.inner.store_input_from(testcase) self.inner.store_input_from(testcase)
} }
} }
impl<I> HasTestcase for CachedOnDiskCorpus<I> impl<I> HasTestcase<I> for CachedOnDiskCorpus<I>
where where
I: Input, I: Input,
{ {
fn testcase(&self, id: CorpusId) -> Result<core::cell::Ref<Testcase<I>>, Error> { fn testcase(&self, id: CorpusId) -> Result<Ref<Testcase<I>>, Error> {
Ok(self.get(id)?.borrow()) Ok(self.get(id)?.borrow())
} }
fn testcase_mut(&self, id: CorpusId) -> Result<core::cell::RefMut<Testcase<I>>, Error> { fn testcase_mut(&self, id: CorpusId) -> Result<RefMut<Testcase<I>>, Error> {
Ok(self.get(id)?.borrow_mut()) Ok(self.get(id)?.borrow_mut())
} }
} }

View File

@ -1,7 +1,7 @@
//! In-memory corpus, keeps all test cases in memory at all times //! In-memory corpus, keeps all test cases in memory at all times
use alloc::vec::Vec; use alloc::vec::Vec;
use core::cell::RefCell; use core::cell::{Ref, RefCell, RefMut};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -314,9 +314,7 @@ pub struct InMemoryCorpus<I> {
current: Option<CorpusId>, current: Option<CorpusId>,
} }
impl<I> Corpus for InMemoryCorpus<I> { impl<I> Corpus<I> for InMemoryCorpus<I> {
type Input = I;
/// Returns the number of all enabled entries /// Returns the number of all enabled entries
#[inline] #[inline]
fn count(&self) -> usize { fn count(&self) -> usize {
@ -360,7 +358,7 @@ impl<I> Corpus for InMemoryCorpus<I> {
/// Removes an entry from the corpus, returning it if it was present; considers both enabled and disabled testcases /// Removes an entry from the corpus, returning it if it was present; considers both enabled and disabled testcases
#[inline] #[inline]
fn remove(&mut self, id: CorpusId) -> Result<Testcase<Self::Input>, Error> { fn remove(&mut self, id: CorpusId) -> Result<Testcase<I>, Error> {
let mut testcase = self.storage.enabled.remove(id); let mut testcase = self.storage.enabled.remove(id);
if testcase.is_none() { if testcase.is_none() {
testcase = self.storage.disabled.remove(id); testcase = self.storage.disabled.remove(id);
@ -380,7 +378,7 @@ impl<I> Corpus for InMemoryCorpus<I> {
} }
/// Get by id; considers both enabled and disabled testcases /// Get by id; considers both enabled and disabled testcases
#[inline] #[inline]
fn get_from_all(&self, id: CorpusId) -> Result<&RefCell<Testcase<Self::Input>>, Error> { fn get_from_all(&self, id: CorpusId) -> Result<&RefCell<Testcase<I>>, Error> {
let mut testcase = self.storage.enabled.get(id); let mut testcase = self.storage.enabled.get(id);
if testcase.is_none() { if testcase.is_none() {
testcase = self.storage.disabled.get(id); testcase = self.storage.disabled.get(id);
@ -400,17 +398,17 @@ impl<I> Corpus for InMemoryCorpus<I> {
&mut self.current &mut self.current
} }
#[inline]
fn next(&self, id: CorpusId) -> Option<CorpusId> {
self.storage.enabled.next(id)
}
/// Peek the next free corpus id /// Peek the next free corpus id
#[inline] #[inline]
fn peek_free_id(&self) -> CorpusId { fn peek_free_id(&self) -> CorpusId {
self.storage.peek_free_id() self.storage.peek_free_id()
} }
#[inline]
fn next(&self, id: CorpusId) -> Option<CorpusId> {
self.storage.enabled.next(id)
}
#[inline] #[inline]
fn prev(&self, id: CorpusId) -> Option<CorpusId> { fn prev(&self, id: CorpusId) -> Option<CorpusId> {
self.storage.enabled.prev(id) self.storage.enabled.prev(id)
@ -443,29 +441,23 @@ impl<I> Corpus for InMemoryCorpus<I> {
} }
#[inline] #[inline]
fn load_input_into(&self, _: &mut Testcase<Self::Input>) -> Result<(), Error> { fn load_input_into(&self, _: &mut Testcase<I>) -> Result<(), Error> {
// Inputs never get evicted, nothing to load here. // Inputs never get evicted, nothing to load here.
Ok(()) Ok(())
} }
#[inline] #[inline]
fn store_input_from(&self, _: &Testcase<Self::Input>) -> Result<(), Error> { fn store_input_from(&self, _: &Testcase<I>) -> Result<(), Error> {
Ok(()) Ok(())
} }
} }
impl<I> HasTestcase for InMemoryCorpus<I> { impl<I> HasTestcase<I> for InMemoryCorpus<I> {
fn testcase( fn testcase(&self, id: CorpusId) -> Result<Ref<Testcase<I>>, Error> {
&self,
id: CorpusId,
) -> Result<core::cell::Ref<Testcase<<Self::Corpus as Corpus>::Input>>, Error> {
Ok(self.get(id)?.borrow()) Ok(self.get(id)?.borrow())
} }
fn testcase_mut( fn testcase_mut(&self, id: CorpusId) -> Result<RefMut<Testcase<I>>, Error> {
&self,
id: CorpusId,
) -> Result<core::cell::RefMut<Testcase<<Self::Corpus as Corpus>::Input>>, Error> {
Ok(self.get(id)?.borrow_mut()) Ok(self.get(id)?.borrow_mut())
} }
} }

View File

@ -5,7 +5,7 @@
//! which only stores a certain number of [`Testcase`]s and removes additional ones in a FIFO manner. //! which only stores a certain number of [`Testcase`]s and removes additional ones in a FIFO manner.
use alloc::string::String; use alloc::string::String;
use core::cell::RefCell; use core::cell::{Ref, RefCell, RefMut};
use std::{ use std::{
fs, fs,
fs::{File, OpenOptions}, fs::{File, OpenOptions},
@ -59,12 +59,10 @@ pub struct InMemoryOnDiskCorpus<I> {
locking: bool, locking: bool,
} }
impl<I> Corpus for InMemoryOnDiskCorpus<I> impl<I> Corpus<I> for InMemoryOnDiskCorpus<I>
where where
I: Input, I: Input,
{ {
type Input = I;
/// Returns the number of all enabled entries /// Returns the number of all enabled entries
#[inline] #[inline]
fn count(&self) -> usize { fn count(&self) -> usize {
@ -182,7 +180,7 @@ where
self.inner.nth_from_all(nth) self.inner.nth_from_all(nth)
} }
fn load_input_into(&self, testcase: &mut Testcase<Self::Input>) -> Result<(), Error> { fn load_input_into(&self, testcase: &mut Testcase<I>) -> Result<(), Error> {
if testcase.input_mut().is_none() { if testcase.input_mut().is_none() {
let Some(file_path) = testcase.file_path().as_ref() else { let Some(file_path) = testcase.file_path().as_ref() else {
return Err(Error::illegal_argument( return Err(Error::illegal_argument(
@ -195,7 +193,7 @@ where
Ok(()) Ok(())
} }
fn store_input_from(&self, testcase: &Testcase<Self::Input>) -> Result<(), Error> { fn store_input_from(&self, testcase: &Testcase<I>) -> Result<(), Error> {
// Store the input to disk // Store the input to disk
let Some(file_path) = testcase.file_path() else { let Some(file_path) = testcase.file_path() else {
return Err(Error::illegal_argument( return Err(Error::illegal_argument(
@ -211,21 +209,15 @@ where
} }
} }
impl<I> HasTestcase for InMemoryOnDiskCorpus<I> impl<I> HasTestcase<I> for InMemoryOnDiskCorpus<I>
where where
I: Input, I: Input,
{ {
fn testcase( fn testcase(&self, id: CorpusId) -> Result<Ref<Testcase<I>>, Error> {
&self,
id: CorpusId,
) -> Result<core::cell::Ref<Testcase<<Self as Corpus>::Input>>, Error> {
Ok(self.get(id)?.borrow()) Ok(self.get(id)?.borrow())
} }
fn testcase_mut( fn testcase_mut(&self, id: CorpusId) -> Result<RefMut<Testcase<I>>, Error> {
&self,
id: CorpusId,
) -> Result<core::cell::RefMut<Testcase<<Self as Corpus>::Input>>, Error> {
Ok(self.get(id)?.borrow_mut()) Ok(self.get(id)?.borrow_mut())
} }
} }
@ -242,7 +234,7 @@ impl<I> InMemoryOnDiskCorpus<I> {
/// If you don't want metadata, use [`InMemoryOnDiskCorpus::no_meta`]. /// If you don't want metadata, use [`InMemoryOnDiskCorpus::no_meta`].
/// To pick a different metadata format, use [`InMemoryOnDiskCorpus::with_meta_format`]. /// To pick a different metadata format, use [`InMemoryOnDiskCorpus::with_meta_format`].
/// ///
/// Will error, if [`std::fs::create_dir_all()`] failed for `dir_path`. /// Will error, if [`fs::create_dir_all()`] failed for `dir_path`.
pub fn new<P>(dir_path: P) -> Result<Self, Error> pub fn new<P>(dir_path: P) -> Result<Self, Error>
where where
P: AsRef<Path>, P: AsRef<Path>,
@ -257,7 +249,7 @@ impl<I> InMemoryOnDiskCorpus<I> {
/// Creates the [`InMemoryOnDiskCorpus`] specifying the format in which `Metadata` will be saved to disk. /// Creates the [`InMemoryOnDiskCorpus`] specifying the format in which `Metadata` will be saved to disk.
/// ///
/// Will error, if [`std::fs::create_dir_all()`] failed for `dir_path`. /// Will error, if [`fs::create_dir_all()`] failed for `dir_path`.
pub fn with_meta_format<P>( pub fn with_meta_format<P>(
dir_path: P, dir_path: P,
meta_format: Option<OnDiskMetadataFormat>, meta_format: Option<OnDiskMetadataFormat>,
@ -271,7 +263,7 @@ impl<I> InMemoryOnDiskCorpus<I> {
/// Creates the [`InMemoryOnDiskCorpus`] specifying the format in which `Metadata` will be saved to disk /// Creates the [`InMemoryOnDiskCorpus`] specifying the format in which `Metadata` will be saved to disk
/// and the prefix for the filenames. /// and the prefix for the filenames.
/// ///
/// Will error, if [`std::fs::create_dir_all()`] failed for `dir_path`. /// Will error, if [`fs::create_dir_all()`] failed for `dir_path`.
pub fn with_meta_format_and_prefix<P>( pub fn with_meta_format_and_prefix<P>(
dir_path: P, dir_path: P,
meta_format: Option<OnDiskMetadataFormat>, meta_format: Option<OnDiskMetadataFormat>,
@ -286,7 +278,7 @@ impl<I> InMemoryOnDiskCorpus<I> {
/// Creates an [`InMemoryOnDiskCorpus`] that will not store .metadata files /// Creates an [`InMemoryOnDiskCorpus`] that will not store .metadata files
/// ///
/// Will error, if [`std::fs::create_dir_all()`] failed for `dir_path`. /// Will error, if [`fs::create_dir_all()`] failed for `dir_path`.
pub fn no_meta<P>(dir_path: P) -> Result<Self, Error> pub fn no_meta<P>(dir_path: P) -> Result<Self, Error>
where where
P: AsRef<Path>, P: AsRef<Path>,

View File

@ -29,16 +29,16 @@ use crate::{
/// ///
/// 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<C, E, O, S, T, TS> { pub struct MapCorpusMinimizer<C, E, I, O, S, T, TS> {
observer_handle: Handle<C>, observer_handle: Handle<C>,
phantom: PhantomData<(E, O, S, T, TS)>, phantom: PhantomData<(E, I, O, S, 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<C, E, O, S, T> = pub type StdCorpusMinimizer<C, E, I, O, S, T> =
MapCorpusMinimizer<C, E, O, S, T, LenTimeMulTestcaseScore>; MapCorpusMinimizer<C, E, I, O, S, T, LenTimeMulTestcaseScore>;
impl<C, E, O, S, T, TS> MapCorpusMinimizer<C, E, O, S, T, TS> impl<C, E, I, O, S, T, TS> MapCorpusMinimizer<C, E, I, O, S, T, TS>
where where
C: Named, C: Named,
{ {
@ -52,14 +52,14 @@ where
} }
} }
impl<C, E, O, S, T, TS> MapCorpusMinimizer<C, E, O, S, T, TS> impl<C, E, I, O, S, T, TS> MapCorpusMinimizer<C, E, I, O, S, T, TS>
where where
for<'a> O: MapObserver<Entry = T> + AsIter<'a, Item = T>, for<'a> O: MapObserver<Entry = T> + AsIter<'a, Item = T>,
C: AsRef<O>, C: AsRef<O>,
S: HasMetadata + HasCorpus + HasExecutions, I: Input,
<S::Corpus as Corpus>::Input: Input, S: HasMetadata + HasCorpus<I> + HasExecutions,
T: Copy + Hash + Eq, T: Copy + Hash + Eq,
TS: TestcaseScore<S>, TS: TestcaseScore<I, S>,
{ {
/// Do the minimization /// Do the minimization
#[expect(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
@ -71,12 +71,11 @@ where
state: &mut S, state: &mut S,
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>, E::Observers: ObserversTuple<I, S>,
CS: Scheduler<<S::Corpus as Corpus>::Input, S> CS: Scheduler<I, S> + RemovableScheduler<I, S>,
+ RemovableScheduler<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, Z: HasScheduler<I, S, Scheduler = CS>,
Z: HasScheduler<<S::Corpus as Corpus>::Input, S, Scheduler = CS>,
{ {
// don't delete this else it won't work after restart // don't delete this else it won't work after restart
let current = *state.corpus().current(); let current = *state.corpus().current();

View File

@ -1,5 +1,11 @@
//! Corpuses contain the testcases, either in memory, on disk, or somewhere else. //! Corpuses contain the testcases, either in memory, on disk, or somewhere else.
use core::{cell::RefCell, fmt, marker::PhantomData};
use serde::{Deserialize, Serialize};
use crate::Error;
pub mod testcase; pub mod testcase;
pub use testcase::{HasTestcase, SchedulerTestcaseMetadata, Testcase}; pub use testcase::{HasTestcase, SchedulerTestcaseMetadata, Testcase};
@ -23,15 +29,11 @@ pub use cached::CachedOnDiskCorpus;
#[cfg(all(feature = "cmin", unix))] #[cfg(all(feature = "cmin", unix))]
pub mod minimizer; pub mod minimizer;
use core::{cell::RefCell, fmt};
pub mod nop; pub mod nop;
#[cfg(all(feature = "cmin", unix))] #[cfg(all(feature = "cmin", unix))]
pub use minimizer::*; pub use minimizer::*;
pub use nop::NopCorpus; pub use nop::NopCorpus;
use serde::{Deserialize, Serialize};
use crate::Error;
/// An abstraction for the index that identify a testcase in the corpus /// An abstraction for the index that identify a testcase in the corpus
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
@ -101,10 +103,7 @@ macro_rules! random_corpus_id_with_disabled {
} }
/// Corpus with all current [`Testcase`]s, or solutions /// Corpus with all current [`Testcase`]s, or solutions
pub trait Corpus: Sized { pub trait Corpus<I>: Sized {
/// The type of input contained in this corpus
type Input;
/// Returns the number of all enabled entries /// Returns the number of all enabled entries
fn count(&self) -> usize; fn count(&self) -> usize;
@ -120,26 +119,22 @@ pub trait Corpus: Sized {
} }
/// Add an enabled testcase to the corpus and return its index /// Add an enabled testcase to the corpus and return its index
fn add(&mut self, testcase: Testcase<Self::Input>) -> Result<CorpusId, Error>; fn add(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error>;
/// Add a disabled testcase to the corpus and return its index /// Add a disabled testcase to the corpus and return its index
fn add_disabled(&mut self, testcase: Testcase<Self::Input>) -> Result<CorpusId, Error>; fn add_disabled(&mut self, testcase: Testcase<I>) -> Result<CorpusId, Error>;
/// Replaces the [`Testcase`] at the given idx, returning the existing. /// Replaces the [`Testcase`] at the given idx, returning the existing.
fn replace( fn replace(&mut self, id: CorpusId, testcase: Testcase<I>) -> Result<Testcase<I>, Error>;
&mut self,
id: CorpusId,
testcase: Testcase<Self::Input>,
) -> Result<Testcase<Self::Input>, Error>;
/// Removes an entry from the corpus, returning it if it was present; considers both enabled and disabled testcases /// Removes an entry from the corpus, returning it if it was present; considers both enabled and disabled testcases
fn remove(&mut self, id: CorpusId) -> Result<Testcase<Self::Input>, Error>; fn remove(&mut self, id: CorpusId) -> Result<Testcase<I>, Error>;
/// Get by id; considers only enabled testcases /// Get by id; considers only enabled testcases
fn get(&self, id: CorpusId) -> Result<&RefCell<Testcase<Self::Input>>, Error>; fn get(&self, id: CorpusId) -> Result<&RefCell<Testcase<I>>, Error>;
/// Get by id; considers both enabled and disabled testcases /// Get by id; considers both enabled and disabled testcases
fn get_from_all(&self, id: CorpusId) -> Result<&RefCell<Testcase<Self::Input>>, Error>; fn get_from_all(&self, id: CorpusId) -> Result<&RefCell<Testcase<I>>, Error>;
/// Current testcase scheduled /// Current testcase scheduled
fn current(&self) -> &Option<CorpusId>; fn current(&self) -> &Option<CorpusId>;
@ -163,11 +158,12 @@ pub trait Corpus: Sized {
fn last(&self) -> Option<CorpusId>; fn last(&self) -> Option<CorpusId>;
/// An iterator over very active corpus id /// An iterator over very active corpus id
fn ids(&self) -> CorpusIdIterator<'_, Self> { fn ids(&self) -> CorpusIdIterator<'_, Self, I> {
CorpusIdIterator { CorpusIdIterator {
corpus: self, corpus: self,
cur: self.first(), cur: self.first(),
cur_back: self.last(), cur_back: self.last(),
phantom: PhantomData,
} }
} }
@ -184,15 +180,15 @@ pub trait Corpus: Sized {
/// Method to load the input for this [`Testcase`] from persistent storage, /// Method to load the input for this [`Testcase`] from persistent storage,
/// if necessary, and if was not already loaded (`== Some(input)`). /// if necessary, and if was not already loaded (`== Some(input)`).
/// After this call, `testcase.input()` must always return `Some(input)`. /// After this call, `testcase.input()` must always return `Some(input)`.
fn load_input_into(&self, testcase: &mut Testcase<Self::Input>) -> Result<(), Error>; fn load_input_into(&self, testcase: &mut Testcase<I>) -> Result<(), Error>;
/// Method to store the input of this `Testcase` to persistent storage, if necessary. /// Method to store the input of this `Testcase` to persistent storage, if necessary.
fn store_input_from(&self, testcase: &Testcase<Self::Input>) -> Result<(), Error>; fn store_input_from(&self, testcase: &Testcase<I>) -> Result<(), Error>;
/// Loads the `Input` for a given [`CorpusId`] from the [`Corpus`], and returns the clone. /// Loads the `Input` for a given [`CorpusId`] from the [`Corpus`], and returns the clone.
fn cloned_input_for_id(&self, id: CorpusId) -> Result<Self::Input, Error> fn cloned_input_for_id(&self, id: CorpusId) -> Result<I, Error>
where where
Self::Input: Clone, I: Clone,
{ {
let mut testcase = self.get(id)?.borrow_mut(); let mut testcase = self.get(id)?.borrow_mut();
Ok(testcase.load_input(self)?.clone()) Ok(testcase.load_input(self)?.clone())
@ -213,18 +209,16 @@ pub trait HasCurrentCorpusId {
/// [`Iterator`] over the ids of a [`Corpus`] /// [`Iterator`] over the ids of a [`Corpus`]
#[derive(Debug)] #[derive(Debug)]
pub struct CorpusIdIterator<'a, C> pub struct CorpusIdIterator<'a, C, I> {
where
C: Corpus,
{
corpus: &'a C, corpus: &'a C,
cur: Option<CorpusId>, cur: Option<CorpusId>,
cur_back: Option<CorpusId>, cur_back: Option<CorpusId>,
phantom: PhantomData<I>,
} }
impl<C> Iterator for CorpusIdIterator<'_, C> impl<C, I> Iterator for CorpusIdIterator<'_, C, I>
where where
C: Corpus, C: Corpus<I>,
{ {
type Item = CorpusId; type Item = CorpusId;
@ -238,9 +232,9 @@ where
} }
} }
impl<C> DoubleEndedIterator for CorpusIdIterator<'_, C> impl<C, I> DoubleEndedIterator for CorpusIdIterator<'_, C, I>
where where
C: Corpus, C: Corpus<I>,
{ {
fn next_back(&mut self) -> Option<Self::Item> { fn next_back(&mut self) -> Option<Self::Item> {
if let Some(cur_back) = self.cur_back { if let Some(cur_back) = self.cur_back {

View File

@ -15,8 +15,7 @@ pub struct NopCorpus<I> {
phantom: PhantomData<I>, phantom: PhantomData<I>,
} }
impl<I> Corpus for NopCorpus<I> { impl<I> Corpus<I> for NopCorpus<I> {
type Input = I;
/// Returns the number of all enabled entries /// Returns the number of all enabled entries
#[inline] #[inline]
fn count(&self) -> usize { fn count(&self) -> usize {
@ -76,12 +75,6 @@ impl<I> Corpus for NopCorpus<I> {
&self.empty &self.empty
} }
/// Peek the next free corpus id
#[inline]
fn peek_free_id(&self) -> CorpusId {
CorpusId::from(0_usize)
}
/// Current testcase scheduled (mutable) /// Current testcase scheduled (mutable)
#[inline] #[inline]
fn current_mut(&mut self) -> &mut Option<CorpusId> { fn current_mut(&mut self) -> &mut Option<CorpusId> {
@ -93,6 +86,12 @@ impl<I> Corpus for NopCorpus<I> {
None None
} }
/// Peek the next free corpus id
#[inline]
fn peek_free_id(&self) -> CorpusId {
CorpusId::from(0_usize)
}
#[inline] #[inline]
fn prev(&self, _id: CorpusId) -> Option<CorpusId> { fn prev(&self, _id: CorpusId) -> Option<CorpusId> {
None None
@ -121,12 +120,12 @@ impl<I> Corpus for NopCorpus<I> {
} }
#[inline] #[inline]
fn load_input_into(&self, _testcase: &mut Testcase<Self::Input>) -> Result<(), Error> { fn load_input_into(&self, _testcase: &mut Testcase<I>) -> Result<(), Error> {
Err(Error::unsupported("Unsupported by NopCorpus")) Err(Error::unsupported("Unsupported by NopCorpus"))
} }
#[inline] #[inline]
fn store_input_from(&self, _testcase: &Testcase<Self::Input>) -> Result<(), Error> { fn store_input_from(&self, _testcase: &Testcase<I>) -> Result<(), Error> {
Err(Error::unsupported("Unsupported by NopCorpus")) Err(Error::unsupported("Unsupported by NopCorpus"))
} }
} }

View File

@ -2,7 +2,7 @@
//! //!
//! It _never_ keeps any of them in memory. //! It _never_ keeps any of them in memory.
//! This is a good solution for solutions that are never reused, or for *very* memory-constraint environments. //! This is a good solution for solutions that are never reused, or for *very* memory-constraint environments.
//! For any other occasions, consider using [`crate::corpus::CachedOnDiskCorpus`] //! For any other occasions, consider using [`CachedOnDiskCorpus`]
//! which stores a certain number of [`Testcase`]s in memory and removes additional ones in a FIFO manner. //! which stores a certain number of [`Testcase`]s in memory and removes additional ones in a FIFO manner.
use alloc::string::String; use alloc::string::String;
@ -56,11 +56,10 @@ pub struct OnDiskCorpus<I> {
inner: CachedOnDiskCorpus<I>, inner: CachedOnDiskCorpus<I>,
} }
impl<I> Corpus for OnDiskCorpus<I> impl<I> Corpus<I> for OnDiskCorpus<I>
where where
I: Input, I: Input,
{ {
type Input = I;
/// Returns the number of all enabled entries /// Returns the number of all enabled entries
#[inline] #[inline]
fn count(&self) -> usize { fn count(&self) -> usize {
@ -96,12 +95,6 @@ where
self.inner.replace(id, testcase) self.inner.replace(id, testcase)
} }
/// Peek the next free corpus id
#[inline]
fn peek_free_id(&self) -> CorpusId {
self.inner.peek_free_id()
}
/// Removes an entry from the corpus, returning it if it was present; considers both enabled and disabled testcases /// Removes an entry from the corpus, returning it if it was present; considers both enabled and disabled testcases
#[inline] #[inline]
fn remove(&mut self, id: CorpusId) -> Result<Testcase<I>, Error> { fn remove(&mut self, id: CorpusId) -> Result<Testcase<I>, Error> {
@ -137,6 +130,12 @@ where
self.inner.next(id) self.inner.next(id)
} }
/// Peek the next free corpus id
#[inline]
fn peek_free_id(&self) -> CorpusId {
self.inner.peek_free_id()
}
#[inline] #[inline]
fn prev(&self, id: CorpusId) -> Option<CorpusId> { fn prev(&self, id: CorpusId) -> Option<CorpusId> {
self.inner.prev(id) self.inner.prev(id)
@ -164,17 +163,17 @@ where
} }
#[inline] #[inline]
fn load_input_into(&self, testcase: &mut Testcase<Self::Input>) -> Result<(), Error> { fn load_input_into(&self, testcase: &mut Testcase<I>) -> Result<(), Error> {
self.inner.load_input_into(testcase) self.inner.load_input_into(testcase)
} }
#[inline] #[inline]
fn store_input_from(&self, testcase: &Testcase<Self::Input>) -> Result<(), Error> { fn store_input_from(&self, testcase: &Testcase<I>) -> Result<(), Error> {
self.inner.store_input_from(testcase) self.inner.store_input_from(testcase)
} }
} }
impl<I> HasTestcase for OnDiskCorpus<I> impl<I> HasTestcase<I> for OnDiskCorpus<I>
where where
I: Input, I: Input,
{ {

View File

@ -15,24 +15,18 @@ use libafl_bolts::{serdeany::SerdeAnyMap, HasLen};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::Corpus; use super::Corpus;
use crate::{corpus::CorpusId, state::HasCorpus, Error, HasMetadata}; use crate::{corpus::CorpusId, Error, HasMetadata};
/// Shorthand to receive a [`Ref`] or [`RefMut`] to a stored [`Testcase`], by [`CorpusId`]. /// Shorthand to receive a [`Ref`] or [`RefMut`] to a stored [`Testcase`], by [`CorpusId`].
/// For a normal state, this should return a [`Testcase`] in the corpus, not the objectives. /// For a normal state, this should return a [`Testcase`] in the corpus, not the objectives.
pub trait HasTestcase: HasCorpus { pub trait HasTestcase<I> {
/// Shorthand to receive a [`Ref`] to a stored [`Testcase`], by [`CorpusId`]. /// Shorthand to receive a [`Ref`] to a stored [`Testcase`], by [`CorpusId`].
/// For a normal state, this should return a [`Testcase`] in the corpus, not the objectives. /// For a normal state, this should return a [`Testcase`] in the corpus, not the objectives.
fn testcase( fn testcase(&self, id: CorpusId) -> Result<Ref<Testcase<I>>, Error>;
&self,
id: CorpusId,
) -> Result<Ref<Testcase<<Self::Corpus as Corpus>::Input>>, Error>;
/// Shorthand to receive a [`RefMut`] to a stored [`Testcase`], by [`CorpusId`]. /// Shorthand to receive a [`RefMut`] to a stored [`Testcase`], by [`CorpusId`].
/// For a normal state, this should return a [`Testcase`] in the corpus, not the objectives. /// For a normal state, this should return a [`Testcase`] in the corpus, not the objectives.
fn testcase_mut( fn testcase_mut(&self, id: CorpusId) -> Result<RefMut<Testcase<I>>, Error>;
&self,
id: CorpusId,
) -> Result<RefMut<Testcase<<Self::Corpus as Corpus>::Input>>, Error>;
} }
/// An entry in the [`Testcase`] Corpus /// An entry in the [`Testcase`] Corpus
@ -87,7 +81,7 @@ impl<I> HasMetadata for Testcase<I> {
/// Impl of a testcase /// Impl of a testcase
impl<I> Testcase<I> { impl<I> Testcase<I> {
/// Returns this [`Testcase`] with a loaded `Input`] /// Returns this [`Testcase`] with a loaded `Input`]
pub fn load_input<C: Corpus<Input = I>>(&mut self, corpus: &C) -> Result<&I, Error> { pub fn load_input<C: Corpus<I>>(&mut self, corpus: &C) -> Result<&I, Error> {
corpus.load_input_into(self)?; corpus.load_input_into(self)?;
Ok(self.input.as_ref().unwrap()) Ok(self.input.as_ref().unwrap())
} }
@ -358,7 +352,7 @@ where
} }
/// Get the `len` or calculate it, if not yet calculated. /// Get the `len` or calculate it, if not yet calculated.
pub fn load_len<C: Corpus<Input = I>>(&mut self, corpus: &C) -> Result<usize, Error> { pub fn load_len<C: Corpus<I>>(&mut self, corpus: &C) -> Result<usize, Error> {
match &self.input { match &self.input {
Some(i) => { Some(i) => {
let l = i.len(); let l = i.len();

View File

@ -29,7 +29,6 @@ use super::{CanSerializeObserver, ManagerExit, NopEventManager};
use crate::events::llmp::COMPRESS_THRESHOLD; use crate::events::llmp::COMPRESS_THRESHOLD;
use crate::{ use crate::{
common::HasMetadata, common::HasMetadata,
corpus::Corpus,
events::{ events::{
serialize_observers_adaptive, std_maybe_report_progress, std_report_progress, serialize_observers_adaptive, std_maybe_report_progress, std_report_progress,
AdaptiveSerializer, Event, EventConfig, EventFirer, EventManagerHooksTuple, EventManagerId, AdaptiveSerializer, Event, EventConfig, EventFirer, EventManagerHooksTuple, EventManagerId,
@ -39,9 +38,7 @@ use crate::{
fuzzer::{EvaluatorObservers, ExecutionProcessor}, fuzzer::{EvaluatorObservers, ExecutionProcessor},
inputs::{Input, NopInput}, inputs::{Input, NopInput},
observers::TimeObserver, observers::TimeObserver,
state::{ state::{HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor, NopState, Stoppable},
HasCorpus, HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor, NopState, Stoppable,
},
Error, Error,
}; };
@ -49,7 +46,7 @@ pub(crate) const _LLMP_TAG_TO_MAIN: Tag = Tag(0x3453453);
/// A wrapper manager to implement a main-secondary architecture with another broker /// A wrapper manager to implement a main-secondary architecture with another broker
#[derive(Debug)] #[derive(Debug)]
pub struct CentralizedEventManager<EM, EMH, S, SP> pub struct CentralizedEventManager<EM, EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -61,10 +58,10 @@ where
time_ref: Option<Handle<TimeObserver>>, time_ref: Option<Handle<TimeObserver>>,
hooks: EMH, hooks: EMH,
is_main: bool, is_main: bool,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl CentralizedEventManager<NopEventManager, (), NopState<NopInput>, NopShMemProvider> { impl CentralizedEventManager<NopEventManager, (), NopInput, NopState<NopInput>, NopShMemProvider> {
/// Creates a builder for [`CentralizedEventManager`] /// Creates a builder for [`CentralizedEventManager`]
#[must_use] #[must_use]
pub fn builder() -> CentralizedEventManagerBuilder { pub fn builder() -> CentralizedEventManagerBuilder {
@ -98,13 +95,13 @@ impl CentralizedEventManagerBuilder {
} }
/// Creates a new [`CentralizedEventManager`]. /// Creates a new [`CentralizedEventManager`].
pub fn build_from_client<EM, EMH, S, SP>( pub fn build_from_client<EM, EMH, I, S, SP>(
self, self,
inner: EM, inner: EM,
hooks: EMH, hooks: EMH,
client: LlmpClient<SP>, client: LlmpClient<SP>,
time_obs: Option<Handle<TimeObserver>>, time_obs: Option<Handle<TimeObserver>>,
) -> Result<CentralizedEventManager<EM, EMH, S, SP>, Error> ) -> Result<CentralizedEventManager<EM, EMH, I, S, SP>, Error>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -124,14 +121,14 @@ impl CentralizedEventManagerBuilder {
/// ///
/// If the port is not yet bound, it will act as a broker; otherwise, it /// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client. /// will act as a client.
pub fn build_on_port<EM, EMH, S, SP>( pub fn build_on_port<EM, EMH, I, S, SP>(
self, self,
inner: EM, inner: EM,
hooks: EMH, hooks: EMH,
shmem_provider: SP, shmem_provider: SP,
port: u16, port: u16,
time_obs: Option<Handle<TimeObserver>>, time_obs: Option<Handle<TimeObserver>>,
) -> Result<CentralizedEventManager<EM, EMH, S, SP>, Error> ) -> Result<CentralizedEventManager<EM, EMH, I, S, SP>, Error>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -141,14 +138,14 @@ impl CentralizedEventManagerBuilder {
/// If a client respawns, it may reuse the existing connection, previously /// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`]. /// stored by [`LlmpClient::to_env()`].
pub fn build_existing_client_from_env<EM, EMH, S, SP>( pub fn build_existing_client_from_env<EM, EMH, I, S, SP>(
self, self,
inner: EM, inner: EM,
hooks: EMH, hooks: EMH,
shmem_provider: SP, shmem_provider: SP,
env_name: &str, env_name: &str,
time_obs: Option<Handle<TimeObserver>>, time_obs: Option<Handle<TimeObserver>>,
) -> Result<CentralizedEventManager<EM, EMH, S, SP>, Error> ) -> Result<CentralizedEventManager<EM, EMH, I, S, SP>, Error>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -157,14 +154,14 @@ impl CentralizedEventManagerBuilder {
} }
/// Create an existing client from description /// Create an existing client from description
pub fn existing_client_from_description<EM, EMH, S, SP>( pub fn existing_client_from_description<EM, EMH, I, S, SP>(
self, self,
inner: EM, inner: EM,
hooks: EMH, hooks: EMH,
shmem_provider: SP, shmem_provider: SP,
description: &LlmpClientDescription, description: &LlmpClientDescription,
time_obs: Option<Handle<TimeObserver>>, time_obs: Option<Handle<TimeObserver>>,
) -> Result<CentralizedEventManager<EM, EMH, S, SP>, Error> ) -> Result<CentralizedEventManager<EM, EMH, I, S, SP>, Error>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -173,7 +170,7 @@ impl CentralizedEventManagerBuilder {
} }
} }
impl<EM, EMH, S, SP> AdaptiveSerializer for CentralizedEventManager<EM, EMH, S, SP> impl<EM, EMH, I, S, SP> AdaptiveSerializer for CentralizedEventManager<EM, EMH, I, S, SP>
where where
EM: AdaptiveSerializer, EM: AdaptiveSerializer,
SP: ShMemProvider, SP: ShMemProvider,
@ -209,25 +206,20 @@ where
} }
} }
impl<EM, EMH, S, SP> EventFirer<<S::Corpus as Corpus>::Input, S> impl<EM, EMH, I, S, SP> EventFirer<I, S> for CentralizedEventManager<EM, EMH, I, S, SP>
for CentralizedEventManager<EM, EMH, S, SP>
where where
EM: HasEventManagerId + EventFirer<<S::Corpus as Corpus>::Input, S>, EM: HasEventManagerId + EventFirer<I, S>,
EMH: EventManagerHooksTuple<<<S as HasCorpus>::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
SP: ShMemProvider, SP: ShMemProvider,
S: HasCorpus + Stoppable, S: Stoppable,
<<S as HasCorpus>::Corpus as Corpus>::Input: Input, I: Input,
{ {
fn should_send(&self) -> bool { fn should_send(&self) -> bool {
self.inner.should_send() self.inner.should_send()
} }
#[expect(clippy::match_same_arms)] #[expect(clippy::match_same_arms)]
fn fire( fn fire(&mut self, state: &mut S, mut event: Event<I>) -> Result<(), Error> {
&mut self,
state: &mut S,
mut event: Event<<S::Corpus as Corpus>::Input>,
) -> Result<(), Error> {
if !self.is_main { if !self.is_main {
// secondary node // secondary node
let mut is_tc = false; let mut is_tc = false;
@ -270,7 +262,7 @@ where
} }
} }
impl<EM, EMH, S, SP> EventRestarter<S> for CentralizedEventManager<EM, EMH, S, SP> impl<EM, EMH, I, S, SP> EventRestarter<S> for CentralizedEventManager<EM, EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
EM: EventRestarter<S>, EM: EventRestarter<S>,
@ -283,7 +275,7 @@ where
} }
} }
impl<EM, EMH, OT, S, SP> CanSerializeObserver<OT> for CentralizedEventManager<EM, EMH, S, SP> impl<EM, EMH, I, OT, S, SP> CanSerializeObserver<OT> for CentralizedEventManager<EM, EMH, I, S, SP>
where where
EM: AdaptiveSerializer, EM: AdaptiveSerializer,
SP: ShMemProvider, SP: ShMemProvider,
@ -299,7 +291,7 @@ where
} }
} }
impl<EM, EMH, S, SP> ManagerExit for CentralizedEventManager<EM, EMH, S, SP> impl<EM, EMH, I, S, SP> ManagerExit for CentralizedEventManager<EM, EMH, I, S, SP>
where where
EM: ManagerExit, EM: ManagerExit,
SP: ShMemProvider, SP: ShMemProvider,
@ -316,17 +308,16 @@ where
} }
} }
impl<E, EM, EMH, S, SP, Z> EventProcessor<E, S, Z> for CentralizedEventManager<EM, EMH, S, SP> impl<E, EM, EMH, I, S, SP, Z> EventProcessor<E, S, Z> for CentralizedEventManager<EM, EMH, I, S, SP>
where where
E: HasObservers, E: HasObservers,
E::Observers: DeserializeOwned, E::Observers: DeserializeOwned,
EM: EventProcessor<E, S, Z> + HasEventManagerId + EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventProcessor<E, S, Z> + HasEventManagerId + EventFirer<I, S>,
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
S: HasCorpus + Stoppable, S: Stoppable,
<S::Corpus as Corpus>::Input: Input, I: Input,
SP: ShMemProvider, SP: ShMemProvider,
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S> Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
{ {
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> {
if self.is_main { if self.is_main {
@ -345,17 +336,12 @@ where
} }
} }
impl<EM, EMH, S, SP> ProgressReporter<S> for CentralizedEventManager<EM, EMH, S, SP> impl<EM, EMH, I, S, SP> ProgressReporter<S> for CentralizedEventManager<EM, EMH, I, S, SP>
where where
EM: EventFirer<<S::Corpus as Corpus>::Input, S> + HasEventManagerId, EM: EventFirer<I, S> + HasEventManagerId,
EMH: EventManagerHooksTuple<<<S as HasCorpus>::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
S: HasExecutions S: HasExecutions + HasMetadata + HasLastReportTime + Stoppable + MaybeHasClientPerfMonitor,
+ HasMetadata I: Input,
+ HasLastReportTime
+ Stoppable
+ HasCorpus
+ MaybeHasClientPerfMonitor,
<S::Corpus as Corpus>::Input: Input,
SP: ShMemProvider, SP: ShMemProvider,
{ {
fn maybe_report_progress( fn maybe_report_progress(
@ -371,7 +357,7 @@ where
} }
} }
impl<EM, EMH, S, SP> HasEventManagerId for CentralizedEventManager<EM, EMH, S, SP> impl<EM, EMH, I, S, SP> HasEventManagerId for CentralizedEventManager<EM, EMH, I, S, SP>
where where
EM: HasEventManagerId, EM: HasEventManagerId,
SP: ShMemProvider, SP: ShMemProvider,
@ -381,7 +367,7 @@ where
} }
} }
impl<EM, EMH, S, SP> CentralizedEventManager<EM, EMH, S, SP> impl<EM, EMH, I, S, SP> CentralizedEventManager<EM, EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -402,19 +388,16 @@ where
} }
} }
impl<EM, EMH, S, SP> CentralizedEventManager<EM, EMH, S, SP> impl<EM, EMH, I, S, SP> CentralizedEventManager<EM, EMH, I, S, SP>
where where
EM: HasEventManagerId + EventFirer<<S::Corpus as Corpus>::Input, S>, EM: HasEventManagerId + EventFirer<I, S>,
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
S: HasCorpus + Stoppable, S: Stoppable,
<S::Corpus as Corpus>::Input: Input, I: Input,
SP: ShMemProvider, SP: ShMemProvider,
{ {
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
fn forward_to_main<I>(&mut self, event: &Event<I>) -> Result<(), Error> fn forward_to_main(&mut self, event: &Event<I>) -> Result<(), Error> {
where
I: Input,
{
let serialized = postcard::to_allocvec(event)?; let serialized = postcard::to_allocvec(event)?;
let flags = LLMP_FLAG_INITIALIZED; let flags = LLMP_FLAG_INITIALIZED;
@ -434,10 +417,7 @@ where
} }
#[cfg(not(feature = "llmp_compression"))] #[cfg(not(feature = "llmp_compression"))]
fn forward_to_main<I>(&mut self, event: &Event<I>) -> Result<(), Error> fn forward_to_main(&mut self, event: &Event<I>) -> Result<(), Error> {
where
I: Input,
{
let serialized = postcard::to_allocvec(event)?; let serialized = postcard::to_allocvec(event)?;
self.client.send_buf(_LLMP_TAG_TO_MAIN, &serialized)?; self.client.send_buf(_LLMP_TAG_TO_MAIN, &serialized)?;
Ok(()) Ok(())
@ -452,8 +432,7 @@ where
where where
E: HasObservers, E: HasObservers,
E::Observers: DeserializeOwned, E::Observers: DeserializeOwned,
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S> Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
{ {
// 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.client.sender().id(); let self_id = self.client.sender().id();
@ -478,7 +457,7 @@ where
} else { } else {
msg msg
}; };
let event: Event<<S::Corpus as Corpus>::Input> = postcard::from_bytes(event_bytes)?; let event: Event<I> = postcard::from_bytes(event_bytes)?;
log::debug!("Processor received message {}", event.name_detailed()); log::debug!("Processor received message {}", event.name_detailed());
self.handle_in_main(fuzzer, executor, state, client_id, event)?; self.handle_in_main(fuzzer, executor, state, client_id, event)?;
count += 1; count += 1;
@ -493,13 +472,12 @@ where
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut S,
client_id: ClientId, client_id: ClientId,
event: Event<<S::Corpus as Corpus>::Input>, event: Event<I>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: HasObservers, E: HasObservers,
E::Observers: DeserializeOwned, E::Observers: DeserializeOwned,
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S> Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
{ {
log::debug!("handle_in_main!"); log::debug!("handle_in_main!");
@ -594,14 +572,3 @@ where
Ok(()) Ok(())
} }
} }
/*
impl<EM, SP> Drop for CentralizedEventManager<EM, SP>
where
EM: UsesState, SP: ShMemProvider + 'static,
{
/// LLMP clients will have to wait until their pages are mapped by somebody.
fn drop(&mut self) {
self.await_restart_safe();
}
}*/

View File

@ -51,14 +51,12 @@ use {libafl_bolts::os::startable_self, std::process::Stdio};
#[cfg(all(unix, feature = "fork", feature = "multi_machine"))] #[cfg(all(unix, feature = "fork", feature = "multi_machine"))]
use crate::events::multi_machine::{NodeDescriptor, TcpMultiMachineHooks}; use crate::events::multi_machine::{NodeDescriptor, TcpMultiMachineHooks};
use crate::{ use crate::{
corpus::Corpus,
events::{ events::{
llmp::{LlmpRestartingEventManager, LlmpShouldSaveState, ManagerKind, RestartingMgr}, llmp::{LlmpRestartingEventManager, LlmpShouldSaveState, ManagerKind, RestartingMgr},
EventConfig, EventManagerHooksTuple, EventConfig, EventManagerHooksTuple,
}, },
monitors::Monitor, monitors::Monitor,
observers::TimeObserver, observers::TimeObserver,
state::HasCorpus,
Error, Error,
}; };
@ -214,15 +212,15 @@ where
{ {
/// Launch the broker and the clients and fuzz /// Launch the broker and the clients and fuzz
#[cfg(any(windows, not(feature = "fork"), all(unix, feature = "fork")))] #[cfg(any(windows, not(feature = "fork"), all(unix, feature = "fork")))]
pub fn launch<S>(&mut self) -> Result<(), Error> pub fn launch<I, S>(&mut self) -> Result<(), Error>
where where
S: DeserializeOwned + HasCorpus + Serialize,
<S::Corpus as Corpus>::Input: DeserializeOwned,
CF: FnOnce( CF: FnOnce(
Option<S>, Option<S>,
LlmpRestartingEventManager<(), S, SP>, LlmpRestartingEventManager<(), I, S, SP>,
ClientDescription, ClientDescription,
) -> Result<(), Error>, ) -> Result<(), Error>,
I: DeserializeOwned,
S: DeserializeOwned + Serialize,
{ {
Self::launch_with_hooks(self, tuple_list!()) Self::launch_with_hooks(self, tuple_list!())
} }
@ -235,14 +233,14 @@ where
{ {
/// Launch the broker and the clients and fuzz with a user-supplied hook /// Launch the broker and the clients and fuzz with a user-supplied hook
#[cfg(all(unix, feature = "fork"))] #[cfg(all(unix, feature = "fork"))]
pub fn launch_with_hooks<EMH, S>(&mut self, hooks: EMH) -> Result<(), Error> pub fn launch_with_hooks<EMH, I, S>(&mut self, hooks: EMH) -> Result<(), Error>
where where
S: DeserializeOwned + HasCorpus + Serialize, S: DeserializeOwned + Serialize,
<S::Corpus as Corpus>::Input: DeserializeOwned, I: DeserializeOwned,
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S> + Clone + Copy, EMH: EventManagerHooksTuple<I, S> + Clone + Copy,
CF: FnOnce( CF: FnOnce(
Option<S>, Option<S>,
LlmpRestartingEventManager<EMH, S, SP>, LlmpRestartingEventManager<EMH, I, S, SP>,
ClientDescription, ClientDescription,
) -> Result<(), Error>, ) -> Result<(), Error>,
{ {
@ -314,7 +312,7 @@ where
ClientDescription::new(index, overcommit_id, bind_to); ClientDescription::new(index, overcommit_id, bind_to);
// 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 builder = RestartingMgr::<EMH, MT, S, SP>::builder() let builder = RestartingMgr::<EMH, I, 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 {
@ -341,7 +339,7 @@ where
log::info!("I am broker!!."); log::info!("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
let builder = RestartingMgr::<EMH, MT, S, SP>::builder() let builder = RestartingMgr::<EMH, I, 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)
@ -383,18 +381,18 @@ where
/// Launch the broker and the clients and fuzz /// Launch the broker and the clients and fuzz
#[cfg(any(windows, not(feature = "fork")))] #[cfg(any(windows, not(feature = "fork")))]
#[expect(clippy::too_many_lines, clippy::match_wild_err_arm)] #[expect(clippy::too_many_lines, clippy::match_wild_err_arm)]
pub fn launch_with_hooks<EMH, S>(&mut self, hooks: EMH) -> Result<(), Error> pub fn launch_with_hooks<EMH, I, S>(&mut self, hooks: EMH) -> Result<(), Error>
where where
S: DeserializeOwned + HasCorpus + Serialize,
<S::Corpus as Corpus>::Input: DeserializeOwned,
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S> + Clone + Copy,
CF: FnOnce( CF: FnOnce(
Option<S>, Option<S>,
LlmpRestartingEventManager<EMH, S, SP>, LlmpRestartingEventManager<EMH, I, S, SP>,
ClientDescription, ClientDescription,
) -> Result<(), Error>, ) -> Result<(), Error>,
EMH: EventManagerHooksTuple<I, S> + Clone + Copy,
I: DeserializeOwned,
S: DeserializeOwned + Serialize,
{ {
use libafl_bolts::core_affinity; use libafl_bolts::core_affinity::get_core_ids;
let is_client = std::env::var(_AFL_LAUNCHER_CLIENT); let is_client = std::env::var(_AFL_LAUNCHER_CLIENT);
@ -403,7 +401,7 @@ where
let client_description = ClientDescription::from_safe_string(&core_conf); let client_description = ClientDescription::from_safe_string(&core_conf);
// the actual client. do the fuzzing // the actual client. do the fuzzing
let builder = RestartingMgr::<EMH, MT, S, SP>::builder() let builder = RestartingMgr::<EMH, I, 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 {
@ -423,7 +421,7 @@ where
// I am a broker // I am a broker
// before going to the broker loop, spawn n clients // before going to the broker loop, spawn n clients
let core_ids = core_affinity::get_core_ids().unwrap(); let core_ids = get_core_ids().unwrap();
let mut handles = vec![]; let mut handles = vec![];
log::info!("spawning on cores: {:?}", self.cores); log::info!("spawning on cores: {:?}", self.cores);
@ -504,7 +502,7 @@ where
if self.spawn_broker { if self.spawn_broker {
log::info!("I am broker!!."); log::info!("I am broker!!.");
let builder = RestartingMgr::<EMH, MT, S, SP>::builder() let builder = RestartingMgr::<EMH, I, 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)
@ -622,7 +620,7 @@ impl<CF, MF, MT, SP> Debug for CentralizedLauncher<'_, CF, MF, MT, SP> {
} }
/// The standard inner manager of centralized /// The standard inner manager of centralized
pub type StdCentralizedInnerMgr<S, SP> = LlmpRestartingEventManager<(), S, SP>; pub type StdCentralizedInnerMgr<I, S, SP> = LlmpRestartingEventManager<(), I, S, SP>;
#[cfg(all(unix, feature = "fork"))] #[cfg(all(unix, feature = "fork"))]
impl<CF, MF, MT, SP> CentralizedLauncher<'_, CF, MF, MT, SP> impl<CF, MF, MT, SP> CentralizedLauncher<'_, CF, MF, MT, SP>
@ -631,25 +629,25 @@ where
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
{ {
/// Launch a standard Centralized-based fuzzer /// Launch a standard Centralized-based fuzzer
pub fn launch<S>(&mut self) -> Result<(), Error> pub fn launch<I, S>(&mut self) -> Result<(), Error>
where where
S: DeserializeOwned + HasCorpus + Serialize, S: DeserializeOwned + Serialize,
<S::Corpus as Corpus>::Input: DeserializeOwned + Input + Send + Sync + 'static, I: DeserializeOwned + Input + Send + Sync + 'static,
CF: FnOnce( CF: FnOnce(
Option<S>, Option<S>,
CentralizedEventManager<StdCentralizedInnerMgr<S, SP>, (), S, SP>, CentralizedEventManager<StdCentralizedInnerMgr<I, S, SP>, (), I, S, SP>,
ClientDescription, ClientDescription,
) -> Result<(), Error>, ) -> Result<(), Error>,
MF: FnOnce( MF: FnOnce(
Option<S>, Option<S>,
CentralizedEventManager<StdCentralizedInnerMgr<S, SP>, (), S, SP>, CentralizedEventManager<StdCentralizedInnerMgr<I, S, SP>, (), I, S, SP>,
ClientDescription, ClientDescription,
) -> Result<(), Error>, ) -> Result<(), Error>,
{ {
let restarting_mgr_builder = let restarting_mgr_builder =
|centralized_launcher: &Self, client_description: ClientDescription| { |centralized_launcher: &Self, client_description: ClientDescription| {
// 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 builder = RestartingMgr::<(), MT, S, SP>::builder() let builder = RestartingMgr::<(), I, MT, S, SP>::builder()
.shmem_provider(centralized_launcher.shmem_provider.clone()) .shmem_provider(centralized_launcher.shmem_provider.clone())
.broker_port(centralized_launcher.broker_port) .broker_port(centralized_launcher.broker_port)
.kind(ManagerKind::Client { client_description }) .kind(ManagerKind::Client { client_description })
@ -675,23 +673,22 @@ where
/// Launch a Centralized-based fuzzer. /// Launch a Centralized-based fuzzer.
/// - `main_inner_mgr_builder` will be called to build the inner manager of the main node. /// - `main_inner_mgr_builder` will be called to build the inner manager of the main node.
/// - `secondary_inner_mgr_builder` will be called to build the inner manager of the secondary nodes. /// - `secondary_inner_mgr_builder` will be called to build the inner manager of the secondary nodes.
pub fn launch_generic<EM, EMB, S>( pub fn launch_generic<EM, EMB, I, S>(
&mut self, &mut self,
main_inner_mgr_builder: EMB, main_inner_mgr_builder: EMB,
secondary_inner_mgr_builder: EMB, secondary_inner_mgr_builder: EMB,
) -> Result<(), Error> ) -> Result<(), Error>
where where
S: HasCorpus, I: Input + Send + Sync + 'static,
<S::Corpus as Corpus>::Input: Input + Send + Sync + 'static,
CF: FnOnce( CF: FnOnce(
Option<S>, Option<S>,
CentralizedEventManager<EM, (), S, SP>, CentralizedEventManager<EM, (), I, S, SP>,
ClientDescription, ClientDescription,
) -> Result<(), Error>, ) -> Result<(), Error>,
EMB: FnOnce(&Self, ClientDescription) -> Result<(Option<S>, EM), Error>, EMB: FnOnce(&Self, ClientDescription) -> Result<(Option<S>, EM), Error>,
MF: FnOnce( MF: FnOnce(
Option<S>, Option<S>,
CentralizedEventManager<EM, (), S, SP>, // No broker_hooks for centralized EM CentralizedEventManager<EM, (), I, S, SP>, // No broker_hooks for centralized EM
ClientDescription, ClientDescription,
) -> Result<(), Error>, ) -> Result<(), Error>,
{ {
@ -835,7 +832,7 @@ where
} = unsafe { } = unsafe {
TcpMultiMachineHooks::builder() TcpMultiMachineHooks::builder()
.node_descriptor(self.multi_machine_node_descriptor.clone()) .node_descriptor(self.multi_machine_node_descriptor.clone())
.build::<<S::Corpus as Corpus>::Input>()? .build::<I>()?
}; };
let mut brokers = Brokers::new(); let mut brokers = Brokers::new();
@ -845,13 +842,12 @@ where
brokers.add(Box::new({ brokers.add(Box::new({
#[cfg(feature = "multi_machine")] #[cfg(feature = "multi_machine")]
let centralized_hooks = tuple_list!( let centralized_hooks = tuple_list!(
CentralizedLlmpHook::<<S::Corpus as Corpus>::Input>::new()?, CentralizedLlmpHook::<I>::new()?,
multi_machine_receiver_hook, multi_machine_receiver_hook,
); );
#[cfg(not(feature = "multi_machine"))] #[cfg(not(feature = "multi_machine"))]
let centralized_hooks = let centralized_hooks = tuple_list!(CentralizedLlmpHook::<I>::new()?);
tuple_list!(CentralizedLlmpHook::<<S::Corpus as Corpus>::Input>::new()?);
// TODO switch to false after solving the bug // TODO switch to false after solving the bug
let mut broker = LlmpBroker::with_keep_pages_attach_to_tcp( let mut broker = LlmpBroker::with_keep_pages_attach_to_tcp(
@ -875,13 +871,11 @@ where
log::info!("I am broker!!."); log::info!("I am broker!!.");
#[cfg(not(feature = "multi_machine"))] #[cfg(not(feature = "multi_machine"))]
let llmp_hook = tuple_list!(StdLlmpEventHook::<<S::Corpus as Corpus>::Input, MT>::new( let llmp_hook = tuple_list!(StdLlmpEventHook::<I, MT>::new(self.monitor.clone())?);
self.monitor.clone()
)?);
#[cfg(feature = "multi_machine")] #[cfg(feature = "multi_machine")]
let llmp_hook = tuple_list!( let llmp_hook = tuple_list!(
StdLlmpEventHook::<<S::Corpus as Corpus>::Input, MT>::new(self.monitor.clone())?, StdLlmpEventHook::<I, MT>::new(self.monitor.clone())?,
multi_machine_sender_hook, multi_machine_sender_hook,
); );

View File

@ -34,7 +34,6 @@ use crate::events::llmp::COMPRESS_THRESHOLD;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::events::{serialize_observers_adaptive, CanSerializeObserver}; use crate::events::{serialize_observers_adaptive, CanSerializeObserver};
use crate::{ use crate::{
corpus::Corpus,
events::{ events::{
llmp::{LLMP_TAG_EVENT_TO_BOTH, _LLMP_TAG_EVENT_TO_BROKER}, llmp::{LLMP_TAG_EVENT_TO_BOTH, _LLMP_TAG_EVENT_TO_BROKER},
std_maybe_report_progress, std_on_restart, std_report_progress, AdaptiveSerializer, Event, std_maybe_report_progress, std_on_restart, std_report_progress, AdaptiveSerializer, Event,
@ -47,8 +46,8 @@ use crate::{
observers::TimeObserver, observers::TimeObserver,
stages::HasCurrentStageId, stages::HasCurrentStageId,
state::{ state::{
HasCorpus, HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor, HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor, NopState,
NopState, Stoppable, Stoppable,
}, },
Error, HasMetadata, Error, HasMetadata,
}; };
@ -58,7 +57,7 @@ const INITIAL_EVENT_BUFFER_SIZE: usize = 1024 * 4;
/// 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, `llmp`. /// using low-level message passing, `llmp`.
pub struct LlmpEventManager<EMH, S, SP> pub struct LlmpEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -80,11 +79,11 @@ where
serializations_cnt: usize, serializations_cnt: usize,
should_serialize_cnt: usize, should_serialize_cnt: usize,
pub(crate) time_ref: Option<Handle<TimeObserver>>, pub(crate) time_ref: Option<Handle<TimeObserver>>,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
event_buffer: Vec<u8>, event_buffer: Vec<u8>,
} }
impl LlmpEventManager<(), NopState<NopInput>, NopShMemProvider> { impl LlmpEventManager<(), NopState<NopInput>, NopInput, NopShMemProvider> {
/// Creates a builder for [`LlmpEventManager`] /// Creates a builder for [`LlmpEventManager`]
#[must_use] #[must_use]
pub fn builder() -> LlmpEventManagerBuilder<()> { pub fn builder() -> LlmpEventManagerBuilder<()> {
@ -133,12 +132,12 @@ impl<EMH> LlmpEventManagerBuilder<EMH> {
} }
/// Create a manager from a raw LLMP client /// Create a manager from a raw LLMP client
pub fn build_from_client<S, SP>( pub fn build_from_client<I, S, SP>(
self, self,
llmp: LlmpClient<SP>, llmp: LlmpClient<SP>,
configuration: EventConfig, configuration: EventConfig,
time_ref: Option<Handle<TimeObserver>>, time_ref: Option<Handle<TimeObserver>>,
) -> Result<LlmpEventManager<EMH, S, SP>, Error> ) -> Result<LlmpEventManager<EMH, I, S, SP>, Error>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -163,13 +162,13 @@ impl<EMH> LlmpEventManagerBuilder<EMH> {
/// Create an LLMP event manager on a port. /// Create an LLMP event manager on a port.
/// It expects a broker to exist on this port. /// It expects a broker to exist on this port.
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn build_on_port<S, SP>( pub fn build_on_port<I, S, SP>(
self, self,
shmem_provider: SP, shmem_provider: SP,
port: u16, port: u16,
configuration: EventConfig, configuration: EventConfig,
time_ref: Option<Handle<TimeObserver>>, time_ref: Option<Handle<TimeObserver>>,
) -> Result<LlmpEventManager<EMH, S, SP>, Error> ) -> Result<LlmpEventManager<EMH, I, S, SP>, Error>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -180,13 +179,13 @@ impl<EMH> LlmpEventManagerBuilder<EMH> {
/// If a client respawns, it may reuse the existing connection, previously /// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`]. /// stored by [`LlmpClient::to_env()`].
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn build_existing_client_from_env<S, SP>( pub fn build_existing_client_from_env<I, S, SP>(
self, self,
shmem_provider: SP, shmem_provider: SP,
env_name: &str, env_name: &str,
configuration: EventConfig, configuration: EventConfig,
time_ref: Option<Handle<TimeObserver>>, time_ref: Option<Handle<TimeObserver>>,
) -> Result<LlmpEventManager<EMH, S, SP>, Error> ) -> Result<LlmpEventManager<EMH, I, S, SP>, Error>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -195,13 +194,13 @@ impl<EMH> LlmpEventManagerBuilder<EMH> {
} }
/// Create an existing client from description /// Create an existing client from description
pub fn build_existing_client_from_description<S, SP>( pub fn build_existing_client_from_description<I, S, SP>(
self, self,
shmem_provider: SP, shmem_provider: SP,
description: &LlmpClientDescription, description: &LlmpClientDescription,
configuration: EventConfig, configuration: EventConfig,
time_ref: Option<Handle<TimeObserver>>, time_ref: Option<Handle<TimeObserver>>,
) -> Result<LlmpEventManager<EMH, S, SP>, Error> ) -> Result<LlmpEventManager<EMH, I, S, SP>, Error>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -211,7 +210,7 @@ impl<EMH> LlmpEventManagerBuilder<EMH> {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<EMH, OT, S, SP> CanSerializeObserver<OT> for LlmpEventManager<EMH, S, SP> impl<EMH, I, OT, S, SP> CanSerializeObserver<OT> for LlmpEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
OT: Serialize + MatchNameRef, OT: Serialize + MatchNameRef,
@ -221,7 +220,7 @@ where
} }
} }
impl<EMH, S, SP> AdaptiveSerializer for LlmpEventManager<EMH, S, SP> impl<EMH, I, S, SP> AdaptiveSerializer for LlmpEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -256,7 +255,7 @@ where
} }
} }
impl<EMH, S, SP> core::fmt::Debug for LlmpEventManager<EMH, S, SP> impl<EMH, I, S, SP> core::fmt::Debug for LlmpEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -273,7 +272,7 @@ where
} }
} }
impl<EMH, S, SP> Drop for LlmpEventManager<EMH, S, SP> impl<EMH, I, S, SP> Drop for LlmpEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -283,7 +282,7 @@ where
} }
} }
impl<EMH, S, SP> LlmpEventManager<EMH, S, SP> impl<EMH, I, S, SP> LlmpEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -333,7 +332,7 @@ where
} }
} }
impl<EMH, S, SP> LlmpEventManager<EMH, S, SP> impl<EMH, I, S, SP> LlmpEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -344,16 +343,15 @@ where
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut S,
client_id: ClientId, client_id: ClientId,
event: Event<<S::Corpus as Corpus>::Input>, event: Event<I>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
S: HasCorpus + HasImported + Stoppable, S: HasImported + Stoppable,
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
<S::Corpus as Corpus>::Input: Input, I: Input,
E: HasObservers, E: HasObservers,
E::Observers: DeserializeOwned, E::Observers: DeserializeOwned,
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S> Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
{ {
log::trace!("Got event in client: {} from {client_id:?}", event.name()); log::trace!("Got event in client: {} from {client_id:?}", event.name());
if !self.hooks.pre_exec_all(state, client_id, &event)? { if !self.hooks.pre_exec_all(state, client_id, &event)? {
@ -409,7 +407,7 @@ where
} }
} }
impl<EMH, S, SP: ShMemProvider> LlmpEventManager<EMH, S, SP> { impl<EMH, I, S, SP: ShMemProvider> LlmpEventManager<EMH, I, S, SP> {
/// Send information that this client is exiting. /// Send information that this client is exiting.
/// The other side may free up all allocated memory. /// The other side may free up all allocated memory.
/// We are no longer allowed to send anything afterwards. /// We are no longer allowed to send anything afterwards.
@ -418,7 +416,7 @@ impl<EMH, S, SP: ShMemProvider> LlmpEventManager<EMH, S, SP> {
} }
} }
impl<EMH, I, S, SP> EventFirer<I, S> for LlmpEventManager<EMH, S, SP> impl<EMH, I, S, SP> EventFirer<I, S> for LlmpEventManager<EMH, I, S, SP>
where where
I: Serialize, I: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
@ -482,7 +480,7 @@ where
} }
} }
impl<EMH, S, SP> EventRestarter<S> for LlmpEventManager<EMH, S, SP> impl<EMH, I, S, SP> EventRestarter<S> for LlmpEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
S: HasCurrentStageId, S: HasCurrentStageId,
@ -492,7 +490,7 @@ where
} }
} }
impl<EMH, S, SP> ManagerExit for LlmpEventManager<EMH, S, SP> impl<EMH, I, S, SP> ManagerExit for LlmpEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -508,16 +506,15 @@ where
} }
} }
impl<E, EMH, S, SP, Z> EventProcessor<E, S, Z> for LlmpEventManager<EMH, S, SP> impl<E, EMH, I, S, SP, Z> EventProcessor<E, S, Z> for LlmpEventManager<EMH, I, S, SP>
where where
E: HasObservers, E: HasObservers,
E::Observers: DeserializeOwned, E::Observers: DeserializeOwned,
S: HasCorpus + HasImported + Stoppable, S: HasImported + Stoppable,
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
<S::Corpus as Corpus>::Input: DeserializeOwned + Input, I: DeserializeOwned + Input,
SP: ShMemProvider, SP: ShMemProvider,
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S> Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
{ {
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> {
// TODO: Get around local event copy by moving handle_in_client // TODO: Get around local event copy by moving handle_in_client
@ -543,7 +540,7 @@ where
} else { } else {
msg msg
}; };
let event: Event<<S::Corpus as Corpus>::Input> = postcard::from_bytes(event_bytes)?; let event: Event<I> = postcard::from_bytes(event_bytes)?;
log::debug!("Received event in normal llmp {}", event.name_detailed()); log::debug!("Received event in normal llmp {}", event.name_detailed());
// If the message comes from another machine, do not // If the message comes from another machine, do not
@ -563,11 +560,11 @@ where
} }
} }
impl<EMH, S, SP> ProgressReporter<S> for LlmpEventManager<EMH, S, SP> impl<EMH, I, S, SP> ProgressReporter<S> for LlmpEventManager<EMH, I, S, SP>
where where
S: HasExecutions + HasLastReportTime + HasMetadata + HasCorpus + MaybeHasClientPerfMonitor, S: HasExecutions + HasLastReportTime + HasMetadata + MaybeHasClientPerfMonitor,
SP: ShMemProvider, SP: ShMemProvider,
<S::Corpus as Corpus>::Input: Serialize, I: Serialize,
{ {
fn maybe_report_progress( fn maybe_report_progress(
&mut self, &mut self,
@ -582,7 +579,7 @@ where
} }
} }
impl<EMH, S, SP> HasEventManagerId for LlmpEventManager<EMH, S, SP> impl<EMH, I, S, SP> HasEventManagerId for LlmpEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {

View File

@ -15,11 +15,10 @@ use libafl_bolts::{
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
use crate::{ use crate::{
corpus::Corpus,
events::{Event, EventFirer}, events::{Event, EventFirer},
fuzzer::EvaluatorObservers, fuzzer::EvaluatorObservers,
inputs::{Input, InputConverter, NopInput, NopInputConverter}, inputs::{Input, InputConverter, NopInput, NopInputConverter},
state::{HasCorpus, NopState}, state::NopState,
Error, Error,
}; };
@ -83,7 +82,7 @@ impl LlmpShouldSaveState {
} }
/// A manager-like llmp client that converts between input types /// A manager-like llmp client that converts between input types
pub struct LlmpEventConverter<IC, ICB, S, SP> pub struct LlmpEventConverter<I, IC, ICB, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -94,11 +93,12 @@ where
compressor: GzipCompressor, compressor: GzipCompressor,
converter: Option<IC>, converter: Option<IC>,
converter_back: Option<ICB>, converter_back: Option<ICB>,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl impl
LlmpEventConverter< LlmpEventConverter<
NopInput,
NopInputConverter<NopInput>, NopInputConverter<NopInput>,
NopInputConverter<NopInput>, NopInputConverter<NopInput>,
NopState<NopInput>, NopState<NopInput>,
@ -134,12 +134,12 @@ impl LlmpEventConverterBuilder {
} }
/// Create a event converter from a raw llmp client /// Create a event converter from a raw llmp client
pub fn build_from_client<IC, ICB, S, SP>( pub fn build_from_client<I, IC, ICB, S, SP>(
self, self,
llmp: LlmpClient<SP>, llmp: LlmpClient<SP>,
converter: Option<IC>, converter: Option<IC>,
converter_back: Option<ICB>, converter_back: Option<ICB>,
) -> Result<LlmpEventConverter<IC, ICB, S, SP>, Error> ) -> Result<LlmpEventConverter<I, IC, ICB, S, SP>, Error>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -157,13 +157,13 @@ impl LlmpEventConverterBuilder {
/// Create a client from port and the input converters /// Create a client from port and the input converters
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn build_on_port<IC, ICB, S, SP>( pub fn build_on_port<I, IC, ICB, S, SP>(
self, self,
shmem_provider: SP, shmem_provider: SP,
port: u16, port: u16,
converter: Option<IC>, converter: Option<IC>,
converter_back: Option<ICB>, converter_back: Option<ICB>,
) -> Result<LlmpEventConverter<IC, ICB, S, SP>, Error> ) -> Result<LlmpEventConverter<I, IC, ICB, S, SP>, Error>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -182,13 +182,13 @@ impl LlmpEventConverterBuilder {
/// If a client respawns, it may reuse the existing connection, previously stored by [`LlmpClient::to_env()`]. /// If a client respawns, it may reuse the existing connection, previously stored by [`LlmpClient::to_env()`].
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn build_existing_client_from_env<IC, ICB, S, SP>( pub fn build_existing_client_from_env<I, IC, ICB, S, SP>(
self, self,
shmem_provider: SP, shmem_provider: SP,
env_name: &str, env_name: &str,
converter: Option<IC>, converter: Option<IC>,
converter_back: Option<ICB>, converter_back: Option<ICB>,
) -> Result<LlmpEventConverter<IC, ICB, S, SP>, Error> ) -> Result<LlmpEventConverter<I, IC, ICB, S, SP>, Error>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -206,11 +206,11 @@ impl LlmpEventConverterBuilder {
} }
} }
impl<IC, ICB, S, SP> Debug for LlmpEventConverter<IC, ICB, S, SP> impl<I, IC, ICB, S, SP> Debug for LlmpEventConverter<I, IC, ICB, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
ICB: Debug,
IC: Debug, IC: Debug,
ICB: Debug,
{ {
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("LlmpEventConverter"); let mut debug_struct = f.debug_struct("LlmpEventConverter");
@ -226,9 +226,8 @@ where
} }
} }
impl<IC, ICB, S, SP> LlmpEventConverter<IC, ICB, S, SP> impl<I, IC, ICB, S, SP> LlmpEventConverter<I, IC, ICB, S, SP>
where where
S: HasCorpus,
SP: ShMemProvider, SP: ShMemProvider,
{ {
// TODO other new_* routines // TODO other new_* routines
@ -265,8 +264,8 @@ where
event: Event<DI>, event: Event<DI>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
ICB: InputConverter<To = <S::Corpus as Corpus>::Input, From = DI>, ICB: InputConverter<To = I, From = DI>,
Z: EvaluatorObservers<E, EM, <S::Corpus as Corpus>::Input, S>, Z: EvaluatorObservers<E, EM, I, S>,
{ {
match event { match event {
Event::NewTestcase { Event::NewTestcase {
@ -308,9 +307,9 @@ where
manager: &mut EM, manager: &mut EM,
) -> Result<usize, Error> ) -> Result<usize, Error>
where where
ICB: InputConverter<To = <S::Corpus as Corpus>::Input, From = DI>, ICB: InputConverter<To = I, From = DI>,
DI: DeserializeOwned + Input, DI: DeserializeOwned + Input,
Z: EvaluatorObservers<E, EM, <S::Corpus as Corpus>::Input, S>, Z: EvaluatorObservers<E, EM, I, S>,
{ {
// 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();
@ -345,11 +344,9 @@ where
} }
} }
impl<IC, ICB, S, SP> EventFirer<<S::Corpus as Corpus>::Input, S> impl<I, IC, ICB, S, SP> EventFirer<I, S> for LlmpEventConverter<I, IC, ICB, S, SP>
for LlmpEventConverter<IC, ICB, S, SP>
where where
IC: InputConverter<From = <S::Corpus as Corpus>::Input>, IC: InputConverter<From = I>,
S: HasCorpus,
SP: ShMemProvider, SP: ShMemProvider,
IC::To: Serialize, IC::To: Serialize,
{ {
@ -362,11 +359,7 @@ where
} }
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
fn fire( fn fire(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> {
&mut self,
_state: &mut S,
event: Event<<S::Corpus as Corpus>::Input>,
) -> Result<(), Error> {
if self.converter.is_none() { if self.converter.is_none() {
return Ok(()); return Ok(());
} }
@ -418,11 +411,7 @@ where
} }
#[cfg(not(feature = "llmp_compression"))] #[cfg(not(feature = "llmp_compression"))]
fn fire( fn fire(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> {
&mut self,
_state: &mut S,
event: Event<<S::Corpus as Corpus>::Input>,
) -> Result<(), Error> {
if self.converter.is_none() { if self.converter.is_none() {
return Ok(()); return Ok(());
} }

View File

@ -33,7 +33,6 @@ use typed_builder::TypedBuilder;
use crate::events::EVENTMGR_SIGHANDLER_STATE; use crate::events::EVENTMGR_SIGHANDLER_STATE;
use crate::{ use crate::{
common::HasMetadata, common::HasMetadata,
corpus::Corpus,
events::{ events::{
launcher::ClientDescription, serialize_observers_adaptive, std_maybe_report_progress, launcher::ClientDescription, serialize_observers_adaptive, std_maybe_report_progress,
std_report_progress, AdaptiveSerializer, CanSerializeObserver, Event, EventConfig, std_report_progress, AdaptiveSerializer, CanSerializeObserver, Event, EventConfig,
@ -47,28 +46,25 @@ use crate::{
monitors::Monitor, monitors::Monitor,
observers::TimeObserver, observers::TimeObserver,
stages::HasCurrentStageId, stages::HasCurrentStageId,
state::{ state::{HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor, Stoppable},
HasCorpus, HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor,
Stoppable,
},
Error, Error,
}; };
/// 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`)
#[derive(Debug)] #[derive(Debug)]
pub struct LlmpRestartingEventManager<EMH, S, SP> pub struct LlmpRestartingEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
/// The embedded LLMP event manager /// The embedded LLMP event manager
llmp_mgr: LlmpEventManager<EMH, S, SP>, llmp_mgr: LlmpEventManager<EMH, I, 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>,
/// Decide if the state restorer must save the serialized state /// Decide if the state restorer must save the serialized state
save_state: LlmpShouldSaveState, save_state: LlmpShouldSaveState,
} }
impl<EMH, S, SP> AdaptiveSerializer for LlmpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> AdaptiveSerializer for LlmpRestartingEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -103,16 +99,11 @@ where
} }
} }
impl<EMH, S, SP> ProgressReporter<S> for LlmpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> ProgressReporter<S> for LlmpRestartingEventManager<EMH, I, S, SP>
where where
S: HasExecutions S: HasExecutions + HasLastReportTime + HasMetadata + Serialize + MaybeHasClientPerfMonitor,
+ HasLastReportTime
+ HasMetadata
+ HasCorpus
+ Serialize
+ MaybeHasClientPerfMonitor,
SP: ShMemProvider, SP: ShMemProvider,
<S::Corpus as Corpus>::Input: Serialize, I: Serialize,
{ {
fn maybe_report_progress( fn maybe_report_progress(
&mut self, &mut self,
@ -127,14 +118,14 @@ where
} }
} }
impl<EMH, I, S, SP> EventFirer<I, S> for LlmpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> EventFirer<I, S> for LlmpRestartingEventManager<EMH, I, S, SP>
where where
I: Serialize, I: Serialize,
S: HasCorpus + Serialize, S: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
{ {
fn should_send(&self) -> bool { fn should_send(&self) -> bool {
<LlmpEventManager<EMH, S, SP> as EventFirer<I, S>>::should_send(&self.llmp_mgr) <LlmpEventManager<EMH, I, S, SP> as EventFirer<I, S>>::should_send(&self.llmp_mgr)
} }
fn fire(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error> { fn fire(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error> {
@ -145,12 +136,12 @@ where
} }
fn configuration(&self) -> EventConfig { fn configuration(&self) -> EventConfig {
<LlmpEventManager<EMH, S, SP> as EventFirer<I, S>>::configuration(&self.llmp_mgr) <LlmpEventManager<EMH, I, S, SP> as EventFirer<I, S>>::configuration(&self.llmp_mgr)
} }
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<EMH, OT, S, SP> CanSerializeObserver<OT> for LlmpRestartingEventManager<EMH, S, SP> impl<EMH, I, OT, S, SP> CanSerializeObserver<OT> for LlmpRestartingEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
OT: Serialize + MatchNameRef, OT: Serialize + MatchNameRef,
@ -160,7 +151,7 @@ where
} }
} }
impl<EMH, S, SP> EventRestarter<S> for LlmpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> EventRestarter<S> for LlmpRestartingEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
S: Serialize + HasCurrentStageId, S: Serialize + HasCurrentStageId,
@ -186,7 +177,7 @@ where
} }
} }
impl<EMH, S, SP> ManagerExit for LlmpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> ManagerExit for LlmpRestartingEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -205,21 +196,16 @@ where
} }
} }
impl<E, EMH, S, SP, Z> EventProcessor<E, S, Z> for LlmpRestartingEventManager<EMH, S, SP> impl<E, EMH, I, S, SP, Z> EventProcessor<E, S, Z> for LlmpRestartingEventManager<EMH, I, S, SP>
where where
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
E: HasObservers, E: HasObservers,
E::Observers: DeserializeOwned, E::Observers: DeserializeOwned,
S: HasCorpus + HasImported + Stoppable + Serialize, S: HasImported + Stoppable + Serialize,
<S::Corpus as Corpus>::Input: DeserializeOwned + Input, I: DeserializeOwned + Input,
S::Corpus: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
Z: ExecutionProcessor< Z: ExecutionProcessor<LlmpEventManager<EMH, I, S, SP>, I, E::Observers, S>
LlmpEventManager<EMH, S, SP>, + EvaluatorObservers<E, LlmpEventManager<EMH, I, S, SP>, I, S>,
<S::Corpus as Corpus>::Input,
E::Observers,
S,
> + EvaluatorObservers<E, LlmpEventManager<EMH, S, SP>, <S::Corpus as Corpus>::Input, S>,
{ {
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> {
let res = self.llmp_mgr.process(fuzzer, state, executor)?; let res = self.llmp_mgr.process(fuzzer, state, executor)?;
@ -232,7 +218,7 @@ where
} }
} }
impl<EMH, S, SP> HasEventManagerId for LlmpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> HasEventManagerId for LlmpRestartingEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -247,13 +233,16 @@ const _ENV_FUZZER_RECEIVER: &str = "_AFL_ENV_FUZZER_RECEIVER";
/// The llmp (2 way) connection from a fuzzer to the broker (broadcasting all other fuzzer messages) /// The llmp (2 way) connection from a fuzzer to the broker (broadcasting all other fuzzer messages)
const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT"; const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT";
impl<EMH, S, SP> LlmpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> LlmpRestartingEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
S: Serialize, S: Serialize,
{ {
/// 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<EMH, S, SP>, staterestorer: StateRestorer<SP>) -> Self { pub fn new(
llmp_mgr: LlmpEventManager<EMH, I, S, SP>,
staterestorer: StateRestorer<SP>,
) -> Self {
Self { Self {
llmp_mgr, llmp_mgr,
staterestorer, staterestorer,
@ -263,7 +252,7 @@ where
/// Create a new runner specifying if it must save the serialized state on restart. /// Create a new runner specifying if it must save the serialized state on restart.
pub fn with_save_state( pub fn with_save_state(
llmp_mgr: LlmpEventManager<EMH, S, SP>, llmp_mgr: LlmpEventManager<EMH, I, S, SP>,
staterestorer: StateRestorer<SP>, staterestorer: StateRestorer<SP>,
save_state: LlmpShouldSaveState, save_state: LlmpShouldSaveState,
) -> Self { ) -> Self {
@ -315,21 +304,21 @@ pub enum ManagerKind {
/// The restarting mgr is a combination of restarter and runner, that can be used on systems with and without `fork` support. /// The restarting mgr is a combination of restarter and runner, that can be used on systems with and without `fork` support.
/// 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.
#[expect(clippy::type_complexity)] #[expect(clippy::type_complexity)]
pub fn setup_restarting_mgr_std<MT, S>( pub fn setup_restarting_mgr_std<I, MT, S>(
monitor: MT, monitor: MT,
broker_port: u16, broker_port: u16,
configuration: EventConfig, configuration: EventConfig,
) -> Result< ) -> Result<
( (
Option<S>, Option<S>,
LlmpRestartingEventManager<(), S, StdShMemProvider>, LlmpRestartingEventManager<(), I, S, StdShMemProvider>,
), ),
Error, Error,
> >
where where
MT: Monitor + Clone, MT: Monitor + Clone,
S: HasCorpus + Serialize + DeserializeOwned, S: Serialize + DeserializeOwned,
<S::Corpus as Corpus>::Input: DeserializeOwned, I: DeserializeOwned,
{ {
RestartingMgr::builder() RestartingMgr::builder()
.shmem_provider(StdShMemProvider::new()?) .shmem_provider(StdShMemProvider::new()?)
@ -347,7 +336,7 @@ where
/// 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.
/// This one, additionally uses the timeobserver for the adaptive serialization /// This one, additionally uses the timeobserver for the adaptive serialization
#[expect(clippy::type_complexity)] #[expect(clippy::type_complexity)]
pub fn setup_restarting_mgr_std_adaptive<MT, S>( pub fn setup_restarting_mgr_std_adaptive<I, MT, S>(
monitor: MT, monitor: MT,
broker_port: u16, broker_port: u16,
configuration: EventConfig, configuration: EventConfig,
@ -355,14 +344,14 @@ pub fn setup_restarting_mgr_std_adaptive<MT, S>(
) -> Result< ) -> Result<
( (
Option<S>, Option<S>,
LlmpRestartingEventManager<(), S, StdShMemProvider>, LlmpRestartingEventManager<(), I, S, StdShMemProvider>,
), ),
Error, Error,
> >
where where
MT: Monitor + Clone, MT: Monitor + Clone,
S: HasCorpus + Serialize + DeserializeOwned, S: Serialize + DeserializeOwned,
<S::Corpus as Corpus>::Input: DeserializeOwned, I: DeserializeOwned,
{ {
RestartingMgr::builder() RestartingMgr::builder()
.shmem_provider(StdShMemProvider::new()?) .shmem_provider(StdShMemProvider::new()?)
@ -381,7 +370,7 @@ where
/// `restarter` and `runner`, that can be used on systems both with and without `fork` support. The /// `restarter` and `runner`, that can be used on systems both with and without `fork` support. The
/// `restarter` will start a new process each time the child crashes or times out. /// `restarter` will start a new process each time the child crashes or times out.
#[derive(TypedBuilder, Debug)] #[derive(TypedBuilder, Debug)]
pub struct RestartingMgr<EMH, MT, S, SP> { pub struct RestartingMgr<EMH, I, MT, S, SP> {
/// The shared memory provider to use for the broker or client spawned by the restarting /// The shared memory provider to use for the broker or client spawned by the restarting
/// manager. /// manager.
shmem_provider: SP, shmem_provider: SP,
@ -415,20 +404,22 @@ pub struct RestartingMgr<EMH, MT, S, SP> {
#[builder(default = None)] #[builder(default = None)]
time_ref: Option<Handle<TimeObserver>>, time_ref: Option<Handle<TimeObserver>>,
#[builder(setter(skip), default = PhantomData)] #[builder(setter(skip), default = PhantomData)]
phantom_data: PhantomData<(EMH, S)>, phantom_data: PhantomData<(EMH, I, S)>,
} }
#[expect(clippy::type_complexity, clippy::too_many_lines)] #[expect(clippy::type_complexity, clippy::too_many_lines)]
impl<EMH, MT, S, SP> RestartingMgr<EMH, MT, S, SP> impl<EMH, I, MT, S, SP> RestartingMgr<EMH, I, MT, S, SP>
where where
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S> + Copy + Clone, EMH: EventManagerHooksTuple<I, S> + Copy + Clone,
SP: ShMemProvider, SP: ShMemProvider,
S: HasCorpus + Serialize + DeserializeOwned, S: Serialize + DeserializeOwned,
<S::Corpus as Corpus>::Input: DeserializeOwned, I: DeserializeOwned,
MT: Monitor + Clone, MT: Monitor + Clone,
{ {
/// Launch the broker and the clients and fuzz /// Launch the broker and the clients and fuzz
pub fn launch(&mut self) -> Result<(Option<S>, LlmpRestartingEventManager<EMH, S, SP>), Error> { pub fn launch(
&mut self,
) -> Result<(Option<S>, LlmpRestartingEventManager<EMH, I, S, SP>), Error> {
// We start ourselves as child process to actually fuzz // We start ourselves 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()
@ -458,9 +449,7 @@ where
match connection { match connection {
LlmpConnection::IsBroker { broker } => { LlmpConnection::IsBroker { broker } => {
let llmp_hook = let llmp_hook =
StdLlmpEventHook::<<S::Corpus as Corpus>::Input, MT>::new( StdLlmpEventHook::<I, MT>::new(self.monitor.take().unwrap())?;
self.monitor.take().unwrap(),
)?;
// Yep, broker. Just loop here. // Yep, broker. Just loop here.
log::info!( log::info!(
@ -475,7 +464,7 @@ where
return Err(Error::shutting_down()); return Err(Error::shutting_down());
} }
LlmpConnection::IsClient { client } => { LlmpConnection::IsClient { client } => {
let mgr: LlmpEventManager<EMH, S, SP> = LlmpEventManager::builder() let mgr: LlmpEventManager<EMH, I, S, SP> = LlmpEventManager::builder()
.hooks(self.hooks) .hooks(self.hooks)
.build_from_client( .build_from_client(
client, client,

View File

@ -45,11 +45,10 @@ use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use crate::{ use crate::{
corpus::Corpus,
executors::ExitKind, executors::ExitKind,
inputs::Input, inputs::Input,
monitors::UserStats, monitors::UserStats,
state::{HasCorpus, HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor}, state::{HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor},
Error, HasMetadata, Error, HasMetadata,
}; };
@ -489,10 +488,10 @@ where
/// Default implementation of [`ProgressReporter::report_progress`] for implementors with the /// Default implementation of [`ProgressReporter::report_progress`] for implementors with the
/// given constraints /// given constraints
pub fn std_report_progress<EM, S>(reporter: &mut EM, state: &mut S) -> Result<(), Error> pub fn std_report_progress<EM, I, S>(reporter: &mut EM, state: &mut S) -> Result<(), Error>
where where
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
S: HasExecutions + HasLastReportTime + HasCorpus + MaybeHasClientPerfMonitor, S: HasExecutions + HasLastReportTime + MaybeHasClientPerfMonitor,
{ {
let executions = *state.executions(); let executions = *state.executions();
let cur = current_time(); let cur = current_time();

View File

@ -22,7 +22,6 @@ use super::{std_on_restart, ProgressReporter};
#[cfg(all(unix, feature = "std", not(miri)))] #[cfg(all(unix, feature = "std", not(miri)))]
use crate::events::EVENTMGR_SIGHANDLER_STATE; use crate::events::EVENTMGR_SIGHANDLER_STATE;
use crate::{ use crate::{
corpus::Corpus,
events::{ events::{
std_maybe_report_progress, std_report_progress, BrokerEventResult, CanSerializeObserver, std_maybe_report_progress, std_report_progress, BrokerEventResult, CanSerializeObserver,
Event, EventFirer, EventManagerId, EventProcessor, EventRestarter, HasEventManagerId, Event, EventFirer, EventManagerId, EventProcessor, EventRestarter, HasEventManagerId,
@ -30,7 +29,7 @@ use crate::{
}, },
monitors::Monitor, monitors::Monitor,
stages::HasCurrentStageId, stages::HasCurrentStageId,
state::{HasCorpus, HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor, Stoppable}, state::{HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor, Stoppable},
Error, HasMetadata, Error, HasMetadata,
}; };
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -141,13 +140,7 @@ impl<I, MT, S> ProgressReporter<S> for SimpleEventManager<I, MT, S>
where where
I: Debug, I: Debug,
MT: Monitor, MT: Monitor,
S: HasMetadata S: HasMetadata + HasExecutions + HasLastReportTime + Stoppable + MaybeHasClientPerfMonitor,
+ HasExecutions
+ HasLastReportTime
+ Stoppable
+ HasCorpus
+ MaybeHasClientPerfMonitor,
S::Corpus: Corpus<Input = I>,
{ {
fn maybe_report_progress( fn maybe_report_progress(
&mut self, &mut self,
@ -383,13 +376,7 @@ where
I: Debug, I: Debug,
MT: Monitor, MT: Monitor,
SP: ShMemProvider, SP: ShMemProvider,
S: HasExecutions S: HasExecutions + HasMetadata + HasLastReportTime + Stoppable + MaybeHasClientPerfMonitor,
+ HasMetadata
+ HasLastReportTime
+ Stoppable
+ HasCorpus
+ MaybeHasClientPerfMonitor,
S::Corpus: Corpus<Input = I>,
{ {
fn maybe_report_progress( fn maybe_report_progress(
&mut self, &mut self,
@ -435,7 +422,7 @@ where
/// but can still used shared maps to recover from crashes and timeouts. /// but can still used shared maps to recover from crashes and timeouts.
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 + HasSolutions, S: DeserializeOwned + Serialize + HasSolutions<I>,
MT: Debug, MT: Debug,
{ {
// We start ourself as child process to actually fuzz // We start ourself as child process to actually fuzz

View File

@ -42,7 +42,6 @@ use super::{std_maybe_report_progress, std_report_progress, ManagerExit};
#[cfg(all(unix, not(miri)))] #[cfg(all(unix, not(miri)))]
use crate::events::EVENTMGR_SIGHANDLER_STATE; use crate::events::EVENTMGR_SIGHANDLER_STATE;
use crate::{ use crate::{
corpus::Corpus,
events::{ events::{
std_on_restart, BrokerEventResult, Event, EventConfig, EventFirer, EventManagerHooksTuple, std_on_restart, BrokerEventResult, Event, EventConfig, EventFirer, EventManagerHooksTuple,
EventManagerId, EventProcessor, EventRestarter, HasEventManagerId, ProgressReporter, EventManagerId, EventProcessor, EventRestarter, HasEventManagerId, ProgressReporter,
@ -53,10 +52,7 @@ use crate::{
monitors::Monitor, monitors::Monitor,
observers::ObserversTuple, observers::ObserversTuple,
stages::HasCurrentStageId, stages::HasCurrentStageId,
state::{ state::{HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor, Stoppable},
HasCorpus, HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor,
Stoppable,
},
Error, HasMetadata, Error, HasMetadata,
}; };
@ -409,7 +405,7 @@ where
} }
/// An `EventManager` that forwards all events to other attached via tcp. /// An `EventManager` that forwards all events to other attached via tcp.
pub struct TcpEventManager<EMH, S> { pub struct TcpEventManager<EMH, I, S> {
/// We send message every `throttle` second /// We send message every `throttle` second
throttle: Option<Duration>, throttle: Option<Duration>,
/// When we sent the last message /// When we sent the last message
@ -425,32 +421,32 @@ pub struct TcpEventManager<EMH, S> {
/// A node will not re-use the observer values sent over TCP /// A node will not re-use the observer values sent over TCP
/// from nodes with other configurations. /// from nodes with other configurations.
configuration: EventConfig, configuration: EventConfig,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<S> TcpEventManager<(), S> { impl<I, S> TcpEventManager<(), I, S> {
/// Create a builder for [`TcpEventManager`] /// Create a builder for [`TcpEventManager`]
#[must_use] #[must_use]
pub fn builder() -> TcpEventManagerBuilder<(), S> { pub fn builder() -> TcpEventManagerBuilder<(), I, S> {
TcpEventManagerBuilder::new() TcpEventManagerBuilder::new()
} }
} }
/// Builder for `TcpEventManager` /// Builder for `TcpEventManager`
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct TcpEventManagerBuilder<EMH, S> { pub struct TcpEventManagerBuilder<EMH, I, S> {
throttle: Option<Duration>, throttle: Option<Duration>,
hooks: EMH, hooks: EMH,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<S> Default for TcpEventManagerBuilder<(), S> { impl<I, S> Default for TcpEventManagerBuilder<(), I, S> {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
} }
impl<S> TcpEventManagerBuilder<(), S> { impl<I, S> TcpEventManagerBuilder<(), I, S> {
/// Set the constructor /// Set the constructor
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
@ -463,7 +459,7 @@ impl<S> TcpEventManagerBuilder<(), S> {
/// Set the hooks /// Set the hooks
#[must_use] #[must_use]
pub fn hooks<EMH>(self, hooks: EMH) -> TcpEventManagerBuilder<EMH, S> { pub fn hooks<EMH>(self, hooks: EMH) -> TcpEventManagerBuilder<EMH, I, S> {
TcpEventManagerBuilder { TcpEventManagerBuilder {
throttle: self.throttle, throttle: self.throttle,
hooks, hooks,
@ -472,7 +468,7 @@ impl<S> TcpEventManagerBuilder<(), S> {
} }
} }
impl<EMH, S> TcpEventManagerBuilder<EMH, S> { impl<EMH, I, S> TcpEventManagerBuilder<EMH, I, S> {
/// Set the throttle /// Set the throttle
#[must_use] #[must_use]
pub fn throttle(mut self, throttle: Duration) -> Self { pub fn throttle(mut self, throttle: Duration) -> Self {
@ -486,7 +482,7 @@ impl<EMH, S> TcpEventManagerBuilder<EMH, S> {
addr: &A, addr: &A,
client_id: ClientId, client_id: ClientId,
configuration: EventConfig, configuration: EventConfig,
) -> Result<TcpEventManager<EMH, S>, Error> { ) -> Result<TcpEventManager<EMH, I, S>, Error> {
let mut tcp = TcpStream::connect(addr)?; let mut tcp = TcpStream::connect(addr)?;
let mut our_client_id_buf = client_id.0.to_le_bytes(); let mut our_client_id_buf = client_id.0.to_le_bytes();
@ -521,7 +517,7 @@ impl<EMH, S> TcpEventManagerBuilder<EMH, S> {
port: u16, port: u16,
client_id: ClientId, client_id: ClientId,
configuration: EventConfig, configuration: EventConfig,
) -> Result<TcpEventManager<EMH, S>, Error> { ) -> Result<TcpEventManager<EMH, I, S>, Error> {
Self::build_from_client(self, &("127.0.0.1", port), client_id, configuration) Self::build_from_client(self, &("127.0.0.1", port), client_id, configuration)
} }
@ -534,13 +530,13 @@ impl<EMH, S> TcpEventManagerBuilder<EMH, S> {
addr: &A, addr: &A,
env_name: &str, env_name: &str,
configuration: EventConfig, configuration: EventConfig,
) -> Result<TcpEventManager<EMH, S>, Error> { ) -> Result<TcpEventManager<EMH, I, S>, Error> {
let this_id = ClientId(str::parse::<u32>(&env::var(env_name)?)?); let this_id = ClientId(str::parse::<u32>(&env::var(env_name)?)?);
Self::build_from_client(self, addr, this_id, configuration) Self::build_from_client(self, addr, this_id, configuration)
} }
} }
impl<EMH, S> core::fmt::Debug for TcpEventManager<EMH, S> { impl<EMH, I, S> core::fmt::Debug for TcpEventManager<EMH, I, S> {
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("TcpEventManager"); let mut debug_struct = f.debug_struct("TcpEventManager");
let debug = debug_struct.field("tcp", &self.tcp); let debug = debug_struct.field("tcp", &self.tcp);
@ -554,17 +550,17 @@ impl<EMH, S> core::fmt::Debug for TcpEventManager<EMH, S> {
} }
} }
impl<EMH, S> Drop for TcpEventManager<EMH, S> { impl<EMH, I, S> Drop for TcpEventManager<EMH, I, S> {
/// TCP clients will have to wait until their pages are mapped by somebody. /// TCP clients will have to wait until their pages are mapped by somebody.
fn drop(&mut self) { fn drop(&mut self) {
self.await_restart_safe(); self.await_restart_safe();
} }
} }
impl<EMH, S> TcpEventManager<EMH, S> impl<EMH, I, S> TcpEventManager<EMH, I, S>
where where
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
S: HasExecutions + HasMetadata + HasImported + HasCorpus + Stoppable, S: HasExecutions + HasMetadata + HasImported + Stoppable,
{ {
/// Write the client id for a client `EventManager` to env vars /// Write the client id for a client `EventManager` to env vars
pub fn to_env(&self, env_name: &str) { pub fn to_env(&self, env_name: &str) {
@ -578,14 +574,13 @@ where
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut S,
client_id: ClientId, client_id: ClientId,
event: Event<<S::Corpus as Corpus>::Input>, event: Event<I>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<Self, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, E: Executor<Self, I, S, Z> + HasObservers,
E::Observers: Serialize + ObserversTuple<<S::Corpus as Corpus>::Input, S>, E::Observers: Serialize + ObserversTuple<I, S>,
for<'a> E::Observers: Deserialize<'a>, for<'a> E::Observers: Deserialize<'a>,
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S> Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
{ {
if !self.hooks.pre_exec_all(state, client_id, &event)? { if !self.hooks.pre_exec_all(state, client_id, &event)? {
return Ok(()); return Ok(());
@ -630,7 +625,7 @@ where
} }
} }
impl<EMH, S> TcpEventManager<EMH, S> { impl<EMH, I, S> TcpEventManager<EMH, I, S> {
/// Send information that this client is exiting. /// Send information that this client is exiting.
/// The other side may free up all allocated memory. /// The other side may free up all allocated memory.
/// We are no longer allowed to send anything afterwards. /// We are no longer allowed to send anything afterwards.
@ -641,11 +636,10 @@ impl<EMH, S> TcpEventManager<EMH, S> {
} }
} }
impl<EMH, S> EventFirer<<S::Corpus as Corpus>::Input, S> for TcpEventManager<EMH, S> impl<EMH, I, S> EventFirer<I, S> for TcpEventManager<EMH, I, S>
where where
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
S: HasCorpus, I: Serialize,
<S::Corpus as Corpus>::Input: Serialize,
{ {
fn should_send(&self) -> bool { fn should_send(&self) -> bool {
if let Some(throttle) = self.throttle { if let Some(throttle) = self.throttle {
@ -655,11 +649,7 @@ where
} }
} }
fn fire( fn fire(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> {
&mut self,
_state: &mut S,
event: Event<<S::Corpus as Corpus>::Input>,
) -> Result<(), Error> {
let serialized = postcard::to_allocvec(&event)?; let serialized = postcard::to_allocvec(&event)?;
#[cfg(feature = "tcp_compression")] #[cfg(feature = "tcp_compression")]
@ -679,7 +669,7 @@ where
} }
} }
impl<EMH, S> EventRestarter<S> for TcpEventManager<EMH, S> impl<EMH, I, S> EventRestarter<S> for TcpEventManager<EMH, I, S>
where where
S: HasCurrentStageId, S: HasCurrentStageId,
{ {
@ -688,16 +678,15 @@ where
} }
} }
impl<E, EMH, S, Z> EventProcessor<E, S, Z> for TcpEventManager<EMH, S> impl<E, EMH, I, S, Z> EventProcessor<E, S, Z> for TcpEventManager<EMH, I, S>
where where
E: HasObservers + Executor<Self, <S::Corpus as Corpus>::Input, S, Z>, E: HasObservers + Executor<Self, I, S, Z>,
E::Observers: Serialize + ObserversTuple<<S::Corpus as Corpus>::Input, S>, E::Observers: Serialize + ObserversTuple<I, S>,
for<'a> E::Observers: Deserialize<'a>, for<'a> E::Observers: Deserialize<'a>,
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
S: HasExecutions + HasMetadata + HasImported + HasCorpus + Stoppable, S: HasExecutions + HasMetadata + HasImported + Stoppable,
<S::Corpus as Corpus>::Input: DeserializeOwned, I: DeserializeOwned,
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S> Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
{ {
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> {
// TODO: Get around local event copy by moving handle_in_client // TODO: Get around local event copy by moving handle_in_client
@ -758,7 +747,7 @@ where
} }
} }
impl<EMH, S> ManagerExit for TcpEventManager<EMH, S> { impl<EMH, I, S> ManagerExit for TcpEventManager<EMH, I, S> {
/// The TCP client needs to wait until a broker has mapped all pages before shutting down. /// The TCP client needs to wait until a broker has 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.
fn await_restart_safe(&mut self) { fn await_restart_safe(&mut self) {
@ -773,11 +762,11 @@ impl<EMH, S> ManagerExit for TcpEventManager<EMH, S> {
} }
} }
impl<EMH, S> ProgressReporter<S> for TcpEventManager<EMH, S> impl<EMH, I, S> ProgressReporter<S> for TcpEventManager<EMH, I, S>
where where
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
<S::Corpus as Corpus>::Input: Serialize, I: Serialize,
S: HasExecutions + HasMetadata + HasLastReportTime + HasCorpus + MaybeHasClientPerfMonitor, S: HasExecutions + HasMetadata + HasLastReportTime + MaybeHasClientPerfMonitor,
{ {
fn maybe_report_progress( fn maybe_report_progress(
&mut self, &mut self,
@ -792,7 +781,7 @@ where
} }
} }
impl<EMH, S> HasEventManagerId for TcpEventManager<EMH, S> { impl<EMH, I, S> HasEventManagerId for TcpEventManager<EMH, I, S> {
/// Gets the id assigned to this staterestorer. /// Gets the id assigned to this staterestorer.
fn mgr_id(&self) -> EventManagerId { fn mgr_id(&self) -> EventManagerId {
EventManagerId(self.client_id.0 as usize) EventManagerId(self.client_id.0 as usize)
@ -801,23 +790,23 @@ impl<EMH, S> HasEventManagerId for TcpEventManager<EMH, S> {
/// 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`)
#[derive(Debug)] #[derive(Debug)]
pub struct TcpRestartingEventManager<EMH, S, SP> pub struct TcpRestartingEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
/// The embedded TCP event manager /// The embedded TCP event manager
tcp_mgr: TcpEventManager<EMH, S>, tcp_mgr: TcpEventManager<EMH, I, S>,
/// 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>,
/// Decide if the state restorer must save the serialized state /// Decide if the state restorer must save the serialized state
save_state: bool, save_state: bool,
} }
impl<EMH, S, SP> ProgressReporter<S> for TcpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> ProgressReporter<S> for TcpRestartingEventManager<EMH, I, S, SP>
where where
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
S: HasMetadata + HasExecutions + HasLastReportTime + HasCorpus + MaybeHasClientPerfMonitor, S: HasMetadata + HasExecutions + HasLastReportTime + MaybeHasClientPerfMonitor,
<S::Corpus as Corpus>::Input: Serialize, I: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
{ {
fn maybe_report_progress( fn maybe_report_progress(
@ -833,23 +822,17 @@ where
} }
} }
impl<EMH, S, SP> EventFirer<<S::Corpus as Corpus>::Input, S> impl<EMH, I, S, SP> EventFirer<I, S> for TcpRestartingEventManager<EMH, I, S, SP>
for TcpRestartingEventManager<EMH, S, SP>
where where
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
S: HasCorpus, I: Serialize,
<S::Corpus as Corpus>::Input: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
{ {
fn should_send(&self) -> bool { fn should_send(&self) -> bool {
self.tcp_mgr.should_send() self.tcp_mgr.should_send()
} }
fn fire( fn fire(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error> {
&mut self,
state: &mut S,
event: Event<<S::Corpus as Corpus>::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.tcp_mgr.fire(state, event) self.tcp_mgr.fire(state, event)
} }
@ -859,7 +842,7 @@ where
} }
} }
impl<EMH, S, SP> ManagerExit for TcpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> ManagerExit for TcpRestartingEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -878,10 +861,10 @@ where
} }
} }
impl<EMH, S, SP> EventRestarter<S> for TcpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> EventRestarter<S> for TcpRestartingEventManager<EMH, I, S, SP>
where where
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
S: HasCorpus + HasExecutions + HasCurrentStageId + Serialize, S: HasExecutions + HasCurrentStageId + Serialize,
SP: ShMemProvider, SP: ShMemProvider,
{ {
/// 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.
@ -901,17 +884,17 @@ where
} }
} }
impl<E, EMH, S, SP, Z> EventProcessor<E, S, Z> for TcpRestartingEventManager<EMH, S, SP> impl<E, EMH, I, S, SP, Z> EventProcessor<E, S, Z> for TcpRestartingEventManager<EMH, I, S, SP>
where where
E: HasObservers + Executor<TcpEventManager<EMH, S>, <S::Corpus as Corpus>::Input, S, Z>, E: HasObservers + Executor<TcpEventManager<EMH, I, S>, I, S, Z>,
for<'a> E::Observers: Deserialize<'a>, for<'a> E::Observers: Deserialize<'a>,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize, E::Observers: ObserversTuple<I, S> + Serialize,
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
S: HasExecutions + HasMetadata + HasImported + HasCorpus + Stoppable, I: DeserializeOwned,
<S::Corpus as Corpus>::Input: DeserializeOwned, S: HasExecutions + HasMetadata + HasImported + Stoppable,
SP: ShMemProvider, SP: ShMemProvider,
Z: ExecutionProcessor<TcpEventManager<EMH, S>, <S::Corpus as Corpus>::Input, E::Observers, S> Z: ExecutionProcessor<TcpEventManager<EMH, I, S>, I, E::Observers, S>
+ EvaluatorObservers<E, TcpEventManager<EMH, S>, <S::Corpus as Corpus>::Input, S>, + EvaluatorObservers<E, TcpEventManager<EMH, I, S>, I, S>,
{ {
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.tcp_mgr.process(fuzzer, state, executor) self.tcp_mgr.process(fuzzer, state, executor)
@ -922,7 +905,7 @@ where
} }
} }
impl<EMH, S, SP> HasEventManagerId for TcpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> HasEventManagerId for TcpRestartingEventManager<EMH, I, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -937,15 +920,13 @@ const _ENV_FUZZER_RECEIVER: &str = "_AFL_ENV_FUZZER_RECEIVER";
/// The tcp (2 way) connection from a fuzzer to the broker (broadcasting all other fuzzer messages) /// The tcp (2 way) connection from a fuzzer to the broker (broadcasting all other fuzzer messages)
const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT"; const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT";
impl<EMH, S, SP> TcpRestartingEventManager<EMH, S, SP> impl<EMH, I, S, SP> TcpRestartingEventManager<EMH, I, S, SP>
where where
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>, EMH: EventManagerHooksTuple<I, S>,
S: HasCorpus,
SP: ShMemProvider, SP: ShMemProvider,
//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(tcp_mgr: TcpEventManager<EMH, S>, staterestorer: StateRestorer<SP>) -> Self { pub fn new(tcp_mgr: TcpEventManager<EMH, I, S>, staterestorer: StateRestorer<SP>) -> Self {
Self { Self {
tcp_mgr, tcp_mgr,
staterestorer, staterestorer,
@ -955,7 +936,7 @@ where
/// Create a new runner specifying if it must save the serialized state on restart. /// Create a new runner specifying if it must save the serialized state on restart.
pub fn with_save_state( pub fn with_save_state(
tcp_mgr: TcpEventManager<EMH, S>, tcp_mgr: TcpEventManager<EMH, I, S>,
staterestorer: StateRestorer<SP>, staterestorer: StateRestorer<SP>,
save_state: bool, save_state: bool,
) -> Self { ) -> Self {
@ -996,21 +977,21 @@ pub enum TcpManagerKind {
/// The [`TcpRestartingEventManager`] is a combination of restarter and runner, that can be used on systems with and without `fork` support. /// The [`TcpRestartingEventManager`] is a combination of restarter and runner, that can be used on systems with and without `fork` support.
/// 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.
#[expect(clippy::type_complexity)] #[expect(clippy::type_complexity)]
pub fn setup_restarting_mgr_tcp<MT, S>( pub fn setup_restarting_mgr_tcp<I, MT, S>(
monitor: MT, monitor: MT,
broker_port: u16, broker_port: u16,
configuration: EventConfig, configuration: EventConfig,
) -> Result< ) -> Result<
( (
Option<S>, Option<S>,
TcpRestartingEventManager<(), S, StdShMemProvider>, TcpRestartingEventManager<(), I, S, StdShMemProvider>,
), ),
Error, Error,
> >
where where
MT: Monitor + Clone, MT: Monitor + Clone,
S: HasExecutions + HasMetadata + HasImported + HasCorpus + DeserializeOwned + Stoppable, S: HasExecutions + HasMetadata + HasImported + DeserializeOwned + Stoppable,
<S::Corpus as Corpus>::Input: Input, I: Input,
{ {
TcpRestartingMgr::builder() TcpRestartingMgr::builder()
.shmem_provider(StdShMemProvider::new()?) .shmem_provider(StdShMemProvider::new()?)
@ -1028,11 +1009,11 @@ where
/// `restarter` and `runner`, that can be used on systems both with and without `fork` support. The /// `restarter` and `runner`, that can be used on systems both with and without `fork` support. The
/// `restarter` will start a new process each time the child crashes or times out. /// `restarter` will start a new process each time the child crashes or times out.
#[derive(TypedBuilder, Debug)] #[derive(TypedBuilder, Debug)]
pub struct TcpRestartingMgr<EMH, MT, S, SP> pub struct TcpRestartingMgr<EMH, I, MT, S, SP>
where where
MT: Monitor,
S: DeserializeOwned, S: DeserializeOwned,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
MT: Monitor,
{ {
/// The shared memory provider to use for the broker or client spawned by the restarting /// The shared memory provider to use for the broker or client spawned by the restarting
/// manager. /// manager.
@ -1065,25 +1046,26 @@ where
/// The hooks for `handle_in_client` /// The hooks for `handle_in_client`
hooks: EMH, hooks: EMH,
#[builder(setter(skip), default = PhantomData)] #[builder(setter(skip), default = PhantomData)]
phantom_data: PhantomData<S>, phantom_data: PhantomData<(I, S)>,
} }
#[expect(clippy::type_complexity, clippy::too_many_lines)] #[expect(clippy::type_complexity, clippy::too_many_lines)]
impl<EMH, MT, S, SP> TcpRestartingMgr<EMH, MT, S, SP> impl<EMH, I, MT, S, SP> TcpRestartingMgr<EMH, I, MT, S, SP>
where where
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S> + Copy + Clone, EMH: EventManagerHooksTuple<I, S> + Copy + Clone,
SP: ShMemProvider, I: Input,
S: HasExecutions + HasMetadata + HasImported + HasCorpus + DeserializeOwned + Stoppable,
<S::Corpus as Corpus>::Input: Input,
MT: Monitor + Clone, MT: Monitor + Clone,
SP: ShMemProvider,
S: HasExecutions + HasMetadata + HasImported + DeserializeOwned + Stoppable,
{ {
/// Launch the restarting manager /// Launch the restarting manager
pub fn launch(&mut self) -> Result<(Option<S>, TcpRestartingEventManager<EMH, S, SP>), Error> { pub fn launch(
&mut self,
) -> Result<(Option<S>, TcpRestartingEventManager<EMH, I, 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 env::var(_ENV_FUZZER_SENDER).is_err() let (staterestorer, _new_shmem_provider, core_id) = if env::var(_ENV_FUZZER_SENDER).is_err()
{ {
let broker_things = |mut broker: TcpEventBroker<<S::Corpus as Corpus>::Input, MT>, let broker_things = |mut broker: TcpEventBroker<I, MT>, _remote_broker_addr| {
_remote_broker_addr| {
if let Some(exit_cleanly_after) = self.exit_cleanly_after { if let Some(exit_cleanly_after) = self.exit_cleanly_after {
broker.set_exit_cleanly_after(exit_cleanly_after); broker.set_exit_cleanly_after(exit_cleanly_after);
} }
@ -1097,8 +1079,7 @@ where
let connection = create_nonblocking_listener(("127.0.0.1", self.broker_port)); let connection = create_nonblocking_listener(("127.0.0.1", self.broker_port));
match connection { match connection {
Ok(listener) => { Ok(listener) => {
let event_broker = let event_broker = TcpEventBroker::<I, MT>::with_listener(
TcpEventBroker::<<S::Corpus as Corpus>::Input, MT>::with_listener(
listener, listener,
self.monitor.take().unwrap(), self.monitor.take().unwrap(),
); );
@ -1129,7 +1110,7 @@ where
} }
} }
TcpManagerKind::Broker => { TcpManagerKind::Broker => {
let event_broker = TcpEventBroker::<<S::Corpus as Corpus>::Input, MT>::new( let event_broker = TcpEventBroker::<I, MT>::new(
format!("127.0.0.1:{}", self.broker_port), format!("127.0.0.1:{}", self.broker_port),
self.monitor.take().unwrap(), self.monitor.take().unwrap(),
)?; )?;

View File

@ -49,11 +49,10 @@ use super::HasTimeout;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use crate::executors::hooks::ExecutorHooksTuple; use crate::executors::hooks::ExecutorHooksTuple;
use crate::{ use crate::{
corpus::Corpus,
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
inputs::HasTargetBytes, inputs::HasTargetBytes,
observers::{ObserversTuple, StdErrObserver, StdOutObserver}, observers::{ObserversTuple, StdErrObserver, StdOutObserver},
state::{HasCorpus, HasExecutions}, state::HasExecutions,
std::borrow::ToOwned, std::borrow::ToOwned,
Error, Error,
}; };
@ -280,17 +279,16 @@ where
/// ///
/// 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 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<OT, S, T, HT = (), C = Child> { pub struct CommandExecutor<I, OT, S, T, HT = (), C = Child> {
/// The wrapped command configurer /// The wrapped command configurer
configurer: T, configurer: T,
/// The observers used by this executor /// The observers used by this executor
observers: OT, observers: OT,
hooks: HT, hooks: HT,
phantom: PhantomData<S>, phantom: PhantomData<(C, I, S)>,
phantom_child: PhantomData<C>,
} }
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`].
@ -308,7 +306,7 @@ impl CommandExecutor<(), (), ()> {
} }
} }
impl<OT, S, T, HT, C> Debug for CommandExecutor<OT, S, T, HT, C> impl<I, OT, S, T, HT, C> Debug for CommandExecutor<I, OT, S, T, HT, C>
where where
T: Debug, T: Debug,
OT: Debug, OT: Debug,
@ -323,7 +321,7 @@ where
} }
} }
impl<OT, S, T, HT, C> CommandExecutor<OT, S, T, HT, C> { impl<I, OT, S, T, HT, C> CommandExecutor<I, OT, S, T, HT, C> {
/// Accesses the inner value /// Accesses the inner value
pub fn inner(&mut self) -> &mut T { pub fn inner(&mut self) -> &mut T {
&mut self.configurer &mut self.configurer
@ -331,17 +329,13 @@ impl<OT, S, T, HT, C> CommandExecutor<OT, S, T, HT, C> {
} }
// 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
impl<OT, S, T> CommandExecutor<OT, S, T> impl<I, OT, S, T> CommandExecutor<I, OT, S, T>
where where
S: HasExecutions + HasCorpus, S: HasExecutions,
T: CommandConfigurator<<S::Corpus as Corpus>::Input> + Debug, T: CommandConfigurator<I> + Debug,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>, OT: ObserversTuple<I, S>,
{ {
fn execute_input_with_command( fn execute_input_with_command(&mut self, state: &mut S, input: &I) -> Result<ExitKind, Error> {
&mut self,
state: &mut S,
input: &<S::Corpus as Corpus>::Input,
) -> Result<ExitKind, Error> {
use wait_timeout::ChildExt; use wait_timeout::ChildExt;
*state.executions_mut() += 1; *state.executions_mut() += 1;
@ -391,28 +385,27 @@ where
} }
} }
impl<EM, OT, S, T, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z> for CommandExecutor<OT, S, T> impl<EM, I, OT, S, T, Z> Executor<EM, I, S, Z> for CommandExecutor<I, OT, S, T>
where where
S: HasExecutions + HasCorpus, S: HasExecutions,
T: CommandConfigurator<<S::Corpus as Corpus>::Input> + Debug, T: CommandConfigurator<I> + Debug,
OT: MatchName + ObserversTuple<<S::Corpus as Corpus>::Input, S>, OT: MatchName + ObserversTuple<I, S>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
state: &mut S, state: &mut S,
_mgr: &mut EM, _mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
self.execute_input_with_command(state, input) self.execute_input_with_command(state, input)
} }
} }
// 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
impl<OT, S, T> HasTimeout for CommandExecutor<OT, S, T> impl<I, OT, S, T> HasTimeout for CommandExecutor<I, OT, S, T>
where where
S: HasCorpus, T: CommandConfigurator<I>,
T: CommandConfigurator<<S::Corpus as Corpus>::Input>,
{ {
#[inline] #[inline]
fn timeout(&self) -> Duration { fn timeout(&self) -> Duration {
@ -426,13 +419,12 @@ where
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
impl<EM, OT, S, T, Z, HT> Executor<EM, <S::Corpus as Corpus>::Input, S, Z> impl<EM, I, OT, S, T, Z, HT> Executor<EM, I, S, Z> for CommandExecutor<I, OT, S, T, HT, Pid>
for CommandExecutor<OT, S, T, HT, Pid>
where where
S: HasCorpus + HasExecutions, HT: ExecutorHooksTuple<I, S>,
T: CommandConfigurator<<S::Corpus as Corpus>::Input, Pid> + Debug, OT: MatchName + ObserversTuple<I, S>,
OT: MatchName + ObserversTuple<<S::Corpus as Corpus>::Input, S>, S: HasExecutions,
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>, T: CommandConfigurator<I, Pid> + Debug,
{ {
/// Linux specific low level implementation, to directly handle `fork`, `exec` and use linux /// Linux specific low level implementation, to directly handle `fork`, `exec` and use linux
/// `ptrace` /// `ptrace`
@ -444,7 +436,7 @@ where
_fuzzer: &mut Z, _fuzzer: &mut Z,
state: &mut S, state: &mut S,
_mgr: &mut EM, _mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
*state.executions_mut() += 1; *state.executions_mut() += 1;
@ -502,10 +494,9 @@ where
} }
} }
impl<OT, S, T, HT, C> HasObservers for CommandExecutor<OT, S, T, HT, C> impl<I, OT, S, T, HT, C> HasObservers for CommandExecutor<I, OT, S, T, HT, C>
where where
S: HasCorpus, OT: ObserversTuple<I, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
{ {
type Observers = OT; type Observers = OT;
@ -683,14 +674,13 @@ impl CommandExecutorBuilder {
} }
/// Builds the `CommandExecutor` /// Builds the `CommandExecutor`
pub fn build<OT, S>( pub fn build<I, OT, S>(
&self, &self,
observers: OT, observers: OT,
) -> Result<CommandExecutor<OT, S, StdCommandConfigurator>, Error> ) -> Result<CommandExecutor<I, OT, S, StdCommandConfigurator>, Error>
where where
S: HasCorpus, I: HasTargetBytes,
<S::Corpus as Corpus>::Input: HasTargetBytes, OT: MatchName + ObserversTuple<I, S>,
OT: MatchName + ObserversTuple<<S::Corpus as Corpus>::Input, S>,
{ {
let Some(program) = &self.program else { let Some(program) = &self.program else {
return Err(Error::illegal_argument( return Err(Error::illegal_argument(
@ -737,9 +727,12 @@ impl CommandExecutorBuilder {
timeout: self.timeout, timeout: self.timeout,
command, command,
}; };
Ok(<StdCommandConfigurator as CommandConfigurator< Ok(
<S::Corpus as Corpus>::Input, <StdCommandConfigurator as CommandConfigurator<I>>::into_executor::<OT, S>(
>>::into_executor::<OT, S>(configurator, observers)) configurator,
observers,
),
)
} }
} }
@ -747,7 +740,7 @@ impl CommandExecutorBuilder {
/// # Example /// # Example
/// ``` /// ```
/// use std::{io::Write, process::{Stdio, Command, Child}, time::Duration}; /// use std::{io::Write, process::{Stdio, Command, Child}, time::Duration};
/// use libafl::{Error, corpus::Corpus, inputs::{BytesInput, HasTargetBytes, Input}, executors::{Executor, command::CommandConfigurator}, state::{HasCorpus, HasExecutions}}; /// use libafl::{Error, corpus::Corpus, inputs::{BytesInput, HasTargetBytes, Input}, executors::{Executor, command::CommandConfigurator}, state::{HasExecutions}};
/// use libafl_bolts::AsSlice; /// use libafl_bolts::AsSlice;
/// #[derive(Debug)] /// #[derive(Debug)]
/// struct MyExecutor; /// struct MyExecutor;
@ -779,8 +772,7 @@ impl CommandExecutorBuilder {
/// ///
/// fn make_executor<EM, S, Z>() -> impl Executor<EM, BytesInput, S, Z> /// fn make_executor<EM, S, Z>() -> impl Executor<EM, BytesInput, S, Z>
/// where /// where
/// S: HasCorpus + HasExecutions, /// S: HasExecutions,
/// S::Corpus: Corpus<Input = BytesInput>
/// { /// {
/// MyExecutor.into_executor(()) /// MyExecutor.into_executor(())
/// } /// }
@ -816,13 +808,12 @@ pub trait CommandConfigurator<I, C = Child>: Sized {
} }
/// Create an `Executor` from this `CommandConfigurator`. /// Create an `Executor` from this `CommandConfigurator`.
fn into_executor<OT, S>(self, observers: OT) -> CommandExecutor<OT, S, Self, (), C> { fn into_executor<OT, S>(self, observers: OT) -> CommandExecutor<I, OT, S, Self, (), C> {
CommandExecutor { CommandExecutor {
configurer: self, configurer: self,
observers, observers,
hooks: (), hooks: (),
phantom: PhantomData, phantom: PhantomData,
phantom_child: PhantomData,
} }
} }
@ -831,13 +822,12 @@ pub trait CommandConfigurator<I, C = Child>: Sized {
self, self,
observers: OT, observers: OT,
hooks: HT, hooks: HT,
) -> CommandExecutor<OT, S, Self, HT, C> { ) -> CommandExecutor<I, OT, S, Self, HT, C> {
CommandExecutor { CommandExecutor {
configurer: self, configurer: self,
observers, observers,
hooks, hooks,
phantom: PhantomData, phantom: PhantomData,
phantom_child: PhantomData,
} }
} }
} }
@ -890,7 +880,7 @@ mod tests {
executor executor
.run_target( .run_target(
&mut NopFuzzer::new(), &mut NopFuzzer::new(),
&mut NopState::new(), &mut NopState::<NopInput>::new(),
&mut mgr, &mut mgr,
&BytesInput::new(b"test".to_vec()), &BytesInput::new(b"test".to_vec()),
) )

View File

@ -19,23 +19,21 @@ use serde::{Deserialize, Serialize};
use super::HasTimeout; use super::HasTimeout;
use crate::{ use crate::{
corpus::Corpus,
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
observers::{DifferentialObserversTuple, ObserversTuple}, observers::{DifferentialObserversTuple, ObserversTuple},
state::HasCorpus,
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, DOT, OTA, OTB, S> { pub struct DiffExecutor<A, B, DOT, I, OTA, OTB, S> {
primary: A, primary: A,
secondary: B, secondary: B,
observers: UnsafeCell<ProxyObserversTuple<OTA, OTB, DOT>>, observers: UnsafeCell<ProxyObserversTuple<OTA, OTB, DOT>>,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<A, B, DOT, OTA, OTB, S> DiffExecutor<A, B, DOT, OTA, OTB, S> { impl<A, B, DOT, I, OTA, OTB, S> DiffExecutor<A, B, DOT, I, OTA, OTB, S> {
/// Create a new `DiffExecutor`, wrapping the given `executor`s. /// Create a new `DiffExecutor`, wrapping the given `executor`s.
pub fn new(primary: A, secondary: B, observers: DOT) -> Self { pub fn new(primary: A, secondary: B, observers: DOT) -> Self {
Self { Self {
@ -61,23 +59,21 @@ impl<A, B, DOT, OTA, OTB, S> DiffExecutor<A, B, DOT, OTA, OTB, S> {
} }
} }
impl<A, B, DOT, EM, S, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z> impl<A, B, DOT, EM, I, S, Z> Executor<EM, I, S, Z>
for DiffExecutor<A, B, DOT, A::Observers, B::Observers, S> for DiffExecutor<A, B, DOT, I, A::Observers, B::Observers, S>
where where
A: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, A: Executor<EM, I, S, Z> + HasObservers,
B: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, B: Executor<EM, I, S, Z> + HasObservers,
<A as HasObservers>::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>, <A as HasObservers>::Observers: ObserversTuple<I, S>,
<B as HasObservers>::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>, <B as HasObservers>::Observers: ObserversTuple<I, S>,
DOT: DifferentialObserversTuple<A::Observers, B::Observers, <S::Corpus as Corpus>::Input, S> DOT: DifferentialObserversTuple<A::Observers, B::Observers, I, S> + MatchName,
+ MatchName,
S: HasCorpus,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut S,
mgr: &mut EM, mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
self.observers(); // update in advance self.observers(); // update in advance
let observers = self.observers.get_mut(); let observers = self.observers.get_mut();
@ -117,7 +113,7 @@ where
} }
} }
impl<A, B, DOT, OTA, OTB, S> HasTimeout for DiffExecutor<A, B, DOT, OTA, OTB, S> impl<A, B, DOT, I, OTA, OTB, S> HasTimeout for DiffExecutor<A, B, DOT, I, OTA, OTB, S>
where where
A: HasTimeout, A: HasTimeout,
B: HasTimeout, B: HasTimeout,
@ -233,14 +229,13 @@ impl<A, B, DOT> ProxyObserversTuple<A, B, DOT> {
} }
} }
impl<A, B, DOT, OTA, OTB, S> HasObservers for DiffExecutor<A, B, DOT, OTA, OTB, S> impl<A, B, DOT, I, OTA, OTB, S> HasObservers for DiffExecutor<A, B, DOT, I, OTA, OTB, S>
where where
A: HasObservers<Observers = OTA>, A: HasObservers<Observers = OTA>,
B: HasObservers<Observers = OTB>, B: HasObservers<Observers = OTB>,
DOT: DifferentialObserversTuple<OTA, OTB, <S::Corpus as Corpus>::Input, S> + MatchName, DOT: DifferentialObserversTuple<OTA, OTB, I, S> + MatchName,
OTA: ObserversTuple<<S::Corpus as Corpus>::Input, S>, OTA: ObserversTuple<I, S>,
OTB: ObserversTuple<<S::Corpus as Corpus>::Input, S>, OTB: ObserversTuple<I, S>,
S: HasCorpus,
{ {
type Observers = ProxyObserversTuple<OTA, OTB, DOT>; type Observers = ProxyObserversTuple<OTA, OTB, DOT>;

View File

@ -43,12 +43,11 @@ use crate::observers::{
get_asan_runtime_flags, get_asan_runtime_flags_with_log_path, AsanBacktraceObserver, get_asan_runtime_flags, get_asan_runtime_flags_with_log_path, AsanBacktraceObserver,
}; };
use crate::{ use crate::{
corpus::Corpus,
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
inputs::{BytesInput, Input, NopTargetBytesConverter, TargetBytesConverter}, inputs::{BytesInput, HasTargetBytes, Input, NopTargetBytesConverter, TargetBytesConverter},
mutators::Tokens, mutators::Tokens,
observers::{MapObserver, Observer, ObserversTuple}, observers::{MapObserver, Observer, ObserversTuple},
state::{HasCorpus, HasExecutions}, state::HasExecutions,
Error, Error,
}; };
@ -607,7 +606,7 @@ impl 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<TC, OT, S, SP> pub struct ForkserverExecutor<I, OT, S, SP, TC>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -619,7 +618,7 @@ where
forkserver: Forkserver, forkserver: Forkserver,
observers: OT, observers: OT,
map: Option<SP::ShMem>, map: Option<SP::ShMem>,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
map_size: Option<usize>, map_size: Option<usize>,
min_input_size: usize, min_input_size: usize,
max_input_size: usize, max_input_size: usize,
@ -629,7 +628,7 @@ where
crash_exitcode: Option<i8>, crash_exitcode: Option<i8>,
} }
impl<TC, OT, S, SP> Debug for ForkserverExecutor<TC, OT, S, SP> impl<I, OT, S, SP, TC> Debug for ForkserverExecutor<I, OT, S, SP, TC>
where where
TC: Debug, TC: Debug,
OT: Debug, OT: Debug,
@ -649,7 +648,7 @@ where
} }
} }
impl ForkserverExecutor<(), (), (), UnixShMemProvider> { impl ForkserverExecutor<(), (), (), UnixShMemProvider, ()> {
/// Builder for `ForkserverExecutor` /// Builder for `ForkserverExecutor`
#[must_use] #[must_use]
pub fn builder( pub fn builder(
@ -659,12 +658,11 @@ impl ForkserverExecutor<(), (), (), UnixShMemProvider> {
} }
} }
impl<TC, OT, S, SP> ForkserverExecutor<TC, OT, S, SP> impl<I, OT, S, SP, TC> ForkserverExecutor<I, OT, S, SP, TC>
where where
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>, OT: ObserversTuple<I, S>,
S: HasCorpus,
SP: ShMemProvider, SP: ShMemProvider,
TC: TargetBytesConverter, TC: TargetBytesConverter<I>,
{ {
/// The `target` binary that's going to run. /// The `target` binary that's going to run.
pub fn target(&self) -> &OsString { pub fn target(&self) -> &OsString {
@ -698,7 +696,7 @@ where
/// Execute input and increase the execution counter. /// Execute input and increase the execution counter.
#[inline] #[inline]
fn execute_input(&mut self, state: &mut S, input: &TC::Input) -> Result<ExitKind, Error> fn execute_input(&mut self, state: &mut S, input: &I) -> Result<ExitKind, Error>
where where
S: HasExecutions, S: HasExecutions,
{ {
@ -709,7 +707,7 @@ where
/// Execute input, but side-step the execution counter. /// Execute input, but side-step the execution counter.
#[inline] #[inline]
fn execute_input_uncounted(&mut self, input: &TC::Input) -> Result<ExitKind, Error> { fn execute_input_uncounted(&mut self, input: &I) -> Result<ExitKind, Error> {
let mut exit_kind = ExitKind::Ok; let mut exit_kind = ExitKind::Ok;
let last_run_timed_out = self.forkserver.last_run_timed_out_raw(); let last_run_timed_out = self.forkserver.last_run_timed_out_raw();
@ -839,13 +837,14 @@ where
/// in case no input file is specified. /// in case no input file is specified.
/// If `debug_child` is set, the child will print to `stdout`/`stderr`. /// If `debug_child` is set, the child will print to `stdout`/`stderr`.
#[expect(clippy::pedantic)] #[expect(clippy::pedantic)]
pub fn build<OT, S>(mut self, observers: OT) -> Result<ForkserverExecutor<TC, OT, S, SP>, Error> pub fn build<I, OT, S>(
mut self,
observers: OT,
) -> Result<ForkserverExecutor<I, OT, S, SP, TC>, Error>
where where
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>, OT: ObserversTuple<I, S>,
S: HasCorpus,
<S::Corpus as Corpus>::Input: Input,
TC: TargetBytesConverter,
SP: ShMemProvider, SP: ShMemProvider,
TC: TargetBytesConverter<I>,
{ {
let (forkserver, input_file, map) = self.build_helper()?; let (forkserver, input_file, map) = self.build_helper()?;
@ -901,18 +900,17 @@ where
} }
/// Builds `ForkserverExecutor` downsizing the coverage map to fit exaclty the AFL++ map size. /// Builds `ForkserverExecutor` downsizing the coverage map to fit exaclty the AFL++ map size.
#[expect(clippy::pedantic)] #[expect(clippy::pedantic, clippy::type_complexity)]
pub fn build_dynamic_map<A, MO, OT, S>( pub fn build_dynamic_map<A, MO, OT, I, S>(
mut self, mut self,
mut map_observer: A, mut map_observer: A,
other_observers: OT, other_observers: OT,
) -> Result<ForkserverExecutor<TC, (A, OT), S, SP>, Error> ) -> Result<ForkserverExecutor<I, (A, OT), S, SP, TC>, Error>
where where
A: Observer<I, S> + AsMut<MO>,
I: Input + HasTargetBytes,
MO: MapObserver + Truncate, // TODO maybe enforce Entry = u8 for the cov map MO: MapObserver + Truncate, // TODO maybe enforce Entry = u8 for the cov map
A: Observer<<S::Corpus as Corpus>::Input, S> + AsMut<MO>, OT: ObserversTuple<I, S> + Prepend<MO>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Prepend<MO>,
<S::Corpus as Corpus>::Input: Input,
S: HasCorpus,
SP: ShMemProvider, SP: ShMemProvider,
{ {
let (forkserver, input_file, map) = self.build_helper()?; let (forkserver, input_file, map) = self.build_helper()?;
@ -1540,7 +1538,7 @@ impl<'a, TC> ForkserverExecutorBuilder<'a, TC, UnixShMemProvider> {
impl<'a, TC, SP> ForkserverExecutorBuilder<'a, TC, SP> { impl<'a, TC, SP> ForkserverExecutorBuilder<'a, TC, SP> {
/// Shmem provider for forkserver's shared memory testcase feature. /// Shmem provider for forkserver's shared memory testcase feature.
pub fn target_bytes_converter<TC2: TargetBytesConverter>( pub fn target_bytes_converter<I, TC2: TargetBytesConverter<I>>(
self, self,
target_bytes_converter: TC2, target_bytes_converter: TC2,
) -> ForkserverExecutorBuilder<'a, TC2, SP> { ) -> ForkserverExecutorBuilder<'a, TC2, SP> {
@ -1579,13 +1577,12 @@ impl Default
} }
} }
impl<EM, TC, OT, S, SP, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z> impl<EM, I, OT, S, SP, TC, Z> Executor<EM, I, S, Z> for ForkserverExecutor<I, OT, S, SP, TC>
for ForkserverExecutor<TC, OT, S, SP>
where where
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>, OT: ObserversTuple<I, S>,
SP: ShMemProvider, SP: ShMemProvider,
S: HasCorpus + HasExecutions, S: HasExecutions,
TC: TargetBytesConverter<Input = <S::Corpus as Corpus>::Input>, TC: TargetBytesConverter<I>,
{ {
#[inline] #[inline]
fn run_target( fn run_target(
@ -1593,13 +1590,13 @@ where
_fuzzer: &mut Z, _fuzzer: &mut Z,
state: &mut S, state: &mut S,
_mgr: &mut EM, _mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
self.execute_input(state, input) self.execute_input(state, input)
} }
} }
impl<TC, OT, S, SP> HasTimeout for ForkserverExecutor<TC, OT, S, SP> impl<I, OT, S, SP, TC> HasTimeout for ForkserverExecutor<I, OT, S, SP, TC>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -1614,10 +1611,9 @@ where
} }
} }
impl<TC, OT, S, SP> HasObservers for ForkserverExecutor<TC, OT, S, SP> impl<I, OT, S, SP, TC> HasObservers for ForkserverExecutor<I, OT, S, SP, TC>
where where
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>, OT: ObserversTuple<I, S>,
S: HasCorpus,
SP: ShMemProvider, SP: ShMemProvider,
{ {
type Observers = OT; type Observers = OT;
@ -1677,7 +1673,7 @@ mod tests {
.coverage_map_size(MAP_SIZE) .coverage_map_size(MAP_SIZE)
.debug_child(false) .debug_child(false)
.shmem_provider(&mut shmem_provider) .shmem_provider(&mut shmem_provider)
.build::<_, NopCorpus<BytesInput>>(tuple_list!(edges_observer)); .build::<BytesInput, _, NopCorpus<BytesInput>>(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

@ -23,15 +23,15 @@ use windows::Win32::System::Threading::{CRITICAL_SECTION, PTP_TIMER};
use crate::executors::hooks::timer::TimerStruct; use crate::executors::hooks::timer::TimerStruct;
#[cfg(all(unix, feature = "std"))] #[cfg(all(unix, feature = "std"))]
use crate::executors::hooks::unix::unix_signal_handler; use crate::executors::hooks::unix::unix_signal_handler;
#[cfg(any(unix, windows))]
use crate::{corpus::Corpus, inputs::Input, observers::ObserversTuple, state::HasCurrentTestcase};
use crate::{ use crate::{
events::{EventFirer, EventRestarter}, events::{EventFirer, EventRestarter},
executors::{hooks::ExecutorHook, inprocess::HasInProcessHooks, Executor, HasObservers}, executors::{hooks::ExecutorHook, inprocess::HasInProcessHooks, Executor, HasObservers},
feedbacks::Feedback, feedbacks::Feedback,
state::{HasCorpus, HasExecutions, HasSolutions}, state::{HasExecutions, HasSolutions},
Error, HasObjective, Error, HasObjective,
}; };
#[cfg(any(unix, windows))]
use crate::{inputs::Input, observers::ObserversTuple, state::HasCurrentTestcase};
/// The inmem executor's handlers. /// The inmem executor's handlers.
#[expect(missing_debug_implementations)] #[expect(missing_debug_implementations)]
@ -185,10 +185,7 @@ impl<I, S> HasTimeout for InProcessHooks<I, S> {
} }
} }
impl<I, S> ExecutorHook<I, S> for InProcessHooks<I, S> impl<I, S> ExecutorHook<I, S> for InProcessHooks<I, S> {
where
S: HasCorpus,
{
fn init(&mut self, _state: &mut S) {} fn init(&mut self, _state: &mut S) {}
/// Call before running a target. /// Call before running a target.
fn pre_exec(&mut self, _state: &mut S, _input: &I) { fn pre_exec(&mut self, _state: &mut S, _input: &I) {
@ -223,10 +220,9 @@ impl<I, S> InProcessHooks<I, S> {
E::Observers: ObserversTuple<I, S>, E::Observers: ObserversTuple<I, S>,
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
I: Input + Clone, I: Input + Clone,
S::Solutions: Corpus<Input = I>,
{ {
// # Safety // # Safety
// We get a pointer to `GLOBAL_STATE` that will be initialized at this point in time. // We get a pointer to `GLOBAL_STATE` that will be initialized at this point in time.
@ -268,8 +264,7 @@ impl<I, S> InProcessHooks<I, S> {
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
I: Input + Clone, I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
{ {
let ret; let ret;
@ -330,7 +325,7 @@ impl<I, S> InProcessHooks<I, S> {
E: Executor<EM, I, S, Z> + HasObservers + HasInProcessHooks<I, S>, E: Executor<EM, I, S, Z> + HasObservers + HasInProcessHooks<I, S>,
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus, S: HasExecutions + HasSolutions<I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
{ {
#[cfg_attr(miri, allow(unused_variables))] #[cfg_attr(miri, allow(unused_variables))]

View File

@ -3,10 +3,10 @@ use alloc::vec::Vec;
use core::{ use core::{
ffi::c_void, ffi::c_void,
marker::PhantomData, marker::PhantomData,
mem::transmute,
ptr::null, ptr::null,
sync::atomic::{compiler_fence, Ordering}, sync::atomic::{compiler_fence, Ordering},
}; };
use std::intrinsics::transmute;
#[cfg(not(miri))] #[cfg(not(miri))]
use libafl_bolts::os::unix_signals::setup_signal_handler; use libafl_bolts::os::unix_signals::setup_signal_handler;
@ -21,7 +21,6 @@ use crate::{
HasObservers, HasObservers,
}, },
observers::ObserversTuple, observers::ObserversTuple,
state::HasCorpus,
Error, Error,
}; };
@ -35,10 +34,7 @@ pub struct InChildProcessHooks<I, S> {
phantom: PhantomData<(I, S)>, phantom: PhantomData<(I, S)>,
} }
impl<I, S> ExecutorHook<I, S> for InChildProcessHooks<I, S> impl<I, S> ExecutorHook<I, S> for InChildProcessHooks<I, S> {
where
S: HasCorpus,
{
/// Init this hook /// Init this hook
fn init(&mut self, _state: &mut S) {} fn init(&mut self, _state: &mut S) {}
@ -61,7 +57,6 @@ impl<I, S> InChildProcessHooks<I, S> {
where where
E: HasObservers, E: HasObservers,
E::Observers: ObserversTuple<I, S>, E::Observers: ObserversTuple<I, S>,
S: HasCorpus,
{ {
#[cfg_attr(miri, allow(unused_variables, unused_unsafe))] #[cfg_attr(miri, allow(unused_variables, unused_unsafe))]
unsafe { unsafe {

View File

@ -10,7 +10,7 @@ use num_traits::SaturatingAdd;
use serde::Serialize; use serde::Serialize;
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
use crate::{corpus::Corpus, executors::hooks::ExecutorHook, state::HasCorpus, Error}; use crate::{executors::hooks::ExecutorHook, Error};
/// Info of a binary's section that can be used during `Intel PT` traces decoding /// Info of a binary's section that can be used during `Intel PT` traces decoding
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -36,18 +36,18 @@ pub struct IntelPTHook<T> {
map_len: usize, map_len: usize,
} }
impl<S, T> ExecutorHook<<S::Corpus as Corpus>::Input, S> for IntelPTHook<T> impl<I, S, T> ExecutorHook<I, S> for IntelPTHook<T>
where where
S: Serialize + HasCorpus, S: Serialize,
T: SaturatingAdd + From<u8> + Debug, T: SaturatingAdd + From<u8> + Debug,
{ {
fn init(&mut self, _state: &mut S) {} fn init(&mut self, _state: &mut S) {}
fn pre_exec(&mut self, _state: &mut S, _input: &<S::Corpus as Corpus>::Input) { fn pre_exec(&mut self, _state: &mut S, _input: &I) {
self.intel_pt.enable_tracing().unwrap(); self.intel_pt.enable_tracing().unwrap();
} }
fn post_exec(&mut self, _state: &mut S, _input: &<S::Corpus as Corpus>::Input) { fn post_exec(&mut self, _state: &mut S, _input: &I) {
let pt = &mut self.intel_pt; let pt = &mut self.intel_pt;
pt.disable_tracing().unwrap(); pt.disable_tracing().unwrap();

View File

@ -9,7 +9,6 @@ pub mod unix_signal_handler {
use libc::siginfo_t; use libc::siginfo_t;
use crate::{ use crate::{
corpus::Corpus,
events::{EventFirer, EventRestarter}, events::{EventFirer, EventRestarter},
executors::{ executors::{
common_signals, common_signals,
@ -21,7 +20,7 @@ pub mod unix_signal_handler {
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions}, state::{HasCurrentTestcase, HasExecutions, HasSolutions},
}; };
pub(crate) type HandlerFuncPtr = unsafe fn( pub(crate) type HandlerFuncPtr = unsafe fn(
@ -83,8 +82,7 @@ pub mod unix_signal_handler {
E::Observers: ObserversTuple<I, S>, E::Observers: ObserversTuple<I, S>,
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
I: Input + Clone, I: Input + Clone,
{ {
@ -133,10 +131,9 @@ pub mod unix_signal_handler {
E::Observers: ObserversTuple<I, S>, E::Observers: ObserversTuple<I, S>,
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
I: Input + Clone, I: Input + Clone,
S::Solutions: Corpus<Input = I>,
{ {
// this stuff is for batch timeout // this stuff is for batch timeout
if !data.executor_ptr.is_null() if !data.executor_ptr.is_null()
@ -190,10 +187,9 @@ pub mod unix_signal_handler {
E::Observers: ObserversTuple<I, S>, E::Observers: ObserversTuple<I, S>,
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
I: Input + Clone, I: Input + Clone,
S::Solutions: Corpus<Input = I>,
{ {
#[cfg(all(target_os = "android", target_arch = "aarch64"))] #[cfg(all(target_os = "android", target_arch = "aarch64"))]
let _context = _context.map(|p| { let _context = _context.map(|p| {

View File

@ -9,7 +9,6 @@ pub mod windows_asan_handler {
}; };
use crate::{ use crate::{
corpus::Corpus,
events::{EventFirer, EventRestarter}, events::{EventFirer, EventRestarter},
executors::{ executors::{
hooks::inprocess::GLOBAL_STATE, inprocess::run_observers_and_save_state, Executor, hooks::inprocess::GLOBAL_STATE, inprocess::run_observers_and_save_state, Executor,
@ -19,7 +18,7 @@ pub mod windows_asan_handler {
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions}, state::{HasCurrentTestcase, HasExecutions, HasSolutions},
}; };
/// # Safety /// # Safety
@ -31,8 +30,7 @@ pub mod windows_asan_handler {
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
I: Input + Clone, I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
{ {
let data = &raw mut GLOBAL_STATE; let data = &raw mut GLOBAL_STATE;
@ -127,7 +125,6 @@ pub mod windows_exception_handler {
}; };
use crate::{ use crate::{
corpus::Corpus,
events::{EventFirer, EventRestarter}, events::{EventFirer, EventRestarter},
executors::{ executors::{
hooks::inprocess::{HasTimeout, InProcessExecutorHandlerData, GLOBAL_STATE}, hooks::inprocess::{HasTimeout, InProcessExecutorHandlerData, GLOBAL_STATE},
@ -138,7 +135,7 @@ pub mod windows_exception_handler {
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions}, state::{HasCurrentTestcase, HasExecutions, HasSolutions},
}; };
pub(crate) type HandlerFuncPtr = pub(crate) type HandlerFuncPtr =
@ -189,8 +186,7 @@ pub mod windows_exception_handler {
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
I: Input + Clone, I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
{ {
let old_hook = panic::take_hook(); let old_hook = panic::take_hook();
@ -252,9 +248,8 @@ pub mod windows_exception_handler {
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
I: Input + Clone, I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
S::Solutions: Corpus<Input = I>,
{ {
let data: &mut InProcessExecutorHandlerData = let data: &mut InProcessExecutorHandlerData =
&mut *(global_state as *mut InProcessExecutorHandlerData); &mut *(global_state as *mut InProcessExecutorHandlerData);
@ -322,9 +317,8 @@ pub mod windows_exception_handler {
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
I: Input + Clone, I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
S::Solutions: Corpus<Input = I>,
{ {
// Have we set a timer_before? // Have we set a timer_before?
if data.ptp_timer.is_some() { if data.ptp_timer.is_some() {

View File

@ -15,7 +15,6 @@ use crate::executors::hooks::inprocess::HasTimeout;
#[cfg(all(windows, feature = "std"))] #[cfg(all(windows, feature = "std"))]
use crate::executors::hooks::inprocess::HasTimeout; use crate::executors::hooks::inprocess::HasTimeout;
use crate::{ use crate::{
corpus::Corpus,
events::{EventFirer, EventRestarter}, events::{EventFirer, EventRestarter},
executors::{ executors::{
hooks::{ hooks::{
@ -29,7 +28,7 @@ use crate::{
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions}, state::{HasCurrentTestcase, HasExecutions, HasSolutions},
Error, Error,
}; };
@ -69,7 +68,6 @@ impl<HT, I, OT, S> HasObservers for GenericInProcessExecutorInner<HT, I, OT, S>
impl<HT, I, OT, S> GenericInProcessExecutorInner<HT, I, OT, S> impl<HT, I, OT, S> GenericInProcessExecutorInner<HT, I, OT, S>
where where
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus,
{ {
/// This function marks the boundary between the fuzzer and the target /// This function marks the boundary between the fuzzer and the target
/// ///
@ -132,7 +130,7 @@ impl<HT, I, OT, S> GenericInProcessExecutorInner<HT, I, OT, S>
where where
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus + HasExecutions + HasSolutions, S: HasExecutions + HasSolutions<I>,
{ {
/// Create a new in mem executor with the default timeout (5 sec) /// Create a new in mem executor with the default timeout (5 sec)
pub fn generic<E, EM, OF, Z>( pub fn generic<E, EM, OF, Z>(
@ -148,8 +146,7 @@ where
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
I: Input + Clone, I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasCurrentTestcase + HasCorpus + HasSolutions, S: HasCurrentTestcase<I> + HasSolutions<I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
{ {
Self::with_timeout_generic::<E, EM, OF, Z>( Self::with_timeout_generic::<E, EM, OF, Z>(
@ -178,8 +175,7 @@ where
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
I: Input + Clone, I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasCurrentTestcase + HasCorpus + HasSolutions, S: HasCurrentTestcase<I> + HasSolutions<I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
{ {
let mut me = Self::with_timeout_generic::<E, EM, OF, Z>( let mut me = Self::with_timeout_generic::<E, EM, OF, Z>(
@ -210,9 +206,8 @@ where
E::Observers: ObserversTuple<I, S>, E::Observers: ObserversTuple<I, S>,
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasCurrentTestcase + HasCorpus + HasSolutions, S: HasCurrentTestcase<I> + HasSolutions<I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
S::Solutions: Corpus<Input = I>,
I: Input + Clone, I: Input + Clone,
{ {
let default = InProcessHooks::new::<E, EM, OF, Z>(timeout)?; let default = InProcessHooks::new::<E, EM, OF, Z>(timeout)?;

View File

@ -77,7 +77,7 @@ where
impl<EM, H, HB, HT, I, OT, S, Z> Executor<EM, I, S, Z> impl<EM, H, HB, HT, I, OT, S, Z> Executor<EM, I, S, Z>
for GenericInProcessExecutor<H, HB, HT, I, OT, S> for GenericInProcessExecutor<H, HB, HT, I, OT, S>
where where
S: HasCorpus + HasExecutions, S: HasExecutions,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
HB: BorrowMut<H>, HB: BorrowMut<H>,
@ -124,8 +124,7 @@ impl<'a, H, I, OT, S> InProcessExecutor<'a, H, I, OT, S>
where where
H: FnMut(&I) -> ExitKind + Sized, H: FnMut(&I) -> ExitKind + Sized,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus + HasCurrentTestcase + HasExecutions + HasSolutions, S: HasCurrentTestcase<I> + HasExecutions + HasSolutions<I>,
S::Solutions: Corpus<Input = I>,
I: Input, I: Input,
{ {
/// Create a new in mem executor with the default timeout (5 sec) /// Create a new in mem executor with the default timeout (5 sec)
@ -227,8 +226,7 @@ where
HB: BorrowMut<H>, HB: BorrowMut<H>,
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus + HasCurrentTestcase + HasExecutions + HasSolutions, S: HasCurrentTestcase<I> + HasExecutions + HasSolutions<I>,
S::Solutions: Corpus<Input = I>,
I: Input, I: Input,
{ {
/// Create a new in mem executor with the default timeout (5 sec) /// Create a new in mem executor with the default timeout (5 sec)
@ -381,10 +379,9 @@ pub fn run_observers_and_save_state<E, EM, I, OF, S, Z>(
E::Observers: ObserversTuple<I, S>, E::Observers: ObserversTuple<I, S>,
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, S: HasExecutions + HasSolutions<I> + HasCorpus<I> + HasCurrentTestcase<I>,
Z: HasObjective<Objective = OF>, Z: HasObjective<Objective = OF>,
I: Input + Clone, I: Input + Clone,
S::Solutions: Corpus<Input = I>,
{ {
let mut observers = executor.observers_mut(); let mut observers = executor.observers_mut();
@ -443,9 +440,8 @@ where
E::Observers: ObserversTuple<I, S>, E::Observers: ObserversTuple<I, S>,
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
OF: Feedback<EM, I, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
I: Input + Clone, I: Input + Clone,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF> + ExecutionProcessor<EM, I, E::Observers, S>, Z: HasObjective<Objective = OF> + ExecutionProcessor<EM, I, E::Observers, S>,
{ {
let data = &raw mut GLOBAL_STATE; let data = &raw mut GLOBAL_STATE;

View File

@ -11,7 +11,6 @@ use core::{
use libafl_bolts::tuples::{tuple_list, RefIndexable}; use libafl_bolts::tuples::{tuple_list, RefIndexable};
use crate::{ use crate::{
corpus::Corpus,
events::{EventFirer, EventRestarter}, events::{EventFirer, EventRestarter},
executors::{ executors::{
hooks::{inprocess::InProcessHooks, ExecutorHooksTuple}, hooks::{inprocess::InProcessHooks, ExecutorHooksTuple},
@ -22,7 +21,7 @@ use crate::{
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions}, state::{HasCurrentTestcase, HasExecutions, HasSolutions},
Error, Error,
}; };
@ -74,7 +73,7 @@ where
HB: BorrowMut<H>, HB: BorrowMut<H>,
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus + HasExecutions, S: HasExecutions,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
@ -106,7 +105,6 @@ where
HB: BorrowMut<H>, HB: BorrowMut<H>,
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus,
{ {
type Observers = OT; type Observers = OT;
#[inline] #[inline]
@ -124,9 +122,8 @@ impl<'a, H, I, OT, S, ES> StatefulInProcessExecutor<'a, H, I, OT, S, ES>
where where
H: FnMut(&mut ES, &mut S, &I) -> ExitKind + Sized, H: FnMut(&mut ES, &mut S, &I) -> ExitKind + Sized,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
I: Clone + Input, I: Clone + Input,
S::Solutions: Corpus<Input = I>,
{ {
/// Create a new in mem executor with the default timeout (5 sec) /// Create a new in mem executor with the default timeout (5 sec)
pub fn new<EM, OF, Z>( pub fn new<EM, OF, Z>(
@ -246,8 +243,7 @@ where
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
I: Input + Clone, I: Input + Clone,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus + HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
S::Solutions: Corpus<Input = I>,
{ {
/// Create a new in mem executor with the default timeout (5 sec) /// Create a new in mem executor with the default timeout (5 sec)
pub fn generic<EM, OF, Z>( pub fn generic<EM, OF, Z>(

View File

@ -28,7 +28,6 @@ use crate::{
ExitKind, HasObservers, ExitKind, HasObservers,
}, },
observers::ObserversTuple, observers::ObserversTuple,
state::HasCorpus,
Error, Error,
}; };
@ -108,7 +107,6 @@ fn parse_itimerval(timeout: Duration) -> Itimerval {
impl<EM, HT, I, OT, S, SP, Z> GenericInProcessForkExecutorInner<HT, I, OT, S, SP, EM, Z> impl<EM, HT, I, OT, S, SP, Z> GenericInProcessForkExecutorInner<HT, I, OT, S, SP, EM, Z>
where where
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
S: HasCorpus,
SP: ShMemProvider, SP: ShMemProvider,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
{ {
@ -201,7 +199,6 @@ impl<HT, I, OT, S, SP, EM, Z> GenericInProcessForkExecutorInner<HT, I, OT, S, SP
where where
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus,
{ {
#[inline] #[inline]
/// This function marks the boundary between the fuzzer and the target. /// This function marks the boundary between the fuzzer and the target.

View File

@ -19,7 +19,7 @@ use crate::{
inprocess_fork::inner::GenericInProcessForkExecutorInner, Executor, ExitKind, HasObservers, inprocess_fork::inner::GenericInProcessForkExecutorInner, Executor, ExitKind, HasObservers,
}, },
observers::ObserversTuple, observers::ObserversTuple,
state::{HasCorpus, HasExecutions}, state::HasExecutions,
Error, Error,
}; };
@ -45,7 +45,6 @@ pub type InProcessForkExecutor<'a, H, I, OT, S, SP, EM, Z> =
impl<'a, H, I, OT, S, SP, EM, Z> InProcessForkExecutor<'a, H, I, OT, S, SP, EM, Z> impl<'a, H, I, OT, S, SP, EM, Z> InProcessForkExecutor<'a, H, I, OT, S, SP, EM, Z>
where where
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus,
{ {
/// The constructor for `InProcessForkExecutor` /// The constructor for `InProcessForkExecutor`
pub fn new( pub fn new(
@ -107,7 +106,7 @@ impl<EM, H, HT, I, OT, S, SP, Z> Executor<EM, I, S, Z>
for GenericInProcessForkExecutor<'_, H, HT, I, OT, S, SP, EM, Z> for GenericInProcessForkExecutor<'_, H, HT, I, OT, S, SP, EM, Z>
where where
H: FnMut(&I) -> ExitKind + Sized, H: FnMut(&I) -> ExitKind + Sized,
S: HasCorpus + HasExecutions, S: HasExecutions,
SP: ShMemProvider, SP: ShMemProvider,
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
@ -146,7 +145,6 @@ impl<'a, H, HT, I, OT, S, SP, EM, Z> GenericInProcessForkExecutor<'a, H, HT, I,
where where
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus,
{ {
/// Creates a new [`GenericInProcessForkExecutor`] with custom hooks /// Creates a new [`GenericInProcessForkExecutor`] with custom hooks
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]

View File

@ -20,7 +20,7 @@ use crate::{
ExitKind, HasObservers, ExitKind, HasObservers,
}, },
observers::ObserversTuple, observers::ObserversTuple,
state::{HasCorpus, HasExecutions}, state::HasExecutions,
Error, Error,
}; };
@ -31,7 +31,6 @@ pub type StatefulInProcessForkExecutor<'a, H, I, OT, S, SP, ES, EM, Z> =
impl<'a, H, I, OT, S, SP, ES, EM, Z> StatefulInProcessForkExecutor<'a, H, I, OT, S, SP, ES, EM, Z> impl<'a, H, I, OT, S, SP, ES, EM, Z> StatefulInProcessForkExecutor<'a, H, I, OT, S, SP, ES, EM, Z>
where where
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus,
{ {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
/// The constructor for `InProcessForkExecutor` /// The constructor for `InProcessForkExecutor`
@ -99,7 +98,7 @@ impl<EM, H, HT, I, OT, S, SP, Z, ES> Executor<EM, I, S, Z>
where where
H: FnMut(&mut ES, &I) -> ExitKind + Sized, H: FnMut(&mut ES, &I) -> ExitKind + Sized,
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
S: HasCorpus + HasExecutions, S: HasExecutions,
SP: ShMemProvider, SP: ShMemProvider,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
{ {
@ -138,7 +137,6 @@ impl<'a, H, HT, I, OT, S, SP, ES, EM, Z>
where where
HT: ExecutorHooksTuple<I, S>, HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>, OT: ObserversTuple<I, S>,
S: HasCorpus,
{ {
/// Creates a new [`StatefulGenericInProcessForkExecutor`] with custom hooks /// Creates a new [`StatefulGenericInProcessForkExecutor`] with custom hooks
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]

View File

@ -10,23 +10,21 @@ use libafl_bolts::tuples::RefIndexable;
use super::HasTimeout; use super::HasTimeout;
use crate::{ use crate::{
corpus::Corpus,
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
observers::ObserversTuple, observers::ObserversTuple,
state::HasCorpus,
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, S, SOT> { pub struct ShadowExecutor<E, I, S, SOT> {
/// The wrapped executor /// The wrapped executor
executor: E, executor: E,
/// The shadow observers /// The shadow observers
shadow_observers: SOT, shadow_observers: SOT,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<E, S, SOT> Debug for ShadowExecutor<E, S, SOT> impl<E, I, S, SOT> Debug for ShadowExecutor<E, I, S, SOT>
where where
E: Debug, E: Debug,
SOT: Debug, SOT: Debug,
@ -39,11 +37,10 @@ where
} }
} }
impl<E, S, SOT> ShadowExecutor<E, S, SOT> impl<E, I, S, SOT> ShadowExecutor<E, I, S, SOT>
where where
E: HasObservers, E: HasObservers,
S: HasCorpus, SOT: ObserversTuple<I, S>,
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
{ {
/// 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 {
@ -67,25 +64,23 @@ where
} }
} }
impl<E, EM, S, SOT, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z> impl<E, EM, I, S, SOT, Z> Executor<EM, I, S, Z> for ShadowExecutor<E, I, S, SOT>
for ShadowExecutor<E, S, SOT>
where where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, E: Executor<EM, I, S, Z> + HasObservers,
S: HasCorpus, SOT: ObserversTuple<I, S>,
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut S,
mgr: &mut EM, mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
self.executor.run_target(fuzzer, state, mgr, input) self.executor.run_target(fuzzer, state, mgr, input)
} }
} }
impl<E, S, SOT> HasTimeout for ShadowExecutor<E, S, SOT> impl<E, I, S, SOT> HasTimeout for ShadowExecutor<E, I, S, SOT>
where where
E: HasTimeout, E: HasTimeout,
{ {
@ -99,11 +94,10 @@ where
} }
} }
impl<E, S, SOT> HasObservers for ShadowExecutor<E, S, SOT> impl<E, I, S, SOT> HasObservers for ShadowExecutor<E, I, S, SOT>
where where
E: HasObservers, E: HasObservers,
S: HasCorpus, SOT: ObserversTuple<I, S>,
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
{ {
type Observers = E::Observers; type Observers = E::Observers;
#[inline] #[inline]

View File

@ -5,41 +5,37 @@ use core::{fmt::Debug, marker::PhantomData};
use libafl_bolts::tuples::RefIndexable; use libafl_bolts::tuples::RefIndexable;
use crate::{ use crate::{
corpus::Corpus,
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
observers::ObserversTuple, observers::ObserversTuple,
state::HasCorpus,
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, OT, S> { pub struct WithObservers<E, I, OT, S> {
executor: E, executor: E,
observers: OT, observers: OT,
phantom: PhantomData<S>, phantom: PhantomData<(I, S)>,
} }
impl<E, EM, OT, S, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z> for WithObservers<E, OT, S> impl<E, EM, I, OT, S, Z> Executor<EM, I, S, Z> for WithObservers<E, I, OT, S>
where where
S: HasCorpus, E: Executor<EM, I, S, Z>,
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
state: &mut S, state: &mut S,
mgr: &mut EM, mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
self.executor.run_target(fuzzer, state, mgr, input) self.executor.run_target(fuzzer, state, mgr, input)
} }
} }
impl<E, OT, S> HasObservers for WithObservers<E, OT, S> impl<E, I, OT, S> HasObservers for WithObservers<E, I, OT, S>
where where
S: HasCorpus, OT: ObserversTuple<I, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
{ {
type Observers = OT; type Observers = OT;
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
@ -51,7 +47,7 @@ where
} }
} }
impl<E, OT, S> WithObservers<E, OT, S> { impl<E, I, OT, S> WithObservers<E, I, OT, S> {
/// Wraps the given [`Executor`] with the given [`ObserversTuple`] to implement [`HasObservers`]. /// Wraps the given [`Executor`] with the given [`ObserversTuple`] to implement [`HasObservers`].
/// ///
/// If the executor already implements [`HasObservers`], then the original implementation will be overshadowed by /// If the executor already implements [`HasObservers`], then the original implementation will be overshadowed by

View File

@ -38,7 +38,7 @@ impl<S> StateInitializer<S> for CaptureTimeoutFeedback {}
impl<EM, I, OT, S> Feedback<EM, I, OT, S> for CaptureTimeoutFeedback impl<EM, I, OT, S> Feedback<EM, I, OT, S> for CaptureTimeoutFeedback
where where
S: HasCorpus + HasMetadata, S: HasCorpus<I> + HasMetadata,
I: Debug + Serialize + DeserializeOwned + Default + 'static + Clone, I: Debug + Serialize + DeserializeOwned + Default + 'static + Clone,
{ {
#[inline] #[inline]

View File

@ -21,13 +21,12 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize};
#[cfg(feature = "track_hit_feedbacks")] #[cfg(feature = "track_hit_feedbacks")]
use crate::feedbacks::premature_last_result_err; use crate::feedbacks::premature_last_result_err;
use crate::{ use crate::{
corpus::{Corpus, Testcase}, corpus::Testcase,
events::{Event, EventFirer}, events::{Event, EventFirer},
executors::ExitKind, executors::ExitKind,
feedbacks::{Feedback, HasObserverHandle, StateInitializer}, feedbacks::{Feedback, HasObserverHandle, StateInitializer},
monitors::{AggregatorOps, UserStats, UserStatsValue}, monitors::{AggregatorOps, UserStats, UserStatsValue},
observers::{CanTrack, MapObserver}, observers::{CanTrack, MapObserver},
state::HasCorpus,
Error, HasMetadata, HasNamedMetadata, Error, HasMetadata, HasNamedMetadata,
}; };
@ -395,13 +394,13 @@ where
impl<C, EM, I, N, O, OT, R, S> Feedback<EM, I, OT, S> for MapFeedback<C, N, O, R> impl<C, EM, I, N, O, OT, R, S> Feedback<EM, I, OT, S> for MapFeedback<C, N, O, R>
where where
C: CanTrack + AsRef<O>, C: CanTrack + AsRef<O>,
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
N: IsNovel<O::Entry>, N: IsNovel<O::Entry>,
O: MapObserver + for<'it> AsIter<'it, Item = O::Entry>, O: MapObserver + for<'it> AsIter<'it, Item = O::Entry>,
O::Entry: 'static + Default + Debug + DeserializeOwned + Serialize, O::Entry: 'static + Default + Debug + DeserializeOwned + Serialize,
OT: MatchName, OT: MatchName,
R: Reducer<O::Entry>, R: Reducer<O::Entry>,
S: HasNamedMetadata + HasCorpus, // delete me S: HasNamedMetadata,
{ {
#[rustversion::nightly] #[rustversion::nightly]
default fn is_interesting( default fn is_interesting(
@ -538,10 +537,10 @@ where
impl<C, O, EM, I, OT, S> Feedback<EM, I, OT, S> for MapFeedback<C, DifferentIsNovel, O, MaxReducer> impl<C, O, EM, I, OT, S> Feedback<EM, I, OT, S> for MapFeedback<C, DifferentIsNovel, O, MaxReducer>
where where
C: CanTrack + AsRef<O>, C: CanTrack + AsRef<O>,
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
O: MapObserver<Entry = u8> + for<'a> AsSlice<'a, Entry = u8> + for<'a> AsIter<'a, Item = u8>, O: MapObserver<Entry = u8> + for<'a> AsSlice<'a, Entry = u8> + for<'a> AsIter<'a, Item = u8>,
OT: MatchName, OT: MatchName,
S: HasNamedMetadata + HasCorpus, S: HasNamedMetadata,
{ {
fn is_interesting( fn is_interesting(
&mut self, &mut self,

View File

@ -67,8 +67,7 @@ impl<'a> NautilusFeedback<'a> {
testcase: &mut Testcase<NautilusInput>, testcase: &mut Testcase<NautilusInput>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
S: HasCorpus + HasMetadata, S: HasCorpus<NautilusInput> + HasMetadata,
S::Corpus: Corpus<Input = NautilusInput>,
{ {
state.corpus().load_input_into(testcase)?; state.corpus().load_input_into(testcase)?;
let input = testcase.input().as_ref().unwrap().clone(); let input = testcase.input().as_ref().unwrap().clone();
@ -93,8 +92,7 @@ impl<S> StateInitializer<S> for NautilusFeedback<'_> {}
impl<EM, OT, S> Feedback<EM, NautilusInput, OT, S> for NautilusFeedback<'_> impl<EM, OT, S> Feedback<EM, NautilusInput, OT, S> for NautilusFeedback<'_>
where where
S: HasMetadata + HasCorpus, S: HasMetadata + HasCorpus<NautilusInput>,
S::Corpus: Corpus<Input = NautilusInput>,
{ {
fn is_interesting( fn is_interesting(
&mut self, &mut self,

View File

@ -129,9 +129,9 @@ pub trait ExecutionProcessor<EM, I, OT, S> {
/// Evaluates an input modifying the state of the fuzzer /// Evaluates an input modifying the state of the fuzzer
pub trait EvaluatorObservers<E, EM, I, S> { pub trait EvaluatorObservers<E, EM, 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 /// if it is interesting, returns an (option) the index of the new
/// [`crate::corpus::Testcase`] in the [`crate::corpus::Corpus`] /// [`Testcase`] in the [`Corpus`]
fn evaluate_input_with_observers( fn evaluate_input_with_observers(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -145,7 +145,7 @@ pub trait EvaluatorObservers<E, EM, I, S> {
/// 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, I, S> {
/// Runs the input if it was (likely) not previously run and triggers observers and feedback and adds the input to the previously executed list /// Runs the input if it was (likely) not previously run and triggers observers and feedback and adds the input to the previously executed list
/// returns if is interesting an (option) the index of the new [`crate::corpus::Testcase`] in the corpus /// if it is interesting, returns an (option) the index of the new [`Testcase`] in the corpus
fn evaluate_filtered( fn evaluate_filtered(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -155,7 +155,7 @@ pub trait Evaluator<E, EM, I, S> {
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>; ) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>;
/// 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 [`crate::corpus::Testcase`] in the corpus /// returns if is interesting an (option) the index of the new [`Testcase`] in the corpus
fn evaluate_input( fn evaluate_input(
&mut self, &mut self,
state: &mut S, state: &mut S,
@ -190,7 +190,7 @@ pub trait Evaluator<E, EM, I, S> {
input: I, input: I,
) -> Result<CorpusId, Error>; ) -> Result<CorpusId, Error>;
/// Adds the input to the corpus as disabled a input. /// Adds the input to the corpus as a disabled input.
/// Used during initial corpus loading. /// Used during initial corpus loading.
/// Disabled testcases are only used for splicing /// Disabled testcases are only used for splicing
/// Returns the `index` of the new testcase in the corpus. /// Returns the `index` of the new testcase in the corpus.
@ -199,11 +199,11 @@ pub trait Evaluator<E, EM, I, S> {
} }
/// The main fuzzer trait. /// The main fuzzer trait.
pub trait Fuzzer<E, EM, S, ST> { pub trait Fuzzer<E, EM, I, S, ST> {
/// 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.
/// (Note: An iteration represents a complete run of every stage. /// (Note: An iteration represents a complete run of every stage.
/// Therefore it does not mean that the harness is executed for once, /// Therefore, it does not mean that the harness is executed for once,
/// because each stage could run the harness for multiple times) /// because each stage could run the harness for multiple times)
/// ///
/// If you use this fn in a restarting scenario to only run for `n` iterations, /// If you use this fn in a restarting scenario to only run for `n` iterations,
@ -265,10 +265,9 @@ pub struct StdFuzzer<CS, F, IF, OF> {
input_filter: IF, input_filter: IF,
} }
impl<CS, F, IF, OF, S> HasScheduler<<S::Corpus as Corpus>::Input, S> for StdFuzzer<CS, F, IF, OF> impl<CS, F, I, IF, OF, S> HasScheduler<I, S> for StdFuzzer<CS, F, IF, OF>
where where
S: HasCorpus, CS: Scheduler<I, S>,
CS: Scheduler<<S::Corpus as Corpus>::Input, S>,
{ {
type Scheduler = CS; type Scheduler = CS;
@ -305,23 +304,25 @@ impl<CS, F, IF, OF> HasObjective for StdFuzzer<CS, F, IF, OF> {
} }
} }
impl<CS, EM, F, IF, OF, OT, S> ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, OT, S> impl<CS, EM, F, I, IF, OF, OT, S> ExecutionProcessor<EM, I, OT, S> for StdFuzzer<CS, F, IF, OF>
for StdFuzzer<CS, F, IF, OF>
where where
CS: Scheduler<<S::Corpus as Corpus>::Input, S>, CS: Scheduler<I, S>,
EM: EventFirer<<S::Corpus as Corpus>::Input, S> + CanSerializeObserver<OT>, EM: EventFirer<I, S> + CanSerializeObserver<OT>,
S: HasCorpus + MaybeHasClientPerfMonitor + HasCurrentTestcase + HasSolutions + HasLastFoundTime, F: Feedback<EM, I, OT, S>,
F: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>, I: Input,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>, OF: Feedback<EM, I, OT, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize, OT: ObserversTuple<I, S> + Serialize,
<S::Corpus as Corpus>::Input: Input, S: HasCorpus<I>
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>, + MaybeHasClientPerfMonitor
+ HasCurrentTestcase<I>
+ HasSolutions<I>
+ HasLastFoundTime,
{ {
fn check_results( fn check_results(
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<ExecuteInputResult, Error> { ) -> Result<ExecuteInputResult, Error> {
@ -357,107 +358,12 @@ where
Ok(res) Ok(res)
} }
fn evaluate_execution(
&mut self,
state: &mut S,
manager: &mut EM,
input: <S::Corpus as Corpus>::Input,
observers: &OT,
exit_kind: &ExitKind,
send_events: bool,
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
let exec_res = self.check_results(state, manager, &input, observers, exit_kind)?;
let corpus_id = self.process_execution(state, manager, &input, &exec_res, observers)?;
if send_events {
self.serialize_and_dispatch(state, manager, input, &exec_res, observers, exit_kind)?;
}
if exec_res != ExecuteInputResult::None {
*state.last_found_time_mut() = current_time();
}
Ok((exec_res, corpus_id))
}
fn serialize_and_dispatch(
&mut self,
state: &mut S,
manager: &mut EM,
input: <S::Corpus as Corpus>::Input,
exec_res: &ExecuteInputResult,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<(), Error> {
// Now send off the event
let observers_buf = match exec_res {
ExecuteInputResult::Corpus => {
if manager.should_send() {
// TODO set None for fast targets
if manager.configuration() == EventConfig::AlwaysUnique {
None
} else {
manager.serialize_observers(observers)?
}
} else {
None
}
}
_ => None,
};
self.dispatch_event(state, manager, input, exec_res, observers_buf, exit_kind)?;
Ok(())
}
fn dispatch_event(
&mut self,
state: &mut S,
manager: &mut EM,
input: <S::Corpus as Corpus>::Input,
exec_res: &ExecuteInputResult,
observers_buf: Option<Vec<u8>>,
exit_kind: &ExitKind,
) -> Result<(), Error> {
// Now send off the event
match exec_res {
ExecuteInputResult::Corpus => {
if manager.should_send() {
manager.fire(
state,
Event::NewTestcase {
input,
observers_buf,
exit_kind: *exit_kind,
corpus_size: state.corpus().count(),
client_config: manager.configuration(),
time: current_time(),
forward_id: None,
#[cfg(all(unix, feature = "std", feature = "multi_machine"))]
node_id: None,
},
)?;
}
}
ExecuteInputResult::Solution => {
if manager.should_send() {
manager.fire(
state,
Event::Objective {
objective_size: state.solutions().count(),
time: current_time(),
},
)?;
}
}
ExecuteInputResult::None => (),
}
Ok(())
}
/// 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( fn process_execution(
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
exec_res: &ExecuteInputResult, exec_res: &ExecuteInputResult,
observers: &OT, observers: &OT,
) -> Result<Option<CorpusId>, Error> { ) -> Result<Option<CorpusId>, Error> {
@ -504,25 +410,118 @@ where
} }
} }
} }
fn serialize_and_dispatch(
&mut self,
state: &mut S,
manager: &mut EM,
input: I,
exec_res: &ExecuteInputResult,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<(), Error> {
// Now send off the event
let observers_buf = match exec_res {
ExecuteInputResult::Corpus => {
if manager.should_send() {
// TODO set None for fast targets
if manager.configuration() == EventConfig::AlwaysUnique {
None
} else {
manager.serialize_observers(observers)?
}
} else {
None
}
}
_ => None,
};
self.dispatch_event(state, manager, input, exec_res, observers_buf, exit_kind)?;
Ok(())
} }
impl<CS, E, EM, F, IF, OF, S> EvaluatorObservers<E, EM, <S::Corpus as Corpus>::Input, S> fn dispatch_event(
for StdFuzzer<CS, F, IF, OF> &mut self,
state: &mut S,
manager: &mut EM,
input: I,
exec_res: &ExecuteInputResult,
observers_buf: Option<Vec<u8>>,
exit_kind: &ExitKind,
) -> Result<(), Error> {
// Now send off the event
match exec_res {
ExecuteInputResult::Corpus => {
if manager.should_send() {
manager.fire(
state,
Event::NewTestcase {
input,
observers_buf,
exit_kind: *exit_kind,
corpus_size: state.corpus().count(),
client_config: manager.configuration(),
time: current_time(),
forward_id: None,
#[cfg(all(unix, feature = "std", feature = "multi_machine"))]
node_id: None,
},
)?;
}
}
ExecuteInputResult::Solution => {
if manager.should_send() {
manager.fire(
state,
Event::Objective {
objective_size: state.solutions().count(),
time: current_time(),
},
)?;
}
}
ExecuteInputResult::None => (),
}
Ok(())
}
fn evaluate_execution(
&mut self,
state: &mut S,
manager: &mut EM,
input: I,
observers: &OT,
exit_kind: &ExitKind,
send_events: bool,
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
let exec_res = self.check_results(state, manager, &input, observers, exit_kind)?;
let corpus_id = self.process_execution(state, manager, &input, &exec_res, observers)?;
if send_events {
self.serialize_and_dispatch(state, manager, input, &exec_res, observers, exit_kind)?;
}
if exec_res != ExecuteInputResult::None {
*state.last_found_time_mut() = current_time();
}
Ok((exec_res, corpus_id))
}
}
impl<CS, E, EM, F, I, IF, OF, S> EvaluatorObservers<E, EM, I, S> for StdFuzzer<CS, F, IF, OF>
where where
CS: Scheduler<<S::Corpus as Corpus>::Input, S>, CS: Scheduler<I, S>,
E: HasObservers + Executor<EM, <S::Corpus as Corpus>::Input, S, Self>, E: HasObservers + Executor<EM, I, S, Self>,
E::Observers: MatchName + ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize, E::Observers: MatchName + ObserversTuple<I, S> + Serialize,
EM: EventFirer<<S::Corpus as Corpus>::Input, S> + CanSerializeObserver<E::Observers>, EM: EventFirer<I, S> + CanSerializeObserver<E::Observers>,
F: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>, F: Feedback<EM, I, E::Observers, S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasCorpus S: HasCorpus<I>
+ HasSolutions + HasSolutions<I>
+ MaybeHasClientPerfMonitor + MaybeHasClientPerfMonitor
+ HasCurrentTestcase + HasCurrentTestcase<I>
+ HasExecutions + HasExecutions
+ HasLastFoundTime, + HasLastFoundTime,
<S::Corpus as Corpus>::Input: Input, I: Input,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
{ {
/// Process one input, adding to the respective corpora if needed and firing the right events /// Process one input, adding to the respective corpora if needed and firing the right events
#[inline] #[inline]
@ -531,7 +530,7 @@ where
state: &mut S, state: &mut S,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: <S::Corpus as Corpus>::Input, input: I,
send_events: bool, send_events: bool,
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> { ) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
let exit_kind = self.execute_input(state, executor, manager, &input)?; let exit_kind = self.execute_input(state, executor, manager, &input)?;
@ -583,31 +582,29 @@ impl<I: Hash> InputFilter<I> for BloomInputFilter {
} }
} }
impl<CS, E, EM, F, IF, OF, S> Evaluator<E, EM, <S::Corpus as Corpus>::Input, S> impl<CS, E, EM, F, I, IF, OF, S> Evaluator<E, EM, I, S> for StdFuzzer<CS, F, IF, OF>
for StdFuzzer<CS, F, IF, OF>
where where
CS: Scheduler<<S::Corpus as Corpus>::Input, S>, CS: Scheduler<I, S>,
E: HasObservers + Executor<EM, <S::Corpus as Corpus>::Input, S, Self>, E: HasObservers + Executor<EM, I, S, Self>,
E::Observers: MatchName + ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize, E::Observers: MatchName + ObserversTuple<I, S> + Serialize,
EM: EventFirer<<S::Corpus as Corpus>::Input, S> + CanSerializeObserver<E::Observers>, EM: EventFirer<I, S> + CanSerializeObserver<E::Observers>,
F: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>, F: Feedback<EM, I, E::Observers, S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>, OF: Feedback<EM, I, E::Observers, S>,
S: HasCorpus S: HasCorpus<I>
+ HasSolutions + HasSolutions<I>
+ MaybeHasClientPerfMonitor + MaybeHasClientPerfMonitor
+ HasCurrentTestcase + HasCurrentTestcase<I>
+ HasLastFoundTime + HasLastFoundTime
+ HasExecutions, + HasExecutions,
<S::Corpus as Corpus>::Input: Input, I: Input,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>, IF: InputFilter<I>,
IF: InputFilter<<S::Corpus as Corpus>::Input>,
{ {
fn evaluate_filtered( fn evaluate_filtered(
&mut self, &mut self,
state: &mut S, state: &mut S,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: <S::Corpus as Corpus>::Input, input: I,
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> { ) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
if self.input_filter.should_execute(&input) { if self.input_filter.should_execute(&input) {
self.evaluate_input(state, executor, manager, input) self.evaluate_input(state, executor, manager, input)
@ -623,31 +620,19 @@ where
state: &mut S, state: &mut S,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: <S::Corpus as Corpus>::Input, input: I,
send_events: bool, send_events: bool,
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> { ) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
self.evaluate_input_with_observers(state, executor, manager, input, send_events) self.evaluate_input_with_observers(state, executor, manager, input, send_events)
} }
fn add_disabled_input(
&mut self,
state: &mut S,
input: <S::Corpus as Corpus>::Input,
) -> Result<CorpusId, Error> {
let mut testcase = Testcase::from(input.clone());
testcase.set_disabled(true);
// Add the disabled input to the main corpus
let id = state.corpus_mut().add_disabled(testcase)?;
Ok(id)
}
/// Adds an input, even if it's not considered `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 S,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: <S::Corpus as Corpus>::Input, input: I,
) -> Result<CorpusId, Error> { ) -> Result<CorpusId, Error> {
*state.last_found_time_mut() = current_time(); *state.last_found_time_mut() = current_time();
@ -738,17 +723,25 @@ where
)?; )?;
Ok(id) Ok(id)
} }
fn add_disabled_input(&mut self, state: &mut S, input: I) -> Result<CorpusId, Error> {
let mut testcase = Testcase::from(input.clone());
testcase.set_disabled(true);
// Add the disabled input to the main corpus
let id = state.corpus_mut().add_disabled(testcase)?;
Ok(id)
}
} }
impl<CS, E, EM, F, IF, OF, S, ST> Fuzzer<E, EM, S, ST> for StdFuzzer<CS, F, IF, OF> impl<CS, E, EM, F, I, IF, OF, S, ST> Fuzzer<E, EM, I, S, ST> for StdFuzzer<CS, F, IF, OF>
where where
CS: Scheduler<<S::Corpus as Corpus>::Input, S>, CS: Scheduler<I, S>,
EM: ProgressReporter<S> + EventProcessor<E, S, Self>, EM: ProgressReporter<S> + EventProcessor<E, S, Self>,
S: HasExecutions S: HasExecutions
+ HasMetadata + HasMetadata
+ HasCorpus + HasCorpus<I>
+ HasLastReportTime + HasLastReportTime
+ HasTestcase + HasTestcase<I>
+ HasCurrentCorpusId + HasCurrentCorpusId
+ HasCurrentStageId + HasCurrentStageId
+ Stoppable + Stoppable
@ -855,7 +848,7 @@ where
manager.report_progress(state)?; manager.report_progress(state)?;
// If we would assume the fuzzer loop will always exit after this, we could do this here: // If we assumed the fuzzer loop will always exit after this, we could do this here:
// manager.on_restart(state)?; // manager.on_restart(state)?;
// But as the state may grow to a few megabytes, // But as the state may grow to a few megabytes,
// for now we won't, and the user has to do it (unless we find a way to do this on `Drop`). // for now we won't, and the user has to do it (unless we find a way to do this on `Drop`).
@ -914,13 +907,12 @@ pub trait ExecutesInput<E, EM, I, S> {
) -> Result<ExitKind, Error>; ) -> Result<ExitKind, Error>;
} }
impl<CS, E, EM, F, IF, OF, S> ExecutesInput<E, EM, <S::Corpus as Corpus>::Input, S> impl<CS, E, EM, F, I, IF, OF, S> ExecutesInput<E, EM, I, S> for StdFuzzer<CS, F, IF, OF>
for StdFuzzer<CS, F, IF, OF>
where where
CS: Scheduler<<S::Corpus as Corpus>::Input, S>, CS: Scheduler<I, S>,
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Self> + HasObservers, E: Executor<EM, I, S, Self> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>, E::Observers: ObserversTuple<I, S>,
S: HasExecutions + HasCorpus + MaybeHasClientPerfMonitor, S: HasExecutions + HasCorpus<I> + MaybeHasClientPerfMonitor,
{ {
/// Runs the input and triggers observers and feedback /// Runs the input and triggers observers and feedback
fn execute_input( fn execute_input(
@ -928,7 +920,7 @@ where
state: &mut S, state: &mut S,
executor: &mut E, executor: &mut E,
event_mgr: &mut EM, event_mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
start_timer!(state); start_timer!(state);
executor.observers_mut().pre_exec_all(state, input)?; executor.observers_mut().pre_exec_all(state, input)?;
@ -966,7 +958,7 @@ impl Default for NopFuzzer {
} }
} }
impl<E, EM, S, ST> Fuzzer<E, EM, S, ST> for NopFuzzer impl<E, EM, I, S, ST> Fuzzer<E, EM, I, S, ST> for NopFuzzer
where where
EM: ProgressReporter<S> + EventProcessor<E, S, Self>, EM: ProgressReporter<S> + EventProcessor<E, S, Self>,
ST: StagesTuple<E, EM, S, Self>, ST: StagesTuple<E, EM, S, Self>,

View File

@ -9,7 +9,6 @@ use crate::{
corpus::Testcase, corpus::Testcase,
inputs::BytesInput, inputs::BytesInput,
stages::mutational::{MutatedTransform, MutatedTransformPost}, stages::mutational::{MutatedTransform, MutatedTransformPost},
state::HasCorpus,
Error, HasMetadata, Error, HasMetadata,
}; };
@ -105,10 +104,7 @@ impl GeneralizedInputMetadata {
} }
} }
impl<S> MutatedTransform<BytesInput, S> for GeneralizedInputMetadata impl<S> MutatedTransform<BytesInput, S> for GeneralizedInputMetadata {
where
S: HasCorpus,
{
type Post = Self; type Post = Self;
fn try_transform_from(base: &mut Testcase<BytesInput>, _state: &S) -> Result<Self, Error> { fn try_transform_from(base: &mut Testcase<BytesInput>, _state: &S) -> Result<Self, Error> {
@ -130,4 +126,4 @@ where
} }
} }
impl<S> MutatedTransformPost<S> for GeneralizedInputMetadata where S: HasCorpus {} impl<S> MutatedTransformPost<S> for GeneralizedInputMetadata {}

View File

@ -356,12 +356,9 @@ where
} }
/// A converter that converts from `input` to target bytes /// A converter that converts from `input` to target bytes
pub trait TargetBytesConverter { pub trait TargetBytesConverter<I> {
/// The input
type Input;
/// Create target bytes /// Create target bytes
fn to_target_bytes<'a>(&mut self, input: &'a Self::Input) -> OwnedSlice<'a, u8>; fn to_target_bytes<'a>(&mut self, input: &'a I) -> OwnedSlice<'a, u8>;
} }
/// Simply gets the target bytes out from a [`HasTargetBytes`] type. /// Simply gets the target bytes out from a [`HasTargetBytes`] type.
@ -386,10 +383,11 @@ impl<I> Default for NopTargetBytesConverter<I> {
} }
} }
impl<I: HasTargetBytes> TargetBytesConverter for NopTargetBytesConverter<I> { impl<I> TargetBytesConverter<I> for NopTargetBytesConverter<I>
type Input = I; where
I: HasTargetBytes,
fn to_target_bytes<'a>(&mut self, input: &'a Self::Input) -> OwnedSlice<'a, u8> { {
fn to_target_bytes<'a>(&mut self, input: &'a I) -> OwnedSlice<'a, u8> {
input.target_bytes() input.target_bytes()
} }
} }

View File

@ -154,10 +154,8 @@ impl<'a> NautilusTargetBytesConverter<'a> {
} }
} }
impl TargetBytesConverter for NautilusTargetBytesConverter<'_> { impl TargetBytesConverter<NautilusInput> for NautilusTargetBytesConverter<'_> {
type Input = NautilusInput; fn to_target_bytes<'a>(&mut self, input: &'a NautilusInput) -> OwnedSlice<'a, u8> {
fn to_target_bytes<'a>(&mut self, input: &'a Self::Input) -> OwnedSlice<'a, u8> {
let mut bytes = Vec::new(); let mut bytes = Vec::new();
input.unparse(self.ctx, &mut bytes); input.unparse(self.ctx, &mut bytes);
OwnedSlice::from(bytes) OwnedSlice::from(bytes)

View File

@ -190,14 +190,14 @@ 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>,
_,
StdRand, StdRand,
InMemoryCorpus<BytesInput>, InMemoryCorpus<BytesInput>,
> = postcard::from_bytes::< > = postcard::from_bytes::<
StdState< StdState<
BytesInput,
InMemoryCorpus<BytesInput>, InMemoryCorpus<BytesInput>,
BytesInput,
RomuDuoJrRand, RomuDuoJrRand,
InMemoryCorpus<BytesInput>, InMemoryCorpus<BytesInput>,
>, >,

View File

@ -313,8 +313,7 @@ pub struct EncodedCrossoverInsertMutator;
impl<S> Mutator<EncodedInput, S> for EncodedCrossoverInsertMutator impl<S> Mutator<EncodedInput, S> for EncodedCrossoverInsertMutator
where where
S: HasRand + HasCorpus + HasMaxSize, S: HasRand + HasCorpus<EncodedInput> + HasMaxSize,
S::Corpus: Corpus<Input = EncodedInput>,
{ {
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
let size = input.codes().len(); let size = input.codes().len();
@ -397,8 +396,7 @@ pub struct EncodedCrossoverReplaceMutator;
impl<S> Mutator<EncodedInput, S> for EncodedCrossoverReplaceMutator impl<S> Mutator<EncodedInput, S> for EncodedCrossoverReplaceMutator
where where
S: HasRand + HasCorpus, S: HasRand + HasCorpus<EncodedInput>,
S::Corpus: Corpus<Input = EncodedInput>,
{ {
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
let size = input.codes().len(); let size = input.codes().len();

View File

@ -111,8 +111,7 @@ pub struct GramatronSpliceMutator;
impl<S> Mutator<GramatronInput, S> for GramatronSpliceMutator impl<S> Mutator<GramatronInput, S> for GramatronSpliceMutator
where where
S: HasRand + HasCorpus + HasMetadata, S: HasRand + HasCorpus<GramatronInput> + HasMetadata,
S::Corpus: Corpus<Input = GramatronInput>,
{ {
fn mutate( fn mutate(
&mut self, &mut self,

View File

@ -4,6 +4,7 @@
use alloc::{borrow::Cow, vec::Vec}; use alloc::{borrow::Cow, vec::Vec};
use core::{ use core::{
cmp::{max, min}, cmp::{max, min},
marker::PhantomData,
num::NonZero, num::NonZero,
}; };
@ -25,13 +26,13 @@ const RECURSIVE_REPLACEMENT_DEPTH: [usize; 6] = [2, 4, 8, 16, 32, 64];
const MAX_RECURSIVE_REPLACEMENT_LEN: usize = 64 << 10; const MAX_RECURSIVE_REPLACEMENT_LEN: usize = 64 << 10;
const CHOOSE_SUBINPUT_PROB: f64 = 0.5; const CHOOSE_SUBINPUT_PROB: f64 = 0.5;
fn extend_with_random_generalized<S>( fn extend_with_random_generalized<I, S>(
state: &mut S, state: &mut S,
items: &mut Vec<GeneralizedItem>, items: &mut Vec<GeneralizedItem>,
gap_indices: &mut Vec<usize>, gap_indices: &mut Vec<usize>,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
where where
S: HasMetadata + HasRand + HasCorpus, S: HasMetadata + HasRand + HasCorpus<I>,
{ {
let id = random_corpus_id!(state.corpus(), state.rand_mut()); let id = random_corpus_id!(state.corpus(), state.rand_mut());
@ -116,13 +117,14 @@ where
/// Extend the generalized input with another random one from the corpus /// Extend the generalized input with another random one from the corpus
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct GrimoireExtensionMutator { pub struct GrimoireExtensionMutator<I> {
gap_indices: Vec<usize>, gap_indices: Vec<usize>,
phantom: PhantomData<I>,
} }
impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireExtensionMutator impl<I, S> Mutator<GeneralizedInputMetadata, S> for GrimoireExtensionMutator<I>
where where
S: HasMetadata + HasRand + HasCorpus, S: HasMetadata + HasRand + HasCorpus<I>,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -137,33 +139,35 @@ where
} }
} }
impl Named for GrimoireExtensionMutator { impl<I> Named for GrimoireExtensionMutator<I> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireExtensionMutator"); static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireExtensionMutator");
&NAME &NAME
} }
} }
impl GrimoireExtensionMutator { impl<I> GrimoireExtensionMutator<I> {
/// Creates a new [`GrimoireExtensionMutator`]. /// Creates a new [`GrimoireExtensionMutator`].
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
gap_indices: vec![], gap_indices: vec![],
phantom: PhantomData,
} }
} }
} }
/// Extend the generalized input with another random one from the corpus /// Extend the generalized input with another random one from the corpus
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct GrimoireRecursiveReplacementMutator { pub struct GrimoireRecursiveReplacementMutator<I> {
scratch: Vec<GeneralizedItem>, scratch: Vec<GeneralizedItem>,
gap_indices: Vec<usize>, gap_indices: Vec<usize>,
phantom: PhantomData<I>,
} }
impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireRecursiveReplacementMutator impl<I, S> Mutator<GeneralizedInputMetadata, S> for GrimoireRecursiveReplacementMutator<I>
where where
S: HasMetadata + HasRand + HasCorpus, S: HasMetadata + HasRand + HasCorpus<I>,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -215,31 +219,34 @@ where
} }
} }
impl Named for GrimoireRecursiveReplacementMutator { impl<I> Named for GrimoireRecursiveReplacementMutator<I> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireRecursiveReplacementMutator"); static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireRecursiveReplacementMutator");
&NAME &NAME
} }
} }
impl GrimoireRecursiveReplacementMutator { impl<I> GrimoireRecursiveReplacementMutator<I> {
/// Creates a new [`GrimoireRecursiveReplacementMutator`]. /// Creates a new [`GrimoireRecursiveReplacementMutator`].
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
scratch: vec![], scratch: vec![],
gap_indices: vec![], gap_indices: vec![],
phantom: PhantomData,
} }
} }
} }
/// Replace matching tokens with others from the tokens metadata /// Replace matching tokens with others from the tokens metadata
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct GrimoireStringReplacementMutator {} pub struct GrimoireStringReplacementMutator<I> {
phantom: PhantomData<I>,
}
impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireStringReplacementMutator impl<I, S> Mutator<GeneralizedInputMetadata, S> for GrimoireStringReplacementMutator<I>
where where
S: HasMetadata + HasRand + HasCorpus, S: HasMetadata + HasRand + HasCorpus<I>,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -336,30 +343,33 @@ where
} }
} }
impl Named for GrimoireStringReplacementMutator { impl<I> Named for GrimoireStringReplacementMutator<I> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireStringReplacementMutator"); static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireStringReplacementMutator");
&NAME &NAME
} }
} }
impl GrimoireStringReplacementMutator { impl<I> GrimoireStringReplacementMutator<I> {
/// Creates a new [`GrimoireExtensionMutator`]. /// Creates a new [`GrimoireExtensionMutator`].
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self {
phantom: PhantomData,
}
} }
} }
/// Randomly delete a part of the generalized input /// Randomly delete a part of the generalized input
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct GrimoireRandomDeleteMutator { pub struct GrimoireRandomDeleteMutator<I> {
gap_indices: Vec<usize>, gap_indices: Vec<usize>,
phantom: PhantomData<I>,
} }
impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireRandomDeleteMutator impl<I, S> Mutator<GeneralizedInputMetadata, S> for GrimoireRandomDeleteMutator<I>
where where
S: HasMetadata + HasRand + HasCorpus, S: HasMetadata + HasRand + HasCorpus<I>,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -400,19 +410,20 @@ where
} }
} }
impl Named for GrimoireRandomDeleteMutator { impl<I> Named for GrimoireRandomDeleteMutator<I> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireRandomDeleteMutator"); static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireRandomDeleteMutator");
&NAME &NAME
} }
} }
impl GrimoireRandomDeleteMutator { impl<I> GrimoireRandomDeleteMutator<I> {
/// Creates a new [`GrimoireExtensionMutator`]. /// Creates a new [`GrimoireExtensionMutator`].
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
gap_indices: vec![], gap_indices: vec![],
phantom: PhantomData,
} }
} }
} }

View File

@ -51,9 +51,9 @@ pub type HavocMutationsNoCrossoverType = tuple_list_type!(
pub type HavocCrossoverType = tuple_list_type!(CrossoverInsertMutator, CrossoverReplaceMutator); pub type HavocCrossoverType = tuple_list_type!(CrossoverInsertMutator, CrossoverReplaceMutator);
/// Tuple type of the mutations that compose the Havoc mutator's crossover mutations for mapped input types /// Tuple type of the mutations that compose the Havoc mutator's crossover mutations for mapped input types
pub type MappedHavocCrossoverType<F, O> = tuple_list_type!( pub type MappedHavocCrossoverType<F, I, O> = tuple_list_type!(
MappedCrossoverInsertMutator<F, O>, MappedCrossoverInsertMutator<F, I, O>,
MappedCrossoverReplaceMutator<F, O>, MappedCrossoverReplaceMutator<F, I, O>,
); );
/// Tuple type of the mutations that compose the Havoc mutator /// Tuple type of the mutations that compose the Havoc mutator
@ -61,15 +61,15 @@ pub type HavocMutationsType =
merge_tuple_list_type!(HavocMutationsNoCrossoverType, HavocCrossoverType); merge_tuple_list_type!(HavocMutationsNoCrossoverType, HavocCrossoverType);
/// Tuple type of the mutations that compose the Havoc mutator for mapped input types /// Tuple type of the mutations that compose the Havoc mutator for mapped input types
pub type MappedHavocMutationsType<F1, F2, O> = map_tuple_list_type!( pub type MappedHavocMutationsType<F1, F2, I, O> = map_tuple_list_type!(
merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,O>), merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,I, O>),
ToMappingMutator<F1> ToMappingMutator<F1>
); );
/// Tuple type of the mutations that compose the Havoc mutator for mapped input types, for optional byte array input parts /// Tuple type of the mutations that compose the Havoc mutator for mapped input types, for optional byte array input parts
pub type OptionMappedHavocMutationsType<F1, F2, O> = map_tuple_list_type!( pub type OptionMappedHavocMutationsType<F1, F2, I, O> = map_tuple_list_type!(
map_tuple_list_type!( map_tuple_list_type!(
merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,O>), merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,I, O>),
ToOptionalMutator ToOptionalMutator
), ),
ToMappingMutator<F1> ToMappingMutator<F1>
@ -117,9 +117,9 @@ pub fn havoc_crossover() -> HavocCrossoverType {
} }
/// Get the mutations that compose the Havoc mutator's crossover strategy with custom corpus extraction logic /// Get the mutations that compose the Havoc mutator's crossover strategy with custom corpus extraction logic
pub fn havoc_crossover_with_corpus_mapper<F, IO, O>( pub fn havoc_crossover_with_corpus_mapper<F, I, IO, O>(
input_mapper: F, input_mapper: F,
) -> MappedHavocCrossoverType<F, O> ) -> MappedHavocCrossoverType<F, I, O>
where where
F: Clone + Fn(&IO) -> &O, F: Clone + Fn(&IO) -> &O,
{ {
@ -130,9 +130,9 @@ where
} }
/// Get the mutations that compose the Havoc mutator's crossover strategy with custom corpus extraction logic /// Get the mutations that compose the Havoc mutator's crossover strategy with custom corpus extraction logic
pub fn havoc_crossover_with_corpus_mapper_optional<F, O>( pub fn havoc_crossover_with_corpus_mapper_optional<F, I, O>(
input_mapper: F, input_mapper: F,
) -> MappedHavocCrossoverType<F, O> ) -> MappedHavocCrossoverType<F, I, O>
where where
F: Clone, F: Clone,
{ {
@ -155,7 +155,7 @@ pub fn havoc_mutations() -> HavocMutationsType {
pub fn mapped_havoc_mutations<F1, F2, IO1, IO2, II, O>( pub fn mapped_havoc_mutations<F1, F2, IO1, IO2, II, O>(
current_input_mapper: F1, current_input_mapper: F1,
input_from_corpus_mapper: F2, input_from_corpus_mapper: F2,
) -> MappedHavocMutationsType<F1, F2, O> ) -> MappedHavocMutationsType<F1, F2, IO1, O>
where where
F1: Clone + FnMut(&mut IO1) -> &mut II, F1: Clone + FnMut(&mut IO1) -> &mut II,
F2: Clone + Fn(&IO2) -> &O, F2: Clone + Fn(&IO2) -> &O,
@ -172,7 +172,7 @@ where
pub fn optional_mapped_havoc_mutations<F1, F2, IO1, IO2, II, O>( pub fn optional_mapped_havoc_mutations<F1, F2, IO1, IO2, II, O>(
current_input_mapper: F1, current_input_mapper: F1,
input_from_corpus_mapper: F2, input_from_corpus_mapper: F2,
) -> OptionMappedHavocMutationsType<F1, F2, O> ) -> OptionMappedHavocMutationsType<F1, F2, IO1, O>
where where
F1: Clone + FnMut(&mut IO1) -> &mut II, F1: Clone + FnMut(&mut IO1) -> &mut II,
F2: Clone + Fn(&IO2) -> &O, F2: Clone + Fn(&IO2) -> &O,

View File

@ -371,7 +371,7 @@ pub struct StdMOptMutator<MT> {
impl<I, MT, S> Mutator<I, S> for StdMOptMutator<MT> impl<I, MT, S> Mutator<I, S> for StdMOptMutator<MT>
where where
MT: MutatorsTuple<I, S>, MT: MutatorsTuple<I, S>,
S: HasRand + HasMetadata + HasCorpus + HasSolutions, S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
{ {
#[inline] #[inline]
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
@ -519,7 +519,7 @@ impl<MT> StdMOptMutator<MT> {
} }
fn core_mutate<I, S>(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> fn core_mutate<I, S>(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error>
where where
S: HasMetadata + HasRand + HasSolutions + HasCorpus, S: HasMetadata + HasRand + HasSolutions<I> + HasCorpus<I>,
MT: MutatorsTuple<I, S>, MT: MutatorsTuple<I, S>,
{ {
let mut r = MutationResult::Skipped; let mut r = MutationResult::Skipped;
@ -546,7 +546,7 @@ impl<MT> StdMOptMutator<MT> {
fn pilot_mutate<I, S>(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> fn pilot_mutate<I, S>(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error>
where where
S: HasMetadata + HasRand + HasSolutions + HasCorpus, S: HasMetadata + HasRand + HasSolutions<I> + HasCorpus<I>,
MT: MutatorsTuple<I, S>, MT: MutatorsTuple<I, S>,
{ {
let mut r = MutationResult::Skipped; let mut r = MutationResult::Skipped;
@ -604,7 +604,7 @@ impl<MT> Named for StdMOptMutator<MT> {
impl<I, MT, S> ScheduledMutator<I, S> for StdMOptMutator<MT> impl<I, MT, S> ScheduledMutator<I, S> for StdMOptMutator<MT>
where where
MT: MutatorsTuple<I, 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, _: &I) -> u64 {

View File

@ -118,9 +118,8 @@ impl_default_multipart!(
impl<I, S> Mutator<MultipartInput<I>, S> for CrossoverInsertMutator impl<I, S> Mutator<MultipartInput<I>, S> for CrossoverInsertMutator
where where
S: HasCorpus + HasMaxSize + HasRand, S: HasCorpus<MultipartInput<I>> + HasMaxSize + HasRand,
I: Input + HasMutatorResizableBytes, I: Input + HasMutatorResizableBytes,
S::Corpus: Corpus<Input = MultipartInput<I>>,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -254,9 +253,8 @@ where
impl<I, S> Mutator<MultipartInput<I>, S> for CrossoverReplaceMutator impl<I, S> Mutator<MultipartInput<I>, S> for CrossoverReplaceMutator
where where
S: HasCorpus + HasMaxSize + HasRand, S: HasCorpus<MultipartInput<I>> + HasMaxSize + HasRand,
I: Input + HasMutatorResizableBytes, I: Input + HasMutatorResizableBytes,
S::Corpus: Corpus<Input = MultipartInput<I>>,
{ {
fn mutate( fn mutate(
&mut self, &mut self,

View File

@ -1125,9 +1125,8 @@ impl CrossoverInsertMutator {
impl<I, S> Mutator<I, S> for CrossoverInsertMutator impl<I, S> Mutator<I, S> for CrossoverInsertMutator
where where
S: HasCorpus + HasRand + HasMaxSize,
<S::Corpus as Corpus>::Input: HasMutatorBytes,
I: HasMutatorResizableBytes, I: HasMutatorResizableBytes,
S: HasCorpus<I> + HasRand + HasMaxSize,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -1217,9 +1216,8 @@ impl CrossoverReplaceMutator {
impl<I, S> Mutator<I, S> for CrossoverReplaceMutator impl<I, S> Mutator<I, S> for CrossoverReplaceMutator
where where
S: HasCorpus + HasRand,
<S::Corpus as Corpus>::Input: HasMutatorBytes,
I: HasMutatorBytes, I: HasMutatorBytes,
S: HasCorpus<I> + HasRand,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -1297,12 +1295,12 @@ impl IntoOptionBytes for Option<Vec<u8>> {
/// Crossover insert mutation for inputs mapped to a bytes vector /// Crossover insert mutation for inputs mapped to a bytes vector
#[derive(Debug)] #[derive(Debug)]
pub struct MappedCrossoverInsertMutator<F, O> { pub struct MappedCrossoverInsertMutator<F, I, O> {
input_mapper: F, input_mapper: F,
phantom: PhantomData<O>, phantom: PhantomData<(I, O)>,
} }
impl<F, O> MappedCrossoverInsertMutator<F, O> { impl<F, I, O> MappedCrossoverInsertMutator<F, I, O> {
/// Creates a new [`MappedCrossoverInsertMutator`] /// Creates a new [`MappedCrossoverInsertMutator`]
pub fn new(input_mapper: F) -> Self { pub fn new(input_mapper: F) -> Self {
Self { Self {
@ -1312,14 +1310,14 @@ impl<F, O> MappedCrossoverInsertMutator<F, O> {
} }
} }
impl<S, F, I, O> Mutator<I, S> for MappedCrossoverInsertMutator<F, O> impl<S, F, I1, I2, O> Mutator<I2, S> for MappedCrossoverInsertMutator<F, I1, O>
where where
S: HasCorpus + HasMaxSize + HasRand, F: Fn(&I1) -> &O,
I: HasMutatorResizableBytes, I2: HasMutatorResizableBytes,
O: IntoOptionBytes, O: IntoOptionBytes,
F: Fn(&<S::Corpus as Corpus>::Input) -> &O, S: HasCorpus<I1> + HasMaxSize + HasRand,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I2) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
let max_size = state.max_size(); let max_size = state.max_size();
// TODO: fix bug if size is 0 (?) // TODO: fix bug if size is 0 (?)
@ -1377,7 +1375,7 @@ where
} }
} }
impl<F, O> Named for MappedCrossoverInsertMutator<F, O> { impl<F, I, O> Named for MappedCrossoverInsertMutator<F, I, O> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("MappedCrossoverInsertMutator"); static NAME: Cow<'static, str> = Cow::Borrowed("MappedCrossoverInsertMutator");
&NAME &NAME
@ -1386,12 +1384,12 @@ impl<F, O> Named for MappedCrossoverInsertMutator<F, O> {
/// Crossover replace mutation for inputs mapped to a bytes vector /// Crossover replace mutation for inputs mapped to a bytes vector
#[derive(Debug)] #[derive(Debug)]
pub struct MappedCrossoverReplaceMutator<F, O> { pub struct MappedCrossoverReplaceMutator<F, I, O> {
input_mapper: F, input_mapper: F,
phantom: PhantomData<O>, phantom: PhantomData<(I, O)>,
} }
impl<F, O> MappedCrossoverReplaceMutator<F, O> { impl<F, I, O> MappedCrossoverReplaceMutator<F, I, O> {
/// Creates a new [`MappedCrossoverReplaceMutator`] /// Creates a new [`MappedCrossoverReplaceMutator`]
pub fn new(input_mapper: F) -> Self { pub fn new(input_mapper: F) -> Self {
Self { Self {
@ -1401,14 +1399,14 @@ impl<F, O> MappedCrossoverReplaceMutator<F, O> {
} }
} }
impl<S, F, I, O> Mutator<I, S> for MappedCrossoverReplaceMutator<F, O> impl<S, F, I1, I2, O> Mutator<I2, S> for MappedCrossoverReplaceMutator<F, I1, O>
where where
S: HasCorpus + HasMaxSize + HasRand, F: Fn(&I1) -> &O,
I: HasMutatorBytes, I2: HasMutatorBytes,
O: IntoOptionBytes, O: IntoOptionBytes,
F: Fn(&<S::Corpus as Corpus>::Input) -> &O, S: HasCorpus<I1> + HasMaxSize + HasRand,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I2) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
if size == 0 { if size == 0 {
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
@ -1463,7 +1461,7 @@ where
} }
} }
impl<F, O> Named for MappedCrossoverReplaceMutator<F, O> { impl<F, I, O> Named for MappedCrossoverReplaceMutator<F, I, O> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("MappedCrossoverReplaceMutator"); static NAME: Cow<'static, str> = Cow::Borrowed("MappedCrossoverReplaceMutator");
&NAME &NAME
@ -1492,8 +1490,7 @@ pub struct SpliceMutator;
impl<I, S> Mutator<I, S> for SpliceMutator impl<I, S> Mutator<I, S> for SpliceMutator
where where
S: HasCorpus + HasRand, S: HasCorpus<I> + HasRand,
<S::Corpus as Corpus>::Input: HasMutatorBytes,
I: HasMutatorResizableBytes, I: HasMutatorResizableBytes,
{ {
#[expect(clippy::cast_sign_loss)] #[expect(clippy::cast_sign_loss)]
@ -1657,7 +1654,7 @@ mod tests {
) )
} }
fn test_state() -> impl HasCorpus + HasMetadata + HasRand + HasMaxSize { fn test_state() -> impl HasCorpus<BytesInput> + HasMetadata + HasRand + HasMaxSize {
let rand = StdRand::with_seed(1337); let rand = StdRand::with_seed(1337);
let mut corpus = InMemoryCorpus::new(); let mut corpus = InMemoryCorpus::new();

View File

@ -162,7 +162,7 @@ impl Debug for NautilusSpliceMutator<'_> {
impl<S> Mutator<NautilusInput, S> for NautilusSpliceMutator<'_> impl<S> Mutator<NautilusInput, S> for NautilusSpliceMutator<'_>
where where
S: HasCorpus + HasMetadata + HasRand, S: HasCorpus<NautilusInput> + HasMetadata + HasRand,
{ {
fn mutate( fn mutate(
&mut self, &mut self,

View File

@ -1,6 +1,7 @@
//! Mutators for integer-style inputs //! Mutators for integer-style inputs
use alloc::borrow::Cow; use alloc::borrow::Cow;
use core::marker::PhantomData;
use libafl_bolts::{ use libafl_bolts::{
rands::Rand, rands::Rand,
@ -31,7 +32,7 @@ pub type IntMutatorsType = tuple_list_type!(
pub type IntMutatorsCrossoverType = tuple_list_type!(CrossoverMutator); pub type IntMutatorsCrossoverType = tuple_list_type!(CrossoverMutator);
/// Mapped mutators for integer-like inputs that implement some form of crossover. /// Mapped mutators for integer-like inputs that implement some form of crossover.
pub type MappedIntMutatorsCrossoverType<F> = tuple_list_type!(MappedCrossoverMutator<F>); pub type MappedIntMutatorsCrossoverType<F, I> = tuple_list_type!(MappedCrossoverMutator<F, I>);
/// Mutators for integer-like inputs without crossover mutations /// Mutators for integer-like inputs without crossover mutations
pub type IntMutatorsNoCrossoverType = tuple_list_type!( pub type IntMutatorsNoCrossoverType = tuple_list_type!(
@ -64,7 +65,9 @@ pub fn int_mutators_crossover() -> IntMutatorsCrossoverType {
/// Mutators for integer-like inputs that implement some form of crossover with a mapper to extract the crossed over information. /// Mutators for integer-like inputs that implement some form of crossover with a mapper to extract the crossed over information.
#[must_use] #[must_use]
pub fn mapped_int_mutators_crossover<F>(input_mapper: F) -> MappedIntMutatorsCrossoverType<F> { pub fn mapped_int_mutators_crossover<F, I>(
input_mapper: F,
) -> MappedIntMutatorsCrossoverType<F, I> {
tuple_list!(MappedCrossoverMutator::new(input_mapper)) tuple_list!(MappedCrossoverMutator::new(input_mapper))
} }
@ -77,14 +80,14 @@ pub fn int_mutators() -> IntMutatorsType {
} }
/// Mapped mutators for integer-like inputs /// Mapped mutators for integer-like inputs
pub type MappedIntMutatorsType<F1, F2> = tuple_list_type!( pub type MappedIntMutatorsType<F1, F2, I> = tuple_list_type!(
MappingMutator<BitFlipMutator,F1>, MappingMutator<BitFlipMutator,F1>,
MappingMutator<NegateMutator,F1>, MappingMutator<NegateMutator,F1>,
MappingMutator<IncMutator,F1>, MappingMutator<IncMutator,F1>,
MappingMutator<DecMutator,F1>, MappingMutator<DecMutator,F1>,
MappingMutator<TwosComplementMutator,F1>, MappingMutator<TwosComplementMutator,F1>,
MappingMutator<RandMutator,F1>, MappingMutator<RandMutator,F1>,
MappingMutator<MappedCrossoverMutator<F2>,F1> MappingMutator<MappedCrossoverMutator<F2, I>,F1>
); );
/// Mapped mutators for integer-like inputs /// Mapped mutators for integer-like inputs
@ -93,7 +96,7 @@ pub type MappedIntMutatorsType<F1, F2> = tuple_list_type!(
pub fn mapped_int_mutators<F1, F2, IO, II>( pub fn mapped_int_mutators<F1, F2, IO, II>(
current_input_mapper: F1, current_input_mapper: F1,
input_from_corpus_mapper: F2, input_from_corpus_mapper: F2,
) -> MappedIntMutatorsType<F1, F2> ) -> MappedIntMutatorsType<F1, F2, IO>
where where
F1: Clone + FnMut(&mut IO) -> &mut II, F1: Clone + FnMut(&mut IO) -> &mut II,
{ {
@ -365,8 +368,7 @@ pub struct CrossoverMutator;
impl<I, S> Mutator<I, S> for CrossoverMutator impl<I, S> Mutator<I, S> for CrossoverMutator
where where
S: HasRand + HasCorpus, S: HasRand + HasCorpus<I>,
S::Corpus: Corpus<Input = I>,
I: Copy, I: Copy,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
@ -389,24 +391,28 @@ impl Named for CrossoverMutator {
} }
/// Crossover mutation for integer-like inputs with custom state extraction function /// Crossover mutation for integer-like inputs with custom state extraction function
#[derive(Debug)] #[derive(Debug)]
pub struct MappedCrossoverMutator<F> { pub struct MappedCrossoverMutator<F, I> {
input_mapper: F, input_mapper: F,
phantom: PhantomData<I>,
} }
impl<F> MappedCrossoverMutator<F> { impl<F, I> MappedCrossoverMutator<F, I> {
/// Create a new [`MappedCrossoverMutator`] /// Create a new [`MappedCrossoverMutator`]
pub fn new(input_mapper: F) -> Self { pub fn new(input_mapper: F) -> Self {
Self { input_mapper } Self {
input_mapper,
phantom: PhantomData,
}
} }
} }
impl<I, S, F> Mutator<I, S> for MappedCrossoverMutator<F> impl<I, O, S, F> Mutator<O, S> for MappedCrossoverMutator<F, I>
where where
S: HasRand + HasCorpus, S: HasRand + HasCorpus<I>,
for<'b> F: Fn(&'b <S::Corpus as Corpus>::Input) -> &'b I, for<'b> F: Fn(&'b I) -> &'b O,
I: Clone, O: Clone,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut O) -> Result<MutationResult, Error> {
let id = random_corpus_id_with_disabled!(state.corpus(), state.rand_mut()); let id = random_corpus_id_with_disabled!(state.corpus(), state.rand_mut());
if state.corpus().current().is_some_and(|cur| cur == id) { if state.corpus().current().is_some_and(|cur| cur == id) {
@ -421,7 +427,7 @@ where
} }
} }
impl<F> Named for MappedCrossoverMutator<F> { impl<F, I> Named for MappedCrossoverMutator<F, I> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&Cow::Borrowed("MappedCrossoverMutator") &Cow::Borrowed("MappedCrossoverMutator")
} }

View File

@ -215,7 +215,7 @@ impl<SM> Named for LoggerScheduledMutator<SM> {
impl<I, S, SM> Mutator<I, S> for LoggerScheduledMutator<SM> impl<I, S, SM> Mutator<I, S> for LoggerScheduledMutator<SM>
where where
S: HasRand + HasCorpus, S: HasRand + HasCorpus<I>,
SM: ScheduledMutator<I, S>, SM: ScheduledMutator<I, S>,
SM::Mutations: MutatorsTuple<I, S> + NamedTuple, SM::Mutations: MutatorsTuple<I, S> + NamedTuple,
{ {
@ -258,7 +258,7 @@ where
impl<I, S, SM> ScheduledMutator<I, S> for LoggerScheduledMutator<SM> impl<I, S, SM> ScheduledMutator<I, S> for LoggerScheduledMutator<SM>
where where
S: HasRand + HasCorpus, S: HasRand + HasCorpus<I>,
SM: ScheduledMutator<I, S>, SM: ScheduledMutator<I, S>,
SM::Mutations: MutatorsTuple<I, S> + NamedTuple, SM::Mutations: MutatorsTuple<I, S> + NamedTuple,
{ {

View File

@ -31,7 +31,7 @@ use crate::{
}, },
observers::cmp::{AFLppCmpValuesMetadata, CmpValues, CmpValuesMetadata}, observers::cmp::{AFLppCmpValuesMetadata, CmpValues, CmpValuesMetadata},
stages::TaintMetadata, stages::TaintMetadata,
state::{HasCorpus, HasMaxSize, HasRand}, state::{HasMaxSize, HasRand},
Error, HasMetadata, Error, HasMetadata,
}; };
@ -1305,7 +1305,7 @@ impl AFLppRedQueen {
impl<I, S> MultiMutator<I, S> for AFLppRedQueen impl<I, S> MultiMutator<I, S> for AFLppRedQueen
where where
S: HasMetadata + HasRand + HasMaxSize + HasCorpus + HasCurrentCorpusId, S: HasMetadata + HasRand + HasMaxSize + HasCurrentCorpusId,
I: HasMutatorResizableBytes + From<Vec<u8>>, I: HasMutatorResizableBytes + From<Vec<u8>>,
{ {
#[expect(clippy::needless_range_loop, clippy::too_many_lines)] #[expect(clippy::needless_range_loop, clippy::too_many_lines)]

View File

@ -10,7 +10,7 @@ use core::{
use libafl_bolts::{rands::Rand, Error, HasLen, Named}; use libafl_bolts::{rands::Rand, Error, HasLen, Named};
use crate::{ use crate::{
corpus::{Corpus, CorpusId, HasTestcase, Testcase}, corpus::{CorpusId, HasTestcase, Testcase},
inputs::{BytesInput, HasMutatorBytes, HasMutatorResizableBytes}, inputs::{BytesInput, HasMutatorBytes, HasMutatorResizableBytes},
mutators::{rand_range, MutationResult, Mutator, Tokens}, mutators::{rand_range, MutationResult, Mutator, Tokens},
nonzero, nonzero,
@ -32,8 +32,7 @@ pub type UnicodeInput = (BytesInput, UnicodeIdentificationMetadata);
impl<S> MutatedTransform<BytesInput, S> for UnicodeInput impl<S> MutatedTransform<BytesInput, S> for UnicodeInput
where where
S: HasCorpus + HasTestcase, S: HasCorpus<BytesInput> + HasTestcase<BytesInput>,
S::Corpus: Corpus<Input = BytesInput>,
{ {
type Post = UnicodeIdentificationMetadata; type Post = UnicodeIdentificationMetadata;
@ -50,7 +49,7 @@ where
impl<S> MutatedTransformPost<S> for UnicodeIdentificationMetadata impl<S> MutatedTransformPost<S> for UnicodeIdentificationMetadata
where where
S: HasTestcase, S: HasTestcase<BytesInput>,
{ {
fn post_exec(self, state: &mut S, corpus_id: Option<CorpusId>) -> Result<(), Error> { fn post_exec(self, state: &mut S, corpus_id: Option<CorpusId>) -> Result<(), Error> {
if let Some(corpus_id) = corpus_id { if let Some(corpus_id) = corpus_id {

View File

@ -104,17 +104,17 @@ impl TopAccountingMetadata {
/// A minimizer scheduler using coverage accounting /// A minimizer scheduler using coverage accounting
#[derive(Debug)] #[derive(Debug)]
pub struct CoverageAccountingScheduler<'a, CS, O> { pub struct CoverageAccountingScheduler<'a, CS, I, O> {
accounting_map: &'a [u32], accounting_map: &'a [u32],
skip_non_favored_prob: f64, skip_non_favored_prob: f64,
inner: IndexesLenTimeMinimizerScheduler<CS, O>, inner: IndexesLenTimeMinimizerScheduler<CS, I, O>,
} }
impl<CS, O, S> Scheduler<<S::Corpus as Corpus>::Input, S> for CoverageAccountingScheduler<'_, CS, O> impl<CS, I, O, S> Scheduler<I, S> for CoverageAccountingScheduler<'_, CS, I, O>
where where
CS: Scheduler<<S::Corpus as Corpus>::Input, S>, CS: Scheduler<I, S>,
S: HasCorpus + HasMetadata + HasRand, S: HasCorpus<I> + HasMetadata + HasRand,
<S::Corpus as Corpus>::Input: HasLen, I: HasLen,
O: CanTrack, O: CanTrack,
{ {
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
@ -122,12 +122,7 @@ where
self.inner.on_add(state, id) self.inner.on_add(state, id)
} }
fn on_evaluation<OT>( fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
&mut self,
state: &mut S,
input: &<S::Corpus as Corpus>::Input,
observers: &OT,
) -> Result<(), Error>
where where
OT: MatchName, OT: MatchName,
{ {
@ -173,7 +168,7 @@ where
} }
} }
impl<'a, CS, O> CoverageAccountingScheduler<'a, CS, O> impl<'a, CS, I, O> CoverageAccountingScheduler<'a, CS, I, O>
where where
O: CanTrack, O: CanTrack,
{ {
@ -181,7 +176,7 @@ where
#[expect(clippy::cast_possible_wrap)] #[expect(clippy::cast_possible_wrap)]
pub fn update_accounting_score<S>(&self, state: &mut S, id: CorpusId) -> Result<(), Error> pub fn update_accounting_score<S>(&self, state: &mut S, id: CorpusId) -> Result<(), Error>
where where
S: HasCorpus + HasMetadata, S: HasCorpus<I> + HasMetadata,
{ {
let mut indexes = vec![]; let mut indexes = vec![];
let mut new_favoreds = vec![]; let mut new_favoreds = vec![];
@ -268,7 +263,7 @@ where
/// Cull the `Corpus` /// Cull the `Corpus`
pub fn accounting_cull<S>(&self, state: &S) -> Result<(), Error> pub fn accounting_cull<S>(&self, state: &S) -> Result<(), Error>
where where
S: HasCorpus + HasMetadata, S: HasCorpus<I> + HasMetadata,
{ {
let Some(top_rated) = state.metadata_map().get::<TopAccountingMetadata>() else { let Some(top_rated) = state.metadata_map().get::<TopAccountingMetadata>() else {
return Ok(()); return Ok(());

View File

@ -72,28 +72,26 @@ impl Default for TopRatedsMetadata {
/// ///
/// E.g., it can use all the coverage seen so far to prioritize [`Testcase`]`s` using a [`TestcaseScore`]. /// E.g., it can use all the coverage seen so far to prioritize [`Testcase`]`s` using a [`TestcaseScore`].
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MinimizerScheduler<CS, F, M, S> { pub struct MinimizerScheduler<CS, F, I, M, S> {
base: CS, base: CS,
skip_non_favored_prob: f64, skip_non_favored_prob: f64,
remove_metadata: bool, remove_metadata: bool,
phantom: PhantomData<(F, M, S)>, phantom: PhantomData<(F, I, M, S)>,
} }
impl<CS, F, M, O, S> RemovableScheduler<<S::Corpus as Corpus>::Input, S> impl<CS, F, M, I, O, S> RemovableScheduler<I, S> for MinimizerScheduler<CS, F, I, M, O>
for MinimizerScheduler<CS, F, M, O>
where where
CS: RemovableScheduler<<S::Corpus as Corpus>::Input, S> CS: RemovableScheduler<I, S> + Scheduler<I, S>,
+ Scheduler<<S::Corpus as Corpus>::Input, S>, F: TestcaseScore<I, S>,
F: TestcaseScore<S>,
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
S: HasCorpus + HasMetadata + HasRand, S: HasCorpus<I> + HasMetadata + HasRand,
{ {
/// Replaces the [`Testcase`] at the given [`CorpusId`] /// Replaces the [`Testcase`] at the given [`CorpusId`]
fn on_replace( fn on_replace(
&mut self, &mut self,
state: &mut S, state: &mut S,
id: CorpusId, id: CorpusId,
testcase: &Testcase<<S::Corpus as Corpus>::Input>, testcase: &Testcase<I>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.base.on_replace(state, id, testcase)?; self.base.on_replace(state, id, testcase)?;
self.update_score(state, id) self.update_score(state, id)
@ -104,7 +102,7 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
id: CorpusId, id: CorpusId,
testcase: &Option<Testcase<<S::Corpus as Corpus>::Input>>, testcase: &Option<Testcase<I>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.base.on_remove(state, id, testcase)?; self.base.on_remove(state, id, testcase)?;
let mut entries = let mut entries =
@ -188,12 +186,12 @@ where
} }
} }
impl<CS, F, M, O, S> Scheduler<<S::Corpus as Corpus>::Input, S> for MinimizerScheduler<CS, F, M, O> impl<CS, F, I, M, O, S> Scheduler<I, S> for MinimizerScheduler<CS, F, I, M, O>
where where
CS: Scheduler<<S::Corpus as Corpus>::Input, S>, CS: Scheduler<I, S>,
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
S: HasCorpus + HasMetadata + HasRand, S: HasCorpus<I> + HasMetadata + HasRand,
{ {
/// Called when a [`Testcase`] is added to the corpus /// Called when a [`Testcase`] is added to the corpus
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
@ -202,12 +200,7 @@ where
} }
/// An input has been evaluated /// An input has been evaluated
fn on_evaluation<OT>( fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
&mut self,
state: &mut S,
input: &<S::Corpus as Corpus>::Input,
observers: &OT,
) -> Result<(), Error>
where where
OT: MatchName, OT: MatchName,
{ {
@ -243,7 +236,7 @@ where
} }
} }
impl<CS, F, M, O> MinimizerScheduler<CS, F, M, O> impl<CS, F, I, M, O> MinimizerScheduler<CS, F, I, M, O>
where where
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
{ {
@ -251,8 +244,8 @@ where
#[expect(clippy::cast_possible_wrap)] #[expect(clippy::cast_possible_wrap)]
pub fn update_score<S>(&self, state: &mut S, id: CorpusId) -> Result<(), Error> pub fn update_score<S>(&self, state: &mut S, id: CorpusId) -> Result<(), Error>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
S: HasCorpus + HasMetadata, S: HasCorpus<I> + HasMetadata,
{ {
// Create a new top rated meta if not existing // Create a new top rated meta if not existing
if state.metadata_map().get::<TopRatedsMetadata>().is_none() { if state.metadata_map().get::<TopRatedsMetadata>().is_none() {
@ -328,7 +321,7 @@ where
/// Cull the [`Corpus`] using the [`MinimizerScheduler`] /// Cull the [`Corpus`] using the [`MinimizerScheduler`]
pub fn cull<S>(&self, state: &S) -> Result<(), Error> pub fn cull<S>(&self, state: &S) -> Result<(), Error>
where where
S: HasCorpus + HasMetadata, S: HasCorpus<I> + HasMetadata,
{ {
let Some(top_rated) = state.metadata_map().get::<TopRatedsMetadata>() else { let Some(top_rated) = state.metadata_map().get::<TopRatedsMetadata>() else {
return Ok(()); return Ok(());
@ -356,7 +349,7 @@ where
Ok(()) Ok(())
} }
} }
impl<CS, F, M, O> HasQueueCycles for MinimizerScheduler<CS, F, M, O> impl<CS, F, I, M, O> HasQueueCycles for MinimizerScheduler<CS, F, I, M, O>
where where
CS: HasQueueCycles, CS: HasQueueCycles,
{ {
@ -364,7 +357,7 @@ where
self.base.queue_cycles() self.base.queue_cycles()
} }
} }
impl<CS, F, M, O> MinimizerScheduler<CS, F, M, O> impl<CS, F, I, M, O> MinimizerScheduler<CS, F, I, M, O>
where where
O: CanTrack, O: CanTrack,
{ {
@ -425,10 +418,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, M, O> = pub type LenTimeMinimizerScheduler<CS, I, M, O> =
MinimizerScheduler<CS, LenTimeMulTestcaseScore, M, O>; MinimizerScheduler<CS, LenTimeMulTestcaseScore, I, M, O>;
/// 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, O> = pub type IndexesLenTimeMinimizerScheduler<CS, I, O> =
MinimizerScheduler<CS, LenTimeMulTestcaseScore, MapIndexesMetadata, O>; MinimizerScheduler<CS, LenTimeMulTestcaseScore, I, MapIndexesMetadata, O>;

View File

@ -66,14 +66,14 @@ pub trait RemovableScheduler<I, S> {
} }
/// Called when a [`Testcase`] is evaluated /// Called when a [`Testcase`] is evaluated
pub fn on_add_metadata_default<CS, S>( pub fn on_add_metadata_default<CS, I, S>(
scheduler: &mut CS, scheduler: &mut CS,
state: &mut S, state: &mut S,
id: CorpusId, id: CorpusId,
) -> Result<(), Error> ) -> Result<(), Error>
where where
CS: AflScheduler, CS: AflScheduler,
S: HasTestcase + HasCorpus, S: HasTestcase<I> + HasCorpus<I>,
{ {
let current_id = *state.corpus().current(); let current_id = *state.corpus().current();
@ -131,9 +131,9 @@ where
} }
/// Called when choosing the next [`Testcase`] /// Called when choosing the next [`Testcase`]
pub fn on_next_metadata_default<S>(state: &mut S) -> Result<(), Error> pub fn on_next_metadata_default<I, S>(state: &mut S) -> Result<(), Error>
where where
S: HasCorpus + HasTestcase, S: HasCorpus<I> + HasTestcase<I>,
{ {
let current_id = *state.corpus().current(); let current_id = *state.corpus().current();
@ -215,7 +215,7 @@ pub struct RandScheduler<S> {
impl<I, S> Scheduler<I, S> for RandScheduler<S> impl<I, S> Scheduler<I, S> for RandScheduler<S>
where where
S: HasCorpus + HasRand, S: HasCorpus<I> + HasRand,
{ {
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
// Set parent id // Set parent id

View File

@ -326,7 +326,7 @@ impl<C, O> HasQueueCycles for PowerQueueScheduler<C, O> {
impl<C, I, O, S> Scheduler<I, S> for PowerQueueScheduler<C, O> impl<C, I, O, S> Scheduler<I, S> for PowerQueueScheduler<C, O>
where where
S: HasCorpus + HasMetadata + HasTestcase, S: HasCorpus<I> + HasMetadata + HasTestcase<I>,
O: Hash, O: Hash,
C: AsRef<O>, C: AsRef<O>,
{ {

View File

@ -63,10 +63,10 @@ impl<F> ProbabilitySamplingScheduler<F> {
} }
/// Calculate the score and store in `ProbabilityMetadata` /// Calculate the score and store in `ProbabilityMetadata`
pub fn store_probability<S>(&self, state: &mut S, id: CorpusId) -> Result<(), Error> pub fn store_probability<I, S>(&self, state: &mut S, id: CorpusId) -> Result<(), Error>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
S: HasCorpus + HasMetadata + HasRand, S: HasCorpus<I> + HasMetadata + HasRand,
{ {
let prob = F::compute(state, &mut *state.corpus().get(id)?.borrow_mut())?; let prob = F::compute(state, &mut *state.corpus().get(id)?.borrow_mut())?;
debug_assert!( debug_assert!(
@ -83,16 +83,16 @@ impl<F> ProbabilitySamplingScheduler<F> {
} }
} }
impl<F, S> RemovableScheduler<<S::Corpus as Corpus>::Input, S> for ProbabilitySamplingScheduler<F> impl<F, I, S> RemovableScheduler<I, S> for ProbabilitySamplingScheduler<F>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
S: HasCorpus + HasMetadata + HasRand, S: HasCorpus<I> + HasMetadata + HasRand,
{ {
fn on_remove( fn on_remove(
&mut self, &mut self,
state: &mut S, state: &mut S,
id: CorpusId, id: CorpusId,
_testcase: &Option<Testcase<<S::Corpus as Corpus>::Input>>, _testcase: &Option<Testcase<I>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let meta = state let meta = state
.metadata_map_mut() .metadata_map_mut()
@ -108,7 +108,7 @@ where
&mut self, &mut self,
state: &mut S, state: &mut S,
id: CorpusId, id: CorpusId,
_prev: &Testcase<<S::Corpus as Corpus>::Input>, _prev: &Testcase<I>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let meta = state let meta = state
.metadata_map_mut() .metadata_map_mut()
@ -122,10 +122,10 @@ where
} }
} }
impl<F, S> Scheduler<<S::Corpus as Corpus>::Input, S> for ProbabilitySamplingScheduler<F> impl<F, I, S> Scheduler<I, S> for ProbabilitySamplingScheduler<F>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
S: HasCorpus + HasMetadata + HasRand, S: HasCorpus<I> + HasMetadata + HasRand,
{ {
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
let current_id = *state.corpus().current(); let current_id = *state.corpus().current();
@ -202,14 +202,11 @@ mod tests {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct UniformDistribution {} pub struct UniformDistribution {}
impl<S> TestcaseScore<S> for UniformDistribution impl<I, S> TestcaseScore<I, S> for UniformDistribution
where where
S: HasCorpus, S: HasCorpus<I>,
{ {
fn compute( fn compute(_state: &S, _: &mut Testcase<I>) -> Result<f64, Error> {
_state: &S,
_: &mut Testcase<<S::Corpus as Corpus>::Input>,
) -> Result<f64, Error> {
Ok(FACTOR) Ok(FACTOR)
} }
} }

View File

@ -20,7 +20,7 @@ impl<I, S> RemovableScheduler<I, S> for QueueScheduler {}
impl<I, S> Scheduler<I, S> for QueueScheduler impl<I, S> Scheduler<I, S> for QueueScheduler
where where
S: HasCorpus, S: HasCorpus<I>,
{ {
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
// Set parent id // Set parent id

View File

@ -15,13 +15,9 @@ use crate::{
}; };
/// Compute the favor factor of a [`Testcase`]. Higher is better. /// Compute the favor factor of a [`Testcase`]. Higher is better.
pub trait TestcaseScore<S> pub trait TestcaseScore<I, S> {
where
S: HasCorpus,
{
/// Computes the favor factor of a [`Testcase`]. Higher is better. /// Computes the favor factor of a [`Testcase`]. Higher is better.
fn compute(state: &S, entry: &mut Testcase<<S::Corpus as Corpus>::Input>) fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error>;
-> Result<f64, Error>;
} }
/// Multiply the testcase size with the execution time. /// Multiply the testcase size with the execution time.
@ -29,16 +25,13 @@ where
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LenTimeMulTestcaseScore {} pub struct LenTimeMulTestcaseScore {}
impl<S> TestcaseScore<S> for LenTimeMulTestcaseScore impl<I, S> TestcaseScore<I, S> for LenTimeMulTestcaseScore
where where
S: HasCorpus, S: HasCorpus<I>,
<S::Corpus as Corpus>::Input: HasLen, I: HasLen,
{ {
#[expect(clippy::cast_precision_loss)] #[expect(clippy::cast_precision_loss)]
fn compute( fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error> {
state: &S,
entry: &mut Testcase<<S::Corpus as Corpus>::Input>,
) -> 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 Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as f64
* entry.load_len(state.corpus())? as f64) * entry.load_len(state.corpus())? as f64)
@ -55,16 +48,13 @@ const HAVOC_MAX_MULT: f64 = 64.0;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CorpusPowerTestcaseScore {} pub struct CorpusPowerTestcaseScore {}
impl<S> TestcaseScore<S> for CorpusPowerTestcaseScore impl<I, S> TestcaseScore<I, S> for CorpusPowerTestcaseScore
where where
S: HasCorpus + HasMetadata, S: HasCorpus<I> + HasMetadata,
{ {
/// Compute the `power` we assign to each corpus entry /// Compute the `power` we assign to each corpus entry
#[expect(clippy::cast_precision_loss, clippy::too_many_lines)] #[expect(clippy::cast_precision_loss, clippy::too_many_lines)]
fn compute( fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error> {
state: &S,
entry: &mut Testcase<<S::Corpus as Corpus>::Input>,
) -> Result<f64, Error> {
let psmeta = state.metadata::<SchedulerMetadata>()?; let psmeta = state.metadata::<SchedulerMetadata>()?;
let fuzz_mu = if let Some(strat) = psmeta.strat() { let fuzz_mu = if let Some(strat) = psmeta.strat() {
@ -272,16 +262,13 @@ where
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CorpusWeightTestcaseScore {} pub struct CorpusWeightTestcaseScore {}
impl<S> TestcaseScore<S> for CorpusWeightTestcaseScore impl<I, S> TestcaseScore<I, S> for CorpusWeightTestcaseScore
where where
S: HasCorpus + HasMetadata, S: HasCorpus<I> + HasMetadata,
{ {
/// Compute the `weight` used in weighted corpus entry selection algo /// Compute the `weight` used in weighted corpus entry selection algo
#[expect(clippy::cast_precision_loss)] #[expect(clippy::cast_precision_loss)]
fn compute( fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error> {
state: &S,
entry: &mut Testcase<<S::Corpus as Corpus>::Input>,
) -> Result<f64, Error> {
let mut weight = 1.0; let mut weight = 1.0;
let psmeta = state.metadata::<SchedulerMetadata>()?; let psmeta = state.metadata::<SchedulerMetadata>()?;

View File

@ -90,9 +90,9 @@ impl TuneableScheduler {
} }
/// Gets the current corpus entry id /// Gets the current corpus entry id
pub fn get_current<S>(state: &S) -> CorpusId pub fn get_current<I, S>(state: &S) -> CorpusId
where where
S: HasCorpus, S: HasCorpus<I>,
{ {
state state
.corpus() .corpus()
@ -105,7 +105,7 @@ impl<I, S> RemovableScheduler<I, S> for TuneableScheduler {}
impl<I, S> Scheduler<I, S> for TuneableScheduler impl<I, S> Scheduler<I, S> for TuneableScheduler
where where
S: HasCorpus + HasMetadata, S: HasCorpus<I> + HasMetadata,
{ {
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
// Set parent id // Set parent id

View File

@ -155,10 +155,10 @@ where
/// Create a new alias table when the fuzzer finds a new corpus entry /// Create a new alias table when the fuzzer finds a new corpus entry
#[expect(clippy::cast_precision_loss)] #[expect(clippy::cast_precision_loss)]
pub fn create_alias_table<S>(&self, state: &mut S) -> Result<(), Error> pub fn create_alias_table<I, S>(&self, state: &mut S) -> Result<(), Error>
where where
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
S: HasCorpus + HasMetadata, S: HasCorpus<I> + HasMetadata,
{ {
let n = state.corpus().count(); let n = state.corpus().count();
@ -303,12 +303,12 @@ impl<C, F, O> HasQueueCycles for WeightedScheduler<C, F, O> {
} }
} }
impl<C, F, O, S> Scheduler<<S::Corpus as Corpus>::Input, S> for WeightedScheduler<C, F, O> impl<C, F, I, O, S> Scheduler<I, S> for WeightedScheduler<C, F, O>
where where
C: AsRef<O> + Named, C: AsRef<O> + Named,
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
O: Hash, O: Hash,
S: HasCorpus + HasMetadata + HasRand + HasTestcase, S: HasCorpus<I> + HasMetadata + HasRand + HasTestcase<I>,
{ {
/// Called when a [`Testcase`] is added to the corpus /// Called when a [`Testcase`] is added to the corpus
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
@ -317,12 +317,7 @@ where
Ok(()) Ok(())
} }
fn on_evaluation<OT>( fn on_evaluation<OT>(&mut self, state: &mut S, _input: &I, observers: &OT) -> Result<(), Error>
&mut self,
state: &mut S,
_input: &<S::Corpus as Corpus>::Input,
observers: &OT,
) -> Result<(), Error>
where where
OT: MatchName, OT: MatchName,
{ {

View File

@ -75,7 +75,7 @@ libafl_bolts::impl_serdeany!(FuzzTime);
/// The [`AflStatsStage`] is a Stage that calculates and writes /// The [`AflStatsStage`] is a Stage that calculates and writes
/// AFL++'s `fuzzer_stats` and `plot_data` information. /// AFL++'s `fuzzer_stats` and `plot_data` information.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AflStatsStage<C, E, EM, O, S, Z> { pub struct AflStatsStage<C, E, EM, I, O, S, Z> {
map_observer_handle: Handle<C>, map_observer_handle: Handle<C>,
stats_file_path: Option<PathBuf>, stats_file_path: Option<PathBuf>,
plot_file_path: Option<PathBuf>, plot_file_path: Option<PathBuf>,
@ -114,7 +114,7 @@ pub struct AflStatsStage<C, E, EM, O, S, Z> {
autotokens_enabled: bool, autotokens_enabled: bool,
/// The core we are bound to /// The core we are bound to
core_id: CoreId, core_id: CoreId,
phantom_data: PhantomData<(O, E, EM, S, Z)>, phantom_data: PhantomData<(E, EM, I, O, S, Z)>,
} }
/// AFL++'s `fuzzer_stats` /// AFL++'s `fuzzer_stats`
@ -236,13 +236,14 @@ pub struct AFLPlotData<'a> {
edges_found: &'a u64, edges_found: &'a u64,
} }
impl<C, E, EM, O, S, Z> Stage<E, EM, S, Z> for AflStatsStage<C, E, EM, O, S, Z> impl<C, E, EM, I, O, S, Z> Stage<E, EM, S, Z> for AflStatsStage<C, E, EM, I, O, S, Z>
where where
C: AsRef<O> + Named,
E: HasObservers, E: HasObservers,
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
Z: HasScheduler<<S::Corpus as Corpus>::Input, S>, Z: HasScheduler<I, S>,
S: HasImported S: HasImported
+ HasCorpus + HasCorpus<I>
+ HasMetadata + HasMetadata
+ HasStartTime + HasStartTime
+ HasExecutions + HasExecutions
@ -441,17 +442,17 @@ where
} }
} }
impl<C, E, EM, O, S, Z> AflStatsStage<C, E, EM, O, S, Z> impl<C, E, EM, I, O, S, Z> AflStatsStage<C, E, EM, I, O, S, Z>
where where
E: HasObservers, E: HasObservers,
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
S: HasImported + HasCorpus + HasMetadata + HasExecutions, S: HasImported + HasMetadata + HasExecutions,
C: AsRef<O> + Named, C: AsRef<O> + Named,
O: MapObserver, O: MapObserver,
{ {
/// Builder for `AflStatsStage` /// Builder for `AflStatsStage`
#[must_use] #[must_use]
pub fn builder() -> AflStatsStageBuilder<C, E, EM, O, S, Z> { pub fn builder() -> AflStatsStageBuilder<C, E, EM, I, O, S, Z> {
AflStatsStageBuilder::new() AflStatsStageBuilder::new()
} }
@ -479,13 +480,13 @@ where
Ok(()) Ok(())
} }
fn maybe_update_is_favored_size(&mut self, testcase: &Testcase<<S::Corpus as Corpus>::Input>) { fn maybe_update_is_favored_size(&mut self, testcase: &Testcase<I>) {
if testcase.has_metadata::<IsFavoredMetadata>() { if testcase.has_metadata::<IsFavoredMetadata>() {
self.is_favored_size += 1; self.is_favored_size += 1;
} }
} }
fn maybe_update_slowest_exec(&mut self, testcase: &Testcase<<S::Corpus as Corpus>::Input>) { fn maybe_update_slowest_exec(&mut self, testcase: &Testcase<I>) {
if let Some(exec_time) = testcase.exec_time() { if let Some(exec_time) = testcase.exec_time() {
if exec_time > &self.slowest_exec { if exec_time > &self.slowest_exec {
self.slowest_exec = *exec_time; self.slowest_exec = *exec_time;
@ -497,7 +498,7 @@ where
self.has_fuzzed_size += 1; self.has_fuzzed_size += 1;
} }
fn maybe_update_max_depth(&mut self, testcase: &Testcase<<S::Corpus as Corpus>::Input>) { fn maybe_update_max_depth(&mut self, testcase: &Testcase<I>) {
if let Ok(metadata) = testcase.metadata::<SchedulerTestcaseMetadata>() { if let Ok(metadata) = testcase.metadata::<SchedulerTestcaseMetadata>() {
if metadata.depth() > self.max_depth { if metadata.depth() > self.max_depth {
self.max_depth = metadata.depth(); self.max_depth = metadata.depth();
@ -510,11 +511,7 @@ where
} }
#[cfg(feature = "track_hit_feedbacks")] #[cfg(feature = "track_hit_feedbacks")]
fn maybe_update_last_crash( fn maybe_update_last_crash(&mut self, testcase: &Testcase<I>, state: &S) {
&mut self,
testcase: &Testcase<<S::Corpus as Corpus>::Input>,
state: &S,
) {
#[cfg(feature = "track_hit_feedbacks")] #[cfg(feature = "track_hit_feedbacks")]
if testcase if testcase
.hit_objectives() .hit_objectives()
@ -526,11 +523,7 @@ where
} }
#[cfg(feature = "track_hit_feedbacks")] #[cfg(feature = "track_hit_feedbacks")]
fn maybe_update_last_hang( fn maybe_update_last_hang(&mut self, testcase: &Testcase<I>, state: &S) {
&mut self,
testcase: &Testcase<<S::Corpus as Corpus>::Input>,
state: &S,
) {
if testcase if testcase
.hit_objectives() .hit_objectives()
.contains(&Cow::Borrowed(TIMEOUT_FEEDBACK_NAME)) .contains(&Cow::Borrowed(TIMEOUT_FEEDBACK_NAME))
@ -652,7 +645,7 @@ pub fn get_run_cmdline() -> Cow<'static, str> {
/// The Builder for `AflStatsStage` /// The Builder for `AflStatsStage`
#[derive(Debug)] #[derive(Debug)]
pub struct AflStatsStageBuilder<C, E, EM, O, S, Z> { pub struct AflStatsStageBuilder<C, E, EM, I, O, S, Z> {
stats_file_path: Option<PathBuf>, stats_file_path: Option<PathBuf>,
plot_file_path: Option<PathBuf>, plot_file_path: Option<PathBuf>,
core_id: Option<CoreId>, core_id: Option<CoreId>,
@ -664,16 +657,16 @@ pub struct AflStatsStageBuilder<C, E, EM, O, S, Z> {
banner: String, banner: String,
version: String, version: String,
target_mode: String, target_mode: String,
phantom_data: PhantomData<(O, E, EM, S, Z)>, phantom_data: PhantomData<(E, EM, I, O, S, Z)>,
} }
impl<C, E, EM, O, S, Z> AflStatsStageBuilder<C, E, EM, O, S, Z> impl<C, E, EM, I, O, S, Z> AflStatsStageBuilder<C, E, EM, I, O, S, Z>
where where
E: HasObservers,
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
S: HasImported + HasCorpus + HasMetadata + HasExecutions,
C: AsRef<O> + Named, C: AsRef<O> + Named,
E: HasObservers,
EM: EventFirer<I, S>,
O: MapObserver, O: MapObserver,
S: HasImported + HasMetadata + HasExecutions,
{ {
fn new() -> Self { fn new() -> Self {
Self { Self {
@ -785,7 +778,8 @@ where
/// Cannot create the plot file (if provided) /// Cannot create the plot file (if provided)
/// No `MapObserver` supplied to the builder /// No `MapObserver` supplied to the builder
/// No `stats_file_path` provieded /// No `stats_file_path` provieded
pub fn build(self) -> Result<AflStatsStage<C, E, EM, O, S, Z>, Error> { #[allow(clippy::type_complexity)]
pub fn build(self) -> Result<AflStatsStage<C, E, EM, I, O, S, Z>, Error> {
if self.map_observer_handle.is_none() { if self.map_observer_handle.is_none() {
return Err(Error::illegal_argument("Must set `map_observer`")); return Err(Error::illegal_argument("Must set `map_observer`"));
} }

View File

@ -79,33 +79,33 @@ impl Default for 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<C, E, O, OT, S> { pub struct CalibrationStage<C, E, I, O, OT, S> {
map_observer_handle: Handle<C>, map_observer_handle: Handle<C>,
map_name: Cow<'static, str>, map_name: Cow<'static, str>,
name: Cow<'static, str>, name: Cow<'static, str>,
stage_max: usize, stage_max: usize,
/// If we should track stability /// If we should track stability
track_stability: bool, track_stability: bool,
phantom: PhantomData<(E, O, OT, S)>, phantom: PhantomData<(E, I, O, OT, S)>,
} }
impl<C, E, EM, O, OT, S, Z> Stage<E, EM, S, Z> for CalibrationStage<C, E, O, OT, S> impl<C, E, EM, I, O, OT, S, Z> Stage<E, EM, S, Z> for CalibrationStage<C, E, I, O, OT, S>
where where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers<Observers = OT>, E: Executor<EM, I, S, Z> + HasObservers<Observers = OT>,
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
O: MapObserver, O: MapObserver,
C: AsRef<O>, C: AsRef<O>,
for<'de> <O as MapObserver>::Entry: for<'de> <O as MapObserver>::Entry:
Serialize + Deserialize<'de> + 'static + Default + Debug + Bounded, Serialize + Deserialize<'de> + 'static + Default + Debug + Bounded,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>, OT: ObserversTuple<I, S>,
S: HasCorpus S: HasCorpus<I>
+ HasMetadata + HasMetadata
+ HasNamedMetadata + HasNamedMetadata
+ HasExecutions + HasExecutions
+ HasCurrentTestcase + HasCurrentTestcase<I>
+ HasCurrentCorpusId, + HasCurrentCorpusId,
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>, Z: Evaluator<E, EM, I, S>,
<S::Corpus as Corpus>::Input: Input, I: Input,
{ {
#[inline] #[inline]
#[expect(clippy::too_many_lines, clippy::cast_precision_loss)] #[expect(clippy::too_many_lines, clippy::cast_precision_loss)]
@ -380,13 +380,12 @@ where
} }
} }
impl<C, E, O, OT, S> CalibrationStage<C, E, O, OT, S> impl<C, E, I, O, OT, S> CalibrationStage<C, E, I, O, OT, S>
where where
C: AsRef<O>,
O: MapObserver, O: MapObserver,
for<'it> O: AsIter<'it, Item = O::Entry>, for<'it> O: AsIter<'it, Item = O::Entry>,
C: AsRef<O>, OT: ObserversTuple<I, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
S: HasCorpus,
{ {
/// Create a new [`CalibrationStage`]. /// Create a new [`CalibrationStage`].
#[must_use] #[must_use]
@ -419,7 +418,7 @@ where
} }
} }
impl<C, E, O, OT, S> Named for CalibrationStage<C, E, O, OT, S> { impl<C, E, I, O, OT, S> Named for CalibrationStage<C, E, I, O, OT, S> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }

View File

@ -15,10 +15,10 @@ use libafl_bolts::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
corpus::{Corpus, HasCurrentCorpusId}, corpus::HasCurrentCorpusId,
events::EventFirer, events::EventFirer,
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
inputs::{HasMutatorBytes, HasMutatorResizableBytes}, inputs::HasMutatorResizableBytes,
mutators::mutations::buffer_copy, mutators::mutations::buffer_copy,
nonzero, nonzero,
observers::ObserversTuple, observers::ObserversTuple,
@ -63,25 +63,25 @@ impl Ord for Earlier {
pub const COLORIZATION_STAGE_NAME: &str = "colorization"; pub const COLORIZATION_STAGE_NAME: &str = "colorization";
/// The mutational stage using power schedules /// The mutational stage using power schedules
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ColorizationStage<C, E, EM, O, S, Z> { pub struct ColorizationStage<C, E, EM, I, O, S, Z> {
map_observer_handle: Handle<C>, map_observer_handle: Handle<C>,
name: Cow<'static, str>, name: Cow<'static, str>,
phantom: PhantomData<(E, EM, O, E, S, Z)>, phantom: PhantomData<(E, EM, I, O, E, S, Z)>,
} }
impl<C, E, EM, O, S, Z> Named for ColorizationStage<C, E, EM, O, S, Z> { impl<C, E, EM, I, O, S, Z> Named for ColorizationStage<C, E, EM, I, O, S, Z> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
} }
impl<C, E, EM, O, S, Z> Stage<E, EM, S, Z> for ColorizationStage<C, E, EM, O, S, Z> impl<C, E, EM, I, O, S, Z> Stage<E, EM, S, Z> for ColorizationStage<C, E, EM, I, O, S, Z>
where where
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
E: HasObservers + Executor<EM, <S::Corpus as Corpus>::Input, S, Z>, E: HasObservers + Executor<EM, I, S, Z>,
S: HasCorpus + HasMetadata + HasRand + HasNamedMetadata + HasCurrentCorpusId, S: HasCorpus<I> + HasMetadata + HasRand + HasNamedMetadata + HasCurrentCorpusId,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>, E::Observers: ObserversTuple<I, S>,
<S::Corpus as Corpus>::Input: HasMutatorResizableBytes + Clone, I: HasMutatorResizableBytes + Clone,
O: Hash, O: Hash,
C: AsRef<O> + Named, C: AsRef<O> + Named,
{ {
@ -107,7 +107,7 @@ where
} }
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
RetryCountRestartHelper::clear_progress(state, &self.name) RetryCountRestartHelper::clear_progress::<S>(state, &self.name)
} }
} }
@ -150,15 +150,15 @@ impl TaintMetadata {
libafl_bolts::impl_serdeany!(TaintMetadata); libafl_bolts::impl_serdeany!(TaintMetadata);
impl<C, E, EM, O, S, Z> ColorizationStage<C, E, EM, O, S, Z> impl<C, E, EM, I, O, S, Z> ColorizationStage<C, E, EM, I, O, S, Z>
where where
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
O: Hash, O: Hash,
C: AsRef<O> + Named, C: AsRef<O> + Named,
E: HasObservers + Executor<EM, <S::Corpus as Corpus>::Input, S, Z>, E: HasObservers + Executor<EM, I, S, Z>,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>, E::Observers: ObserversTuple<I, S>,
S: HasCorpus + HasMetadata + HasRand + HasCurrentCorpusId + HasCurrentTestcase, S: HasCorpus<I> + HasMetadata + HasRand + HasCurrentCorpusId + HasCurrentTestcase<I>,
<S::Corpus as Corpus>::Input: HasMutatorResizableBytes + Clone, I: HasMutatorResizableBytes + Clone,
{ {
#[inline] #[inline]
fn colorize( fn colorize(
@ -167,7 +167,7 @@ where
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
observer_handle: &Handle<C>, observer_handle: &Handle<C>,
) -> Result<<S::Corpus as Corpus>::Input, Error> { ) -> Result<I, Error> {
let mut input = state.current_input_cloned()?; let mut input = state.current_input_cloned()?;
// The backup of the input // The backup of the input
let backup = input.clone(); let backup = input.clone();
@ -308,7 +308,7 @@ where
executor: &mut E, executor: &mut E,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &<S::Corpus as Corpus>::Input, input: &I,
observer_handle: &Handle<C>, observer_handle: &Handle<C>,
) -> Result<usize, Error> { ) -> Result<usize, Error> {
executor.observers_mut().pre_exec_all(state, input)?; executor.observers_mut().pre_exec_all(state, input)?;

View File

@ -15,7 +15,7 @@ use libafl_bolts::{
#[cfg(all(feature = "concolic_mutation", feature = "introspection"))] #[cfg(all(feature = "concolic_mutation", feature = "introspection"))]
use crate::monitors::PerfFeature; use crate::monitors::PerfFeature;
use crate::{ use crate::{
corpus::{Corpus, HasCurrentCorpusId}, corpus::HasCurrentCorpusId,
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
observers::{concolic::ConcolicObserver, ObserversTuple}, observers::{concolic::ConcolicObserver, ObserversTuple},
stages::{RetryCountRestartHelper, Stage, TracingStage}, stages::{RetryCountRestartHelper, Stage, TracingStage},
@ -32,29 +32,29 @@ use crate::{
/// Wraps a [`TracingStage`] to add concolic observing. /// Wraps a [`TracingStage`] to add concolic observing.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ConcolicTracingStage<'a, EM, TE, S, Z> { pub struct ConcolicTracingStage<'a, EM, I, TE, S, Z> {
name: Cow<'static, str>, name: Cow<'static, str>,
inner: TracingStage<EM, TE, S, Z>, inner: TracingStage<EM, I, TE, S, Z>,
observer_handle: Handle<ConcolicObserver<'a>>, observer_handle: Handle<ConcolicObserver<'a>>,
} }
/// The name for concolic tracer /// The name for concolic tracer
pub const CONCOLIC_TRACING_STAGE_NAME: &str = "concolictracing"; pub const CONCOLIC_TRACING_STAGE_NAME: &str = "concolictracing";
impl<EM, TE, S, Z> Named for ConcolicTracingStage<'_, EM, TE, S, Z> { impl<EM, I, TE, S, Z> Named for ConcolicTracingStage<'_, EM, I, TE, S, Z> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
} }
impl<E, EM, TE, S, Z> Stage<E, EM, S, Z> for ConcolicTracingStage<'_, EM, TE, S, Z> impl<E, EM, I, TE, S, Z> Stage<E, EM, S, Z> for ConcolicTracingStage<'_, EM, I, TE, S, Z>
where where
TE: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, TE: Executor<EM, I, S, Z> + HasObservers,
TE::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>, TE::Observers: ObserversTuple<I, S>,
S: HasExecutions S: HasExecutions
+ HasCorpus + HasCorpus<I>
+ HasNamedMetadata + HasNamedMetadata
+ HasCurrentTestcase + HasCurrentTestcase<I>
+ HasCurrentCorpusId + HasCurrentCorpusId
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
{ {
@ -89,11 +89,11 @@ where
} }
} }
impl<'a, EM, TE, S, Z> ConcolicTracingStage<'a, EM, TE, S, Z> { impl<'a, EM, I, TE, S, Z> ConcolicTracingStage<'a, EM, I, TE, S, Z> {
/// Creates a new default tracing stage using the given [`Executor`], observing traces from a /// Creates a new default tracing stage using the given [`Executor`], observing traces from a
/// [`ConcolicObserver`] with the given name. /// [`ConcolicObserver`] with the given name.
pub fn new( pub fn new(
inner: TracingStage<EM, TE, S, Z>, inner: TracingStage<EM, I, TE, S, Z>,
observer_handle: Handle<ConcolicObserver<'a>>, observer_handle: Handle<ConcolicObserver<'a>>,
) -> Self { ) -> Self {
let observer_name = observer_handle.name().clone(); let observer_name = observer_handle.name().clone();
@ -353,9 +353,9 @@ 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`].
#[cfg(feature = "concolic_mutation")] #[cfg(feature = "concolic_mutation")]
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct SimpleConcolicMutationalStage<Z> { pub struct SimpleConcolicMutationalStage<I, Z> {
name: Cow<'static, str>, name: Cow<'static, str>,
phantom: PhantomData<Z>, phantom: PhantomData<(I, Z)>,
} }
#[cfg(feature = "concolic_mutation")] #[cfg(feature = "concolic_mutation")]
@ -367,22 +367,22 @@ static mut SIMPLE_CONCOLIC_MUTATIONAL_ID: usize = 0;
pub const SIMPLE_CONCOLIC_MUTATIONAL_NAME: &str = "concolicmutation"; pub const SIMPLE_CONCOLIC_MUTATIONAL_NAME: &str = "concolicmutation";
#[cfg(feature = "concolic_mutation")] #[cfg(feature = "concolic_mutation")]
impl<Z> Named for SimpleConcolicMutationalStage<Z> { impl<I, Z> Named for SimpleConcolicMutationalStage<I, Z> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
} }
#[cfg(feature = "concolic_mutation")] #[cfg(feature = "concolic_mutation")]
impl<E, EM, S, Z> Stage<E, EM, S, Z> for SimpleConcolicMutationalStage<Z> impl<E, EM, I, S, Z> Stage<E, EM, S, Z> for SimpleConcolicMutationalStage<I, Z>
where where
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>, Z: Evaluator<E, EM, I, S>,
<S::Corpus as Corpus>::Input: HasMutatorBytes + Clone, I: HasMutatorBytes + Clone,
S: HasExecutions S: HasExecutions
+ HasCorpus + HasCorpus<I>
+ HasMetadata + HasMetadata
+ HasNamedMetadata + HasNamedMetadata
+ HasCurrentTestcase + HasCurrentTestcase<I>
+ MaybeHasClientPerfMonitor + MaybeHasClientPerfMonitor
+ HasCurrentCorpusId, + HasCurrentCorpusId,
{ {
@ -434,7 +434,7 @@ where
} }
#[cfg(feature = "concolic_mutation")] #[cfg(feature = "concolic_mutation")]
impl<Z> SimpleConcolicMutationalStage<Z> { impl<I, Z> SimpleConcolicMutationalStage<I, Z> {
#[must_use] #[must_use]
/// Construct this stage /// Construct this stage
pub fn new() -> Self { pub fn new() -> Self {

View File

@ -35,20 +35,19 @@ impl_serdeany!(DumpToDiskMetadata);
/// The [`DumpToDiskStage`] is a stage that dumps the corpus and the solutions to disk /// The [`DumpToDiskStage`] is a stage that dumps the corpus and the solutions to disk
#[derive(Debug)] #[derive(Debug)]
pub struct DumpToDiskStage<CB1, CB2, EM, S, Z> { pub struct DumpToDiskStage<CB1, CB2, EM, I, S, Z> {
solutions_dir: PathBuf, solutions_dir: PathBuf,
corpus_dir: PathBuf, corpus_dir: PathBuf,
to_bytes: CB1, to_bytes: CB1,
generate_filename: CB2, generate_filename: CB2,
phantom: PhantomData<(EM, S, Z)>, phantom: PhantomData<(EM, I, S, Z)>,
} }
impl<CB1, CB2, E, EM, S, P, Z> Stage<E, EM, S, Z> for DumpToDiskStage<CB1, CB2, EM, S, Z> impl<CB1, CB2, E, EM, I, S, P, Z> Stage<E, EM, S, Z> for DumpToDiskStage<CB1, CB2, EM, I, S, Z>
where where
CB1: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &S) -> Vec<u8>, CB1: FnMut(&Testcase<I>, &S) -> Vec<u8>,
CB2: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &CorpusId) -> P, CB2: FnMut(&Testcase<I>, &CorpusId) -> P,
S: HasCorpus + HasSolutions + HasRand + HasMetadata, S: HasCorpus<I> + HasSolutions<I> + HasRand + HasMetadata,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
P: AsRef<Path>, P: AsRef<Path>,
{ {
#[inline] #[inline]
@ -76,12 +75,10 @@ where
} }
/// Implementation for `DumpToDiskStage` with a default `generate_filename` function. /// Implementation for `DumpToDiskStage` with a default `generate_filename` function.
impl<CB1, EM, S, Z> impl<CB1, EM, I, S, Z> DumpToDiskStage<CB1, fn(&Testcase<I>, &CorpusId) -> String, EM, I, S, Z>
DumpToDiskStage<CB1, fn(&Testcase<<S::Corpus as Corpus>::Input>, &CorpusId) -> String, EM, S, Z>
where where
S: HasCorpus + HasSolutions + HasRand + HasMetadata, S: HasSolutions<I> + HasRand + HasMetadata,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>, I: Input,
<S::Corpus as Corpus>::Input: Input,
{ {
/// Create a new [`DumpToDiskStage`] with a default `generate_filename` function. /// Create a new [`DumpToDiskStage`] with a default `generate_filename` function.
pub fn new<A, B>(to_bytes: CB1, corpus_dir: A, solutions_dir: B) -> Result<Self, Error> pub fn new<A, B>(to_bytes: CB1, corpus_dir: A, solutions_dir: B) -> Result<Self, Error>
@ -99,10 +96,7 @@ where
/// Default `generate_filename` function. /// Default `generate_filename` function.
#[expect(clippy::trivially_copy_pass_by_ref)] #[expect(clippy::trivially_copy_pass_by_ref)]
fn generate_filename( fn generate_filename(testcase: &Testcase<I>, id: &CorpusId) -> String {
testcase: &Testcase<<S::Corpus as Corpus>::Input>,
id: &CorpusId,
) -> String {
[ [
Some(id.0.to_string()), Some(id.0.to_string()),
testcase.filename().clone(), testcase.filename().clone(),
@ -119,10 +113,9 @@ where
} }
} }
impl<CB1, CB2, EM, S, Z> DumpToDiskStage<CB1, CB2, EM, S, Z> impl<CB1, CB2, EM, I, S, Z> DumpToDiskStage<CB1, CB2, EM, I, S, Z>
where where
S: HasCorpus + HasMetadata + HasSolutions, S: HasMetadata + HasSolutions<I>,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
{ {
/// Create a new [`DumpToDiskStage`] with a custom `generate_filename` function. /// Create a new [`DumpToDiskStage`] with a custom `generate_filename` function.
pub fn new_with_custom_filenames<A, B>( pub fn new_with_custom_filenames<A, B>(
@ -165,8 +158,9 @@ where
#[inline] #[inline]
fn dump_state_to_disk<P: AsRef<Path>>(&mut self, state: &mut S) -> Result<(), Error> fn dump_state_to_disk<P: AsRef<Path>>(&mut self, state: &mut S) -> Result<(), Error>
where where
CB1: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &S) -> Vec<u8>, S: HasCorpus<I>,
CB2: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &CorpusId) -> P, CB1: FnMut(&Testcase<I>, &S) -> Vec<u8>,
CB2: FnMut(&Testcase<I>, &CorpusId) -> P,
{ {
let (mut corpus_id, mut solutions_id) = let (mut corpus_id, mut solutions_id) =
if let Some(meta) = state.metadata_map().get::<DumpToDiskMetadata>() { if let Some(meta) = state.metadata_map().get::<DumpToDiskMetadata>() {

View File

@ -51,32 +51,44 @@ pub static GENERALIZATION_STAGE_NAME: &str = "generalization";
/// A stage that runs a tracer executor /// A stage that runs a tracer executor
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct GeneralizationStage<C, EM, O, OT, S, Z> { pub struct GeneralizationStage<C, EM, I, O, OT, S, Z> {
name: Cow<'static, str>, name: Cow<'static, str>,
map_observer_handle: Handle<C>, map_observer_handle: Handle<C>,
phantom: PhantomData<(EM, O, OT, S, Z)>, phantom: PhantomData<(EM, I, O, OT, S, Z)>,
} }
impl<C, EM, O, OT, S, Z> Named for GeneralizationStage<C, EM, O, OT, S, Z> { impl<C, EM, I, O, OT, S, Z> Named for GeneralizationStage<C, EM, I, O, OT, S, Z> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
} }
impl<C, E, EM, O, S, Z> Stage<E, EM, S, Z> for GeneralizationStage<C, EM, O, E::Observers, S, Z> impl<C, E, EM, O, S, Z> Stage<E, EM, S, Z>
for GeneralizationStage<C, EM, BytesInput, O, E::Observers, S, Z>
where where
O: MapObserver,
C: CanTrack + AsRef<O> + Named, C: CanTrack + AsRef<O> + Named,
E: Executor<EM, BytesInput, S, Z> + HasObservers, E: Executor<EM, BytesInput, S, Z> + HasObservers,
E::Observers: ObserversTuple<BytesInput, S>, E::Observers: ObserversTuple<BytesInput, S>,
O: MapObserver,
S: HasExecutions S: HasExecutions
+ HasMetadata + HasMetadata
+ HasCorpus + HasCorpus<BytesInput>
+ HasNamedMetadata + HasNamedMetadata
+ HasCurrentCorpusId + HasCurrentCorpusId
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
S::Corpus: Corpus<Input = BytesInput>,
{ {
#[inline]
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
// TODO: We need to be able to resume better if something crashes or times out
RetryCountRestartHelper::should_restart::<S>(state, &self.name, 3)
}
#[inline]
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
// TODO: We need to be able to resume better if something crashes or times out
RetryCountRestartHelper::clear_progress::<S>(state, &self.name)
}
#[inline] #[inline]
#[expect(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn perform( fn perform(
@ -326,26 +338,13 @@ where
Ok(()) Ok(())
} }
#[inline]
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
// TODO: We need to be able to resume better if something crashes or times out
RetryCountRestartHelper::should_restart(state, &self.name, 3)
} }
#[inline] impl<C, EM, O, OT, S, Z> GeneralizationStage<C, EM, BytesInput, O, OT, S, Z>
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
// TODO: We need to be able to resume better if something crashes or times out
RetryCountRestartHelper::clear_progress(state, &self.name)
}
}
impl<C, EM, O, OT, S, Z> GeneralizationStage<C, EM, O, OT, S, Z>
where where
O: MapObserver, O: MapObserver,
C: CanTrack + AsRef<O> + Named, C: CanTrack + AsRef<O> + Named,
S: HasExecutions + HasMetadata + HasCorpus + MaybeHasClientPerfMonitor, S: HasExecutions + HasMetadata + HasCorpus<BytesInput> + MaybeHasClientPerfMonitor,
S::Corpus: Corpus<Input = BytesInput>,
OT: ObserversTuple<BytesInput, S>, OT: ObserversTuple<BytesInput, S>,
{ {
/// Create a new [`GeneralizationStage`]. /// Create a new [`GeneralizationStage`].
@ -372,7 +371,7 @@ where
input: &BytesInput, input: &BytesInput,
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, E: Executor<EM, BytesInput, S, Z> + HasObservers,
E::Observers: ObserversTuple<BytesInput, S>, E::Observers: ObserversTuple<BytesInput, S>,
{ {
start_timer!(state); start_timer!(state);
@ -414,7 +413,7 @@ where
split_char: u8, split_char: u8,
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers<Observers = OT>, E: Executor<EM, BytesInput, S, Z> + HasObservers<Observers = OT>,
{ {
let mut start = 0; let mut start = 0;
while start < payload.len() { while start < payload.len() {
@ -452,7 +451,7 @@ where
closing_char: u8, closing_char: u8,
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers<Observers = OT>, E: Executor<EM, BytesInput, S, Z> + HasObservers<Observers = OT>,
{ {
let mut index = 0; let mut index = 0;
while index < payload.len() { while index < payload.len() {

View File

@ -6,33 +6,27 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::{ use crate::{generators::Generator, stages::Stage, state::HasRand, Error, Evaluator};
corpus::Corpus,
generators::Generator,
stages::Stage,
state::{HasCorpus, HasRand},
Error, Evaluator,
};
/// A [`Stage`] that generates a single input via a [`Generator`] and evaluates /// A [`Stage`] that generates a single input via a [`Generator`] and evaluates
/// it using the fuzzer, possibly adding it to the corpus. /// it using the fuzzer, possibly adding it to the corpus.
/// ///
/// This stage can be used to construct black-box (e.g., grammar-based) fuzzers. /// This stage can be used to construct black-box (e.g., grammar-based) fuzzers.
#[derive(Debug)] #[derive(Debug)]
pub struct GenStage<G, S, Z>(G, PhantomData<(S, Z)>); pub struct GenStage<G, I, S, Z>(G, PhantomData<(I, S, Z)>);
impl<G, S, Z> GenStage<G, S, Z> { impl<G, I, S, Z> GenStage<G, I, S, Z> {
/// Create a new [`GenStage`]. /// Create a new [`GenStage`].
pub fn new(g: G) -> Self { pub fn new(g: G) -> Self {
Self(g, PhantomData) Self(g, PhantomData)
} }
} }
impl<E, EM, G, S, Z> Stage<E, EM, S, Z> for GenStage<G, S, Z> impl<E, EM, G, I, S, Z> Stage<E, EM, S, Z> for GenStage<G, I, S, Z>
where where
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>, G: Generator<I, S>,
S: HasCorpus + HasRand, S: HasRand,
G: Generator<<S::Corpus as Corpus>::Input, S>, Z: Evaluator<E, EM, I, S>,
{ {
#[inline] #[inline]
fn perform( fn perform(

View File

@ -27,11 +27,10 @@ use crate::{
// TODO multi mutators stage // TODO multi mutators stage
/// Action performed after the un-transformed input is executed (e.g., updating metadata) /// Action performed after the un-transformed input is executed (e.g., updating metadata)
#[expect(unused_variables)]
pub trait MutatedTransformPost<S>: Sized { pub trait MutatedTransformPost<S>: Sized {
/// Perform any post-execution steps necessary for the transformed input (e.g., updating metadata) /// Perform any post-execution steps necessary for the transformed input (e.g., updating metadata)
#[inline] #[inline]
fn post_exec(self, state: &mut S, new_corpus_id: Option<CorpusId>) -> Result<(), Error> { fn post_exec(self, _state: &mut S, _new_corpus_id: Option<CorpusId>) -> Result<(), Error> {
Ok(()) Ok(())
} }
} }
@ -43,10 +42,7 @@ impl<S> MutatedTransformPost<S> for () {}
/// ///
/// This trait is implemented such that all testcases inherently transform to their inputs, should /// This trait is implemented such that all testcases inherently transform to their inputs, should
/// the input be cloneable. /// the input be cloneable.
pub trait MutatedTransform<I, S>: Sized pub trait MutatedTransform<I, S>: Sized {
where
I: Input,
{
/// Type indicating actions to be taken after the post-transformation input is executed /// Type indicating actions to be taken after the post-transformation input is executed
type Post: MutatedTransformPost<S>; type Post: MutatedTransformPost<S>;
@ -60,9 +56,8 @@ where
// reflexive definition // reflexive definition
impl<I, S> MutatedTransform<I, S> for I impl<I, S> MutatedTransform<I, S> for I
where where
I: Input + Clone, I: Clone,
S: HasCorpus, S: HasCorpus<I>,
S::Corpus: Corpus<Input = I>,
{ {
type Post = (); type Post = ();
@ -101,17 +96,17 @@ pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 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, I1, I2, M, S, Z> {
/// The name /// The name
name: Cow<'static, str>, name: Cow<'static, str>,
/// The mutator(s) to use /// The mutator(s) to use
mutator: M, mutator: M,
/// The maximum amount of iterations we should do each round /// The maximum amount of iterations we should do each round
max_iterations: NonZeroUsize, max_iterations: NonZeroUsize,
phantom: PhantomData<(E, EM, I, S, Z)>, phantom: PhantomData<(E, EM, I1, I2, S, Z)>,
} }
impl<E, EM, I, M, S, Z> MutationalStage<S> for StdMutationalStage<E, EM, I, M, S, Z> impl<E, EM, I1, I2, M, S, Z> MutationalStage<S> for StdMutationalStage<E, EM, I1, I2, M, S, Z>
where where
S: HasRand, S: HasRand,
{ {
@ -140,25 +135,25 @@ static mut MUTATIONAL_STAGE_ID: usize = 0;
/// The name for mutational stage /// The name for mutational stage
pub static MUTATIONAL_STAGE_NAME: &str = "mutational"; pub static MUTATIONAL_STAGE_NAME: &str = "mutational";
impl<E, EM, I, M, S, Z> Named for StdMutationalStage<E, EM, I, M, S, Z> { impl<E, EM, I1, I2, M, S, Z> Named for StdMutationalStage<E, EM, I1, I2, M, S, Z> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
} }
impl<E, EM, I, M, S, Z> Stage<E, EM, S, Z> for StdMutationalStage<E, EM, I, M, S, Z> impl<E, EM, I1, I2, M, S, Z> Stage<E, EM, S, Z> for StdMutationalStage<E, EM, I1, I2, M, S, Z>
where where
M: Mutator<I, S>, I1: Clone + MutatedTransform<I2, S>,
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>, I2: Input,
S: HasCorpus M: Mutator<I1, S>,
+ HasRand S: HasRand
+ HasCorpus<I2>
+ HasMetadata + HasMetadata
+ HasExecutions + HasExecutions
+ HasNamedMetadata + HasNamedMetadata
+ HasCurrentCorpusId + HasCurrentCorpusId
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone, Z: Evaluator<E, EM, I2, S>,
<S::Corpus as Corpus>::Input: Input,
{ {
#[inline] #[inline]
fn perform( fn perform(
@ -185,12 +180,12 @@ where
} }
} }
impl<E, EM, M, S, Z> StdMutationalStage<E, EM, <S::Corpus as Corpus>::Input, M, S, Z> impl<E, EM, I, M, S, Z> StdMutationalStage<E, EM, I, I, M, S, Z>
where where
M: Mutator<<S::Corpus as Corpus>::Input, S>, M: Mutator<I, S>,
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>, I: MutatedTransform<I, S> + Input + Clone,
S: HasCorpus + HasRand + HasCurrentCorpusId + MaybeHasClientPerfMonitor, S: HasCorpus<I> + HasRand + HasCurrentCorpusId + MaybeHasClientPerfMonitor,
<S::Corpus as Corpus>::Input: Input + Clone, Z: Evaluator<E, EM, I, S>,
{ {
/// Creates a new default mutational stage /// Creates a new default mutational stage
pub fn new(mutator: M) -> Self { pub fn new(mutator: M) -> Self {
@ -205,13 +200,13 @@ where
} }
} }
impl<E, EM, I, M, S, Z> StdMutationalStage<E, EM, I, M, S, Z> impl<E, EM, I1, I2, M, S, Z> StdMutationalStage<E, EM, I1, I2, M, S, Z>
where where
M: Mutator<I, S>, I1: MutatedTransform<I2, S> + Clone,
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>, I2: Input,
S: HasCorpus + HasRand + HasCurrentTestcase + MaybeHasClientPerfMonitor, M: Mutator<I1, S>,
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone, S: HasCorpus<I2> + HasRand + HasCurrentCorpusId + MaybeHasClientPerfMonitor,
<S::Corpus as Corpus>::Input: Input, Z: Evaluator<E, EM, I2, S>,
{ {
/// Creates a new transforming mutational stage with the default max iterations /// Creates a new transforming mutational stage with the default max iterations
pub fn transforming(mutator: M) -> Self { pub fn transforming(mutator: M) -> Self {
@ -236,7 +231,16 @@ where
phantom: PhantomData, phantom: PhantomData,
} }
} }
}
impl<E, EM, I1, I2, M, S, Z> StdMutationalStage<E, EM, I1, I2, M, S, Z>
where
I1: MutatedTransform<I2, S> + Clone,
I2: Input,
M: Mutator<I1, S>,
S: HasRand + HasCurrentTestcase<I2> + MaybeHasClientPerfMonitor,
Z: Evaluator<E, EM, I2, S>,
{
/// Runs this (mutational) stage for the given testcase /// Runs this (mutational) stage for the given testcase
fn perform_mutational( fn perform_mutational(
&mut self, &mut self,
@ -256,7 +260,7 @@ where
let num = self.iterations(state)?; let num = self.iterations(state)?;
let mut testcase = state.current_testcase_mut()?; let mut testcase = state.current_testcase_mut()?;
let Ok(input) = I::try_transform_from(&mut testcase, state) else { let Ok(input) = I1::try_transform_from(&mut testcase, state) else {
return Ok(()); return Ok(());
}; };
drop(testcase); drop(testcase);
@ -307,11 +311,10 @@ impl<E, EM, I, M, S, Z> Named for MultiMutationalStage<E, EM, I, M, S, Z> {
impl<E, EM, I, M, S, Z> Stage<E, EM, S, Z> for MultiMutationalStage<E, EM, I, M, S, Z> impl<E, EM, I, M, S, Z> Stage<E, EM, S, Z> for MultiMutationalStage<E, EM, I, M, S, Z>
where where
I: Clone + MutatedTransform<I, S>,
M: MultiMutator<I, S>, M: MultiMutator<I, S>,
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>, S: HasRand + HasNamedMetadata + HasCurrentTestcase<I> + HasCurrentCorpusId,
S: HasCorpus + HasRand + HasNamedMetadata + HasCurrentTestcase + HasCurrentCorpusId, Z: Evaluator<E, EM, I, S>,
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone,
<S::Corpus as Corpus>::Input: Input,
{ {
#[inline] #[inline]
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> { fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {

View File

@ -11,10 +11,9 @@ use libafl_bolts::Named;
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
use crate::monitors::PerfFeature; use crate::monitors::PerfFeature;
use crate::{ use crate::{
corpus::{Corpus, HasCurrentCorpusId}, corpus::HasCurrentCorpusId,
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
fuzzer::Evaluator, fuzzer::Evaluator,
inputs::Input,
mark_feature_time, mark_feature_time,
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
schedulers::{testcase_score::CorpusPowerTestcaseScore, TestcaseScore}, schedulers::{testcase_score::CorpusPowerTestcaseScore, TestcaseScore},
@ -23,7 +22,7 @@ use crate::{
MutationalStage, RetryCountRestartHelper, Stage, MutationalStage, RetryCountRestartHelper, Stage,
}, },
start_timer, start_timer,
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, MaybeHasClientPerfMonitor}, state::{HasCurrentTestcase, HasExecutions, HasRand, MaybeHasClientPerfMonitor},
Error, HasMetadata, HasNamedMetadata, Error, HasMetadata, HasNamedMetadata,
}; };
@ -48,8 +47,8 @@ impl<E, F, EM, I, M, S, Z> Named for PowerMutationalStage<E, F, EM, I, M, S, Z>
impl<E, F, EM, I, M, S, Z> MutationalStage<S> for PowerMutationalStage<E, F, EM, I, M, S, Z> impl<E, F, EM, I, M, S, Z> MutationalStage<S> for PowerMutationalStage<E, F, EM, I, M, S, Z>
where where
S: HasCurrentTestcase, S: HasCurrentTestcase<I>,
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
{ {
type Mutator = M; type Mutator = M;
/// The mutator, added to this stage /// The mutator, added to this stage
@ -77,20 +76,18 @@ where
impl<E, F, EM, I, M, S, Z> Stage<E, EM, S, Z> for PowerMutationalStage<E, F, EM, I, M, S, Z> impl<E, F, EM, I, M, S, Z> Stage<E, EM, S, Z> for PowerMutationalStage<E, F, EM, I, M, S, Z>
where where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, E: Executor<EM, I, S, Z> + HasObservers,
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
M: Mutator<I, S>, M: Mutator<I, S>,
S: HasCorpus S: HasMetadata
+ HasMetadata
+ HasRand + HasRand
+ HasExecutions + HasExecutions
+ HasNamedMetadata + HasNamedMetadata
+ HasCurrentTestcase + HasCurrentTestcase<I>
+ HasCurrentCorpusId + HasCurrentCorpusId
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>, Z: Evaluator<E, EM, I, S>,
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone + Input, I: MutatedTransform<I, S> + Clone,
<S::Corpus as Corpus>::Input: Input,
{ {
#[inline] #[inline]
#[expect(clippy::let_and_return)] #[expect(clippy::let_and_return)]
@ -117,14 +114,12 @@ where
impl<E, F, EM, I, M, S, Z> PowerMutationalStage<E, F, EM, I, M, S, Z> impl<E, F, EM, I, M, S, Z> PowerMutationalStage<E, F, EM, I, M, S, Z>
where where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, E: Executor<EM, I, S, Z> + HasObservers,
F: TestcaseScore<S>, F: TestcaseScore<I, S>,
I: Input,
M: Mutator<I, S>, M: Mutator<I, S>,
S: HasCorpus + HasMetadata + HasRand + HasCurrentTestcase + MaybeHasClientPerfMonitor, S: HasMetadata + HasRand + HasCurrentTestcase<I> + MaybeHasClientPerfMonitor,
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone + Input, I: MutatedTransform<I, S> + Clone,
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>, Z: Evaluator<E, EM, I, S>,
<S::Corpus as Corpus>::Input: Input,
{ {
/// Creates a new [`PowerMutationalStage`] /// Creates a new [`PowerMutationalStage`]
pub fn new(mutator: M) -> Self { pub fn new(mutator: M) -> Self {

View File

@ -23,7 +23,7 @@ pub use mutational::StdMutationalPushStage;
use crate::{ use crate::{
common::HasNamedMetadata, common::HasNamedMetadata,
corpus::{Corpus, CorpusId, HasCurrentCorpusId}, corpus::{CorpusId, HasCurrentCorpusId},
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter}, events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
executors::{Executor, ExitKind, HasObservers}, executors::{Executor, ExitKind, HasObservers},
observers::ObserversTuple, observers::ObserversTuple,
@ -43,7 +43,7 @@ pub struct PushStageSharedState<EM, I, OT, S, Z> {
pub fuzzer: Z, pub fuzzer: Z,
/// The event manager /// The event manager
pub event_mgr: EM, pub event_mgr: EM,
/// The [`crate::observers::ObserversTuple`] /// The [`ObserversTuple`]
pub observers: OT, pub observers: OT,
phantom: PhantomData<I>, phantom: PhantomData<I>,
} }
@ -206,13 +206,13 @@ pub trait PushStage<EM, I, OT, S, Z> {
/// Allows us to use a [`PushStage`] as a normal [`Stage`] /// Allows us to use a [`PushStage`] as a normal [`Stage`]
#[derive(Debug)] #[derive(Debug)]
pub struct PushStageAdapter<CS, EM, OT, PS, Z> { pub struct PushStageAdapter<CS, EM, I, OT, PS, Z> {
name: Cow<'static, str>, name: Cow<'static, str>,
push_stage: PS, push_stage: PS,
phantom: PhantomData<(CS, EM, OT, Z)>, phantom: PhantomData<(CS, EM, I, OT, Z)>,
} }
impl<CS, EM, OT, PS, Z> PushStageAdapter<CS, EM, OT, PS, Z> { impl<CS, EM, I, OT, PS, Z> PushStageAdapter<CS, EM, I, OT, PS, Z> {
/// 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]
@ -237,35 +237,43 @@ static mut PUSH_STAGE_ADAPTER_ID: usize = 0;
/// The name for push stage adapter /// The name for push stage adapter
pub static PUSH_STAGE_ADAPTER_NAME: &str = "pushstageadapter"; pub static PUSH_STAGE_ADAPTER_NAME: &str = "pushstageadapter";
impl<CS, EM, OT, PS, Z> Named for PushStageAdapter<CS, EM, OT, PS, Z> { impl<CS, EM, I, OT, PS, Z> Named for PushStageAdapter<CS, EM, I, OT, PS, Z> {
#[must_use] #[must_use]
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
} }
impl<CS, E, EM, OT, PS, S, Z> Stage<E, EM, S, Z> for PushStageAdapter<CS, EM, OT, PS, Z> impl<CS, E, EM, I, OT, PS, S, Z> Stage<E, EM, S, Z> for PushStageAdapter<CS, EM, I, OT, PS, Z>
where where
CS: Scheduler<<S::Corpus as Corpus>::Input, S>, CS: Scheduler<I, S>,
S: HasExecutions S: HasExecutions
+ HasRand + HasRand
+ HasCorpus + HasCorpus<I>
+ HasLastReportTime + HasLastReportTime
+ HasCurrentCorpusId + HasCurrentCorpusId
+ HasNamedMetadata + HasNamedMetadata
+ HasMetadata, + HasMetadata,
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers<Observers = OT>, E: Executor<EM, I, S, Z> + HasObservers<Observers = OT>,
EM: EventFirer<<S::Corpus as Corpus>::Input, S> EM: EventFirer<I, S> + EventRestarter<S> + HasEventManagerId + ProgressReporter<S>,
+ EventRestarter<S> OT: ObserversTuple<I, S>,
+ HasEventManagerId PS: PushStage<EM, I, OT, S, Z>,
+ ProgressReporter<S>, Z: ExecutesInput<E, EM, I, S>
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>, + ExecutionProcessor<EM, I, OT, S>
PS: PushStage<EM, <S::Corpus as Corpus>::Input, OT, S, Z>, + EvaluatorObservers<E, EM, I, OT>
Z: ExecutesInput<E, EM, <S::Corpus as Corpus>::Input, S> + HasScheduler<I, S>,
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, OT, S>
+ EvaluatorObservers<E, EM, <S::Corpus as Corpus>::Input, OT>
+ HasScheduler<<S::Corpus as Corpus>::Input, S>,
{ {
#[inline]
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
// TODO: Proper restart handling - call post_exec at the right time, etc...
RetryCountRestartHelper::no_retry(state, &self.name)
}
#[inline]
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
RetryCountRestartHelper::clear_progress(state, &self.name)
}
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
@ -309,15 +317,4 @@ where
self.push_stage self.push_stage
.deinit(fuzzer, state, event_mgr, &mut *executor.observers_mut()) .deinit(fuzzer, state, event_mgr, &mut *executor.observers_mut())
} }
#[inline]
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
// TODO: Proper restart handling - call post_exec at the right time, etc...
RetryCountRestartHelper::no_retry(state, &self.name)
}
#[inline]
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
RetryCountRestartHelper::clear_progress(state, &self.name)
}
} }

View File

@ -43,10 +43,10 @@ pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128;
/// ///
/// The default mutational push stage /// The default mutational push stage
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StdMutationalPushStage<EM, M, OT, S, Z> pub struct StdMutationalPushStage<EM, M, I, OT, S, Z>
where where
S: HasCorpus, S: HasCorpus<I>,
<S::Corpus as Corpus>::Input: Clone + Debug, I: Clone + Debug,
{ {
current_corpus_id: Option<CorpusId>, current_corpus_id: Option<CorpusId>,
testcases_to_do: usize, testcases_to_do: usize,
@ -54,13 +54,13 @@ where
mutator: M, mutator: M,
psh: PushStageHelper<EM, <S::Corpus as Corpus>::Input, OT, S, Z>, psh: PushStageHelper<EM, I, OT, S, Z>,
} }
impl<EM, M, OT, S, Z> StdMutationalPushStage<EM, M, OT, S, Z> impl<EM, M, I, OT, S, Z> StdMutationalPushStage<EM, M, I, OT, S, Z>
where where
S: HasCorpus + HasRand, S: HasCorpus<I> + HasRand,
<S::Corpus as Corpus>::Input: Clone + Debug, I: Clone + Debug,
{ {
/// Gets the number of iterations as a random number /// Gets the number of iterations as a random number
#[expect(clippy::unused_self, clippy::unnecessary_wraps)] // TODO: we should put this function into a trait later #[expect(clippy::unused_self, clippy::unnecessary_wraps)] // TODO: we should put this function into a trait later
@ -76,26 +76,22 @@ where
} }
} }
impl<EM, M, OT, S, Z> PushStage<EM, <S::Corpus as Corpus>::Input, OT, S, Z> impl<EM, M, I, OT, S, Z> PushStage<EM, I, OT, S, Z> for StdMutationalPushStage<EM, M, I, OT, S, Z>
for StdMutationalPushStage<EM, M, OT, S, Z>
where where
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
Z: HasScheduler<<S::Corpus as Corpus>::Input, S> Z: HasScheduler<I, S> + ExecutionProcessor<EM, I, OT, S>,
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, OT, S>, S: HasCorpus<I> + HasRand + MaybeHasClientPerfMonitor,
S: HasCorpus + HasRand + MaybeHasClientPerfMonitor, M: Mutator<I, S>,
M: Mutator<<S::Corpus as Corpus>::Input, S>, OT: ObserversTuple<I, S> + Serialize,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize, I: Input + Clone,
<S::Corpus as Corpus>::Input: Input + Clone,
{ {
#[inline] #[inline]
fn push_stage_helper(&self) -> &PushStageHelper<EM, <S::Corpus as Corpus>::Input, OT, S, Z> { fn push_stage_helper(&self) -> &PushStageHelper<EM, I, OT, S, Z> {
&self.psh &self.psh
} }
#[inline] #[inline]
fn push_stage_helper_mut( fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<EM, I, OT, S, Z> {
&mut self,
) -> &mut PushStageHelper<EM, <S::Corpus as Corpus>::Input, OT, S, Z> {
&mut self.psh &mut self.psh
} }
@ -125,7 +121,7 @@ where
state: &mut S, state: &mut S,
_event_mgr: &mut EM, _event_mgr: &mut EM,
_observers: &mut OT, _observers: &mut OT,
) -> Option<Result<<S::Corpus as Corpus>::Input, Error>> { ) -> Option<Result<I, 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;
@ -160,7 +156,7 @@ where
state: &mut S, state: &mut S,
event_mgr: &mut EM, event_mgr: &mut EM,
observers: &mut OT, observers: &mut OT,
last_input: <S::Corpus as Corpus>::Input, last_input: I,
exit_kind: ExitKind, exit_kind: ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
// todo: is_interesting, etc. // todo: is_interesting, etc.
@ -188,51 +184,47 @@ where
} }
} }
impl<EM, M, OT, S, Z> Iterator for StdMutationalPushStage<EM, M, OT, S, Z> impl<EM, M, I, OT, S, Z> Iterator for StdMutationalPushStage<EM, M, I, OT, S, Z>
where where
EM: ProgressReporter<S> + EventFirer<<S::Corpus as Corpus>::Input, S>, EM: ProgressReporter<S> + EventFirer<I, S>,
S: HasCorpus S: HasCorpus<I>
+ HasMetadata + HasMetadata
+ HasExecutions + HasExecutions
+ HasLastReportTime + HasLastReportTime
+ HasRand + HasRand
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize, OT: ObserversTuple<I, S> + Serialize,
M: Mutator<<S::Corpus as Corpus>::Input, S>, M: Mutator<I, S>,
<S::Corpus as Corpus>::Input: Clone + Debug + Input, I: Clone + Debug + Input,
Z: HasScheduler<<S::Corpus as Corpus>::Input, S> Z: HasScheduler<I, S> + ExecutionProcessor<EM, I, OT, S>,
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, OT, S>,
{ {
type Item = Result<<S::Corpus as Corpus>::Input, Error>; type Item = Result<I, Error>;
fn next(&mut self) -> Option<Result<<S::Corpus as Corpus>::Input, Error>> { fn next(&mut self) -> Option<Result<I, Error>> {
self.next_std() self.next_std()
} }
} }
impl<EM, M, OT, S, Z> StdMutationalPushStage<EM, M, OT, S, Z> impl<EM, M, I, OT, S, Z> StdMutationalPushStage<EM, M, I, OT, S, Z>
where where
EM: ProgressReporter<S> + EventFirer<<S::Corpus as Corpus>::Input, S>, EM: ProgressReporter<S> + EventFirer<I, S>,
S: HasCorpus S: HasCorpus<I>
+ HasMetadata + HasMetadata
+ HasExecutions + HasExecutions
+ HasLastReportTime + HasLastReportTime
+ HasRand + HasRand
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize, OT: ObserversTuple<I, S> + Serialize,
M: Mutator<<S::Corpus as Corpus>::Input, S>, M: Mutator<I, S>,
<S::Corpus as Corpus>::Input: Clone + Debug + Input, I: Clone + Debug + Input,
Z: HasScheduler<<S::Corpus as Corpus>::Input, S> Z: HasScheduler<I, S> + ExecutionProcessor<EM, I, OT, S>,
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, OT, S>,
{ {
/// Creates a new default mutational stage /// Creates a new default mutational stage
#[must_use] #[must_use]
#[expect(clippy::type_complexity)] #[expect(clippy::type_complexity)]
pub fn new( pub fn new(
mutator: M, mutator: M,
shared_state: Rc< shared_state: Rc<RefCell<Option<PushStageSharedState<EM, I, OT, S, Z>>>>,
RefCell<Option<PushStageSharedState<EM, <S::Corpus as Corpus>::Input, OT, S, Z>>>,
>,
exit_kind: Rc<Cell<Option<ExitKind>>>, exit_kind: Rc<Cell<Option<ExitKind>>>,
) -> Self { ) -> Self {
Self { Self {
@ -245,7 +237,7 @@ where
} }
/// This is the implementation for `next` for this stage /// This is the implementation for `next` for this stage
pub fn next_std(&mut self) -> Option<Result<<S::Corpus as Corpus>::Input, Error>> { pub fn next_std(&mut self) -> Option<Result<I, 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

@ -52,31 +52,43 @@ 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, S, Z> { pub struct SyncFromDiskStage<CB, E, EM, I, S, Z> {
name: Cow<'static, str>, name: Cow<'static, str>,
sync_dirs: Vec<PathBuf>, sync_dirs: Vec<PathBuf>,
load_callback: CB, load_callback: CB,
interval: Duration, interval: Duration,
phantom: PhantomData<(E, EM, S, Z)>, phantom: PhantomData<(E, EM, I, S, Z)>,
} }
impl<CB, E, EM, S, Z> Named for SyncFromDiskStage<CB, E, EM, S, Z> { impl<CB, E, EM, I, S, Z> Named for SyncFromDiskStage<CB, E, EM, I, S, Z> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
} }
impl<CB, E, EM, S, Z> Stage<E, EM, S, Z> for SyncFromDiskStage<CB, E, EM, S, Z> impl<CB, E, EM, I, S, Z> Stage<E, EM, S, Z> for SyncFromDiskStage<CB, E, EM, I, S, Z>
where where
CB: FnMut(&mut Z, &mut S, &Path) -> Result<<S::Corpus as Corpus>::Input, Error>, CB: FnMut(&mut Z, &mut S, &Path) -> Result<I, Error>,
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>, Z: Evaluator<E, EM, I, S>,
S: HasCorpus S: HasCorpus<I>
+ HasRand + HasRand
+ HasMetadata + HasMetadata
+ HasNamedMetadata + HasNamedMetadata
+ HasCurrentCorpusId + HasCurrentCorpusId
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
{ {
#[inline]
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
// TODO: Needs proper crash handling for when an imported testcase crashes
// For now, Make sure we don't get stuck crashing on this testcase
RetryCountRestartHelper::no_retry(state, &self.name)
}
#[inline]
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
RetryCountRestartHelper::clear_progress(state, &self.name)
}
#[inline] #[inline]
fn perform( fn perform(
&mut self, &mut self,
@ -136,21 +148,9 @@ where
Ok(()) Ok(())
} }
#[inline]
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
// TODO: Needs proper crash handling for when an imported testcase crashes
// For now, Make sure we don't get stuck crashing on this testcase
RetryCountRestartHelper::no_retry(state, &self.name)
} }
#[inline] impl<CB, E, EM, I, S, Z> SyncFromDiskStage<CB, E, EM, I, S, Z> {
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
RetryCountRestartHelper::clear_progress(state, &self.name)
}
}
impl<CB, E, EM, S, Z> SyncFromDiskStage<CB, E, EM, S, Z> {
/// Creates a new [`SyncFromDiskStage`] /// Creates a new [`SyncFromDiskStage`]
#[must_use] #[must_use]
pub fn new(sync_dirs: Vec<PathBuf>, load_callback: CB, interval: Duration, name: &str) -> Self { pub fn new(sync_dirs: Vec<PathBuf>, load_callback: CB, interval: Duration, name: &str) -> Self {
@ -165,25 +165,21 @@ impl<CB, E, EM, S, Z> SyncFromDiskStage<CB, E, EM, S, Z> {
} }
/// 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<S, Z> = pub type SyncFromDiskFunction<I, S, Z> = fn(&mut Z, &mut S, &Path) -> Result<I, Error>;
fn(&mut Z, &mut S, &Path) -> Result<<<S as HasCorpus>::Corpus as Corpus>::Input, Error>;
impl<E, EM, S, Z> SyncFromDiskStage<SyncFromDiskFunction<S, Z>, E, EM, S, Z> impl<E, EM, I, S, Z> SyncFromDiskStage<SyncFromDiskFunction<I, S, Z>, E, EM, I, S, Z>
where where
S: HasCorpus, I: Input,
<S::Corpus as Corpus>::Input: Input, S: HasCorpus<I>,
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>, Z: Evaluator<E, EM, I, S>,
{ {
/// 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_dirs: Vec<PathBuf>, interval: Duration) -> Self { pub fn with_from_file(sync_dirs: Vec<PathBuf>, interval: Duration) -> Self {
fn load_callback<S: HasCorpus, Z>( fn load_callback<I, S, Z>(_: &mut Z, _: &mut S, p: &Path) -> Result<I, Error>
_: &mut Z,
_: &mut S,
p: &Path,
) -> Result<<S::Corpus as Corpus>::Input, Error>
where where
<S::Corpus as Corpus>::Input: Input, I: Input,
S: HasCorpus<I>,
{ {
Input::from_file(p) Input::from_file(p)
} }
@ -191,7 +187,7 @@ where
interval, interval,
name: Cow::Borrowed(SYNC_FROM_DISK_STAGE_NAME), name: Cow::Borrowed(SYNC_FROM_DISK_STAGE_NAME),
sync_dirs, sync_dirs,
load_callback: load_callback::<_, _>, load_callback: load_callback::<_, _, _>,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -220,27 +216,38 @@ impl SyncFromBrokerMetadata {
/// 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 SyncFromBrokerStage<IC, ICB, S, SP> pub struct SyncFromBrokerStage<I, IC, ICB, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
client: LlmpEventConverter<IC, ICB, S, SP>, client: LlmpEventConverter<I, IC, ICB, S, SP>,
} }
impl<E, EM, IC, ICB, DI, S, SP, Z> Stage<E, EM, S, Z> for SyncFromBrokerStage<IC, ICB, S, SP> impl<E, EM, I, IC, ICB, DI, S, SP, Z> Stage<E, EM, S, Z> for SyncFromBrokerStage<I, IC, ICB, S, SP>
where where
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
S: HasExecutions + HasCorpus + HasRand + HasMetadata + Stoppable + MaybeHasClientPerfMonitor,
SP: ShMemProvider,
E: HasObservers + Executor<EM, <S::Corpus as Corpus>::Input, S, Z>,
for<'a> E::Observers: Deserialize<'a>,
Z: EvaluatorObservers<E, EM, <S::Corpus as Corpus>::Input, S>
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
IC: InputConverter<From = <S::Corpus as Corpus>::Input, To = DI>,
ICB: InputConverter<From = DI, To = <S::Corpus as Corpus>::Input>,
DI: Input, DI: Input,
<<S as HasCorpus>::Corpus as Corpus>::Input: Input + Clone, EM: EventFirer<I, S>,
E: HasObservers + Executor<EM, I, S, Z>,
for<'a> E::Observers: Deserialize<'a>,
I: Input + Clone,
IC: InputConverter<From = I, To = DI>,
ICB: InputConverter<From = DI, To = I>,
S: HasExecutions + HasCorpus<I> + HasRand + HasMetadata + Stoppable + MaybeHasClientPerfMonitor,
SP: ShMemProvider,
Z: EvaluatorObservers<E, EM, I, S> + ExecutionProcessor<EM, I, E::Observers, S>,
{ {
#[inline]
fn should_restart(&mut self, _state: &mut S) -> Result<bool, Error> {
// No restart handling needed - does not execute the target.
Ok(true)
}
#[inline]
fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> {
// Not needed - does not execute the target.
Ok(())
}
#[inline] #[inline]
fn perform( fn perform(
&mut self, &mut self,
@ -298,27 +305,15 @@ where
state.introspection_monitor_mut().finish_stage(); state.introspection_monitor_mut().finish_stage();
Ok(()) Ok(())
} }
#[inline]
fn should_restart(&mut self, _state: &mut S) -> Result<bool, Error> {
// No restart handling needed - does not execute the target.
Ok(true)
} }
#[inline] impl<I, IC, ICB, S, SP> SyncFromBrokerStage<I, IC, ICB, S, SP>
fn clear_progress(&mut self, _state: &mut S) -> Result<(), Error> {
// Not needed - does not execute the target.
Ok(())
}
}
impl<IC, ICB, S, SP> SyncFromBrokerStage<IC, ICB, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
{ {
/// Creates a new [`SyncFromBrokerStage`] /// Creates a new [`SyncFromBrokerStage`]
#[must_use] #[must_use]
pub fn new(client: LlmpEventConverter<IC, ICB, S, SP>) -> Self { pub fn new(client: LlmpEventConverter<I, IC, ICB, S, SP>) -> Self {
Self { client } Self { client }
} }
} }

View File

@ -43,7 +43,7 @@ use crate::{
/// The default corpus entry minimising mutational stage /// The default corpus entry minimising mutational stage
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StdTMinMutationalStage<E, EM, F, FF, M, S, Z> { pub struct StdTMinMutationalStage<E, EM, F, FF, I, M, S, Z> {
/// The name /// The name
name: Cow<'static, str>, name: Cow<'static, str>,
/// The mutator(s) this stage uses /// The mutator(s) this stage uses
@ -54,39 +54,40 @@ pub struct StdTMinMutationalStage<E, EM, F, FF, M, S, Z> {
runs: usize, runs: usize,
/// The progress helper for this stage, keeping track of resumes after timeouts/crashes /// The progress helper for this stage, keeping track of resumes after timeouts/crashes
restart_helper: ExecutionCountRestartHelper, restart_helper: ExecutionCountRestartHelper,
phantom: PhantomData<(E, EM, F, S, Z)>, phantom: PhantomData<(E, EM, F, I, S, Z)>,
} }
impl<E, EM, F, FF, M, S, Z> Stage<E, EM, S, Z> for StdTMinMutationalStage<E, EM, F, FF, M, S, Z> impl<E, EM, F, FF, I, M, S, Z> Stage<E, EM, S, Z>
for StdTMinMutationalStage<E, EM, F, FF, I, M, S, Z>
where where
Z: HasScheduler<<S::Corpus as Corpus>::Input, S> Z: HasScheduler<I, S>
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, E::Observers, S> + ExecutionProcessor<EM, I, E::Observers, S>
+ ExecutesInput<E, EM, <S::Corpus as Corpus>::Input, S> + ExecutesInput<E, EM, I, S>
+ HasFeedback, + HasFeedback,
Z::Scheduler: RemovableScheduler<<S::Corpus as Corpus>::Input, S>, Z::Scheduler: RemovableScheduler<I, S>,
E: HasObservers, E: HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize, E::Observers: ObserversTuple<I, S> + Serialize,
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
FF: FeedbackFactory<F, E::Observers>, FF: FeedbackFactory<F, E::Observers>,
F: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>, F: Feedback<EM, I, E::Observers, S>,
S: HasMetadata S: HasMetadata
+ HasCorpus<I>
+ HasExecutions + HasExecutions
+ HasSolutions + HasSolutions<I>
+ HasCorpus
+ HasMaxSize + HasMaxSize
+ HasNamedMetadata + HasNamedMetadata
+ HasCurrentCorpusId + HasCurrentCorpusId
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
Z::Feedback: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>, Z::Feedback: Feedback<EM, I, E::Observers, S>,
M: Mutator<<S::Corpus as Corpus>::Input, S>, M: Mutator<I, S>,
<<S as HasCorpus>::Corpus as Corpus>::Input: Input + Hash + HasLen, I: Input + Hash + HasLen,
{ {
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> { fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
self.restart_helper.should_restart(state, &self.name) self.restart_helper.should_restart(state, &self.name)
} }
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
self.restart_helper.clear_progress(state, &self.name) self.restart_helper.clear_progress::<S>(state, &self.name)
} }
fn perform( fn perform(
@ -105,8 +106,8 @@ where
} }
} }
impl<E, EM, F, FF, M, S, Z> FeedbackFactory<F, E::Observers> impl<E, EM, F, FF, I, M, S, Z> FeedbackFactory<F, E::Observers>
for StdTMinMutationalStage<E, EM, F, FF, M, S, Z> for StdTMinMutationalStage<E, EM, F, FF, I, M, S, Z>
where where
E: HasObservers, E: HasObservers,
FF: FeedbackFactory<F, E::Observers>, FF: FeedbackFactory<F, E::Observers>,
@ -116,7 +117,7 @@ where
} }
} }
impl<E, EM, F, FF, M, S, Z> Named for StdTMinMutationalStage<E, EM, F, FF, M, S, Z> { impl<E, EM, F, FF, I, M, S, Z> Named for StdTMinMutationalStage<E, EM, F, FF, I, M, S, Z> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
@ -127,30 +128,30 @@ static mut TMIN_STAGE_ID: usize = 0;
/// The name for tmin stage /// The name for tmin stage
pub static TMIN_STAGE_NAME: &str = "tmin"; pub static TMIN_STAGE_NAME: &str = "tmin";
impl<E, EM, F, FF, M, S, Z> StdTMinMutationalStage<E, EM, F, FF, M, S, Z> impl<E, EM, F, FF, I, M, S, Z> StdTMinMutationalStage<E, EM, F, FF, I, M, S, Z>
where where
Z: HasScheduler<<S::Corpus as Corpus>::Input, S> Z: HasScheduler<I, S>
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, E::Observers, S> + ExecutionProcessor<EM, I, E::Observers, S>
+ ExecutesInput<E, EM, <S::Corpus as Corpus>::Input, S> + ExecutesInput<E, EM, I, S>
+ HasFeedback, + HasFeedback,
Z::Scheduler: RemovableScheduler<<S::Corpus as Corpus>::Input, S>, Z::Scheduler: RemovableScheduler<I, S>,
E: HasObservers, E: HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize, E::Observers: ObserversTuple<I, S> + Serialize,
EM: EventFirer<<S::Corpus as Corpus>::Input, S>, EM: EventFirer<I, S>,
FF: FeedbackFactory<F, E::Observers>, FF: FeedbackFactory<F, E::Observers>,
F: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>, F: Feedback<EM, I, E::Observers, S>,
S: HasMetadata S: HasMetadata
+ HasExecutions + HasExecutions
+ HasSolutions + HasSolutions<I>
+ HasCorpus + HasCorpus<I>
+ HasMaxSize + HasMaxSize
+ HasNamedMetadata + HasNamedMetadata
+ HasCurrentTestcase + HasCurrentTestcase<I>
+ HasCurrentCorpusId + HasCurrentCorpusId
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
Z::Feedback: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>, Z::Feedback: Feedback<EM, I, E::Observers, S>,
M: Mutator<<S::Corpus as Corpus>::Input, S>, M: Mutator<I, S>,
<S::Corpus as Corpus>::Input: Hash + HasLen + Input, I: Hash + HasLen + Input,
{ {
/// The list of mutators, added to this stage (as mutable ref) /// The list of mutators, added to this stage (as mutable ref)
#[inline] #[inline]
@ -189,10 +190,7 @@ where
} }
start_timer!(state); start_timer!(state);
let transformed = <S::Corpus as Corpus>::Input::try_transform_from( let transformed = I::try_transform_from(state.current_testcase_mut()?.borrow_mut(), state)?;
state.current_testcase_mut()?.borrow_mut(),
state,
)?;
let mut base = state.current_input_cloned()?; let mut base = state.current_input_cloned()?;
// potential post operation if base is replaced by a shorter input // potential post operation if base is replaced by a shorter input
let mut base_post = None; let mut base_post = None;
@ -310,7 +308,7 @@ where
} }
} }
impl<E, EM, F, FF, M, S, Z> StdTMinMutationalStage<E, EM, F, FF, M, S, Z> { impl<E, EM, F, FF, I, M, S, Z> StdTMinMutationalStage<E, EM, F, FF, I, M, S, Z> {
/// Creates a new minimizing mutational stage that will minimize provided corpus entries /// Creates a new minimizing 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 {
// unsafe but impossible that you create two threads both instantiating this instance // unsafe but impossible that you create two threads both instantiating this instance
@ -391,12 +389,12 @@ where
/// A feedback factory for ensuring that the values of the observers for minimized inputs are the same /// A feedback factory for ensuring that the values of the observers for minimized inputs are the same
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ObserverEqualityFactory<C, M, S> { pub struct ObserverEqualityFactory<C, I, M, S> {
observer_handle: Handle<C>, observer_handle: Handle<C>,
phantom: PhantomData<(C, M, S)>, phantom: PhantomData<(C, I, M, S)>,
} }
impl<C, M, S> ObserverEqualityFactory<C, M, S> impl<C, I, M, S> ObserverEqualityFactory<C, I, M, S>
where where
M: Hash, M: Hash,
C: AsRef<M> + Handled, C: AsRef<M> + Handled,
@ -410,7 +408,7 @@ where
} }
} }
impl<C, M, S> HasObserverHandle for ObserverEqualityFactory<C, M, S> { impl<C, I, M, S> HasObserverHandle for ObserverEqualityFactory<C, I, M, S> {
type Observer = C; type Observer = C;
fn observer_handle(&self) -> &Handle<C> { fn observer_handle(&self) -> &Handle<C> {
@ -418,13 +416,13 @@ impl<C, M, S> HasObserverHandle for ObserverEqualityFactory<C, M, S> {
} }
} }
impl<C, M, OT, S> FeedbackFactory<ObserverEqualityFeedback<C, M, S>, OT> impl<C, I, M, OT, S> FeedbackFactory<ObserverEqualityFeedback<C, M, S>, OT>
for ObserverEqualityFactory<C, M, S> for ObserverEqualityFactory<C, I, M, S>
where where
M: Hash, M: Hash,
C: AsRef<M> + Handled, C: AsRef<M> + Handled,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>, OT: ObserversTuple<I, S>,
S: HasCorpus, S: HasCorpus<I>,
{ {
fn create_feedback(&self, observers: &OT) -> ObserverEqualityFeedback<C, M, S> { fn create_feedback(&self, observers: &OT) -> ObserverEqualityFeedback<C, M, S> {
let obs = observers let obs = observers

View File

@ -11,7 +11,7 @@ use libafl_bolts::Named;
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
use crate::monitors::PerfFeature; use crate::monitors::PerfFeature;
use crate::{ use crate::{
corpus::{Corpus, HasCurrentCorpusId}, corpus::HasCurrentCorpusId,
executors::{Executor, HasObservers, ShadowExecutor}, executors::{Executor, HasObservers, ShadowExecutor},
inputs::Input, inputs::Input,
mark_feature_time, mark_feature_time,
@ -24,20 +24,20 @@ use crate::{
/// A stage that runs a tracer executor /// A stage that runs a tracer executor
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct TracingStage<EM, TE, S, Z> { pub struct TracingStage<EM, I, TE, S, Z> {
name: Cow<'static, str>, name: Cow<'static, str>,
tracer_executor: TE, tracer_executor: TE,
phantom: PhantomData<(EM, TE, S, Z)>, phantom: PhantomData<(EM, I, TE, S, Z)>,
} }
impl<EM, TE, S, Z> TracingStage<EM, TE, S, Z> impl<EM, I, TE, S, Z> TracingStage<EM, I, TE, S, Z>
where where
TE: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, TE: Executor<EM, I, S, Z> + HasObservers,
TE::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>, TE::Observers: ObserversTuple<I, S>,
S: HasExecutions S: HasExecutions
+ HasCorpus + HasCorpus<I>
+ HasNamedMetadata + HasNamedMetadata
+ HasCurrentTestcase + HasCurrentTestcase<I>
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
{ {
/// Perform tracing on the given `CorpusId`. Useful for if wrapping [`TracingStage`] with your /// Perform tracing on the given `CorpusId`. Useful for if wrapping [`TracingStage`] with your
@ -72,16 +72,16 @@ where
} }
} }
impl<E, EM, TE, S, Z> Stage<E, EM, S, Z> for TracingStage<EM, TE, S, Z> impl<E, EM, I, TE, S, Z> Stage<E, EM, S, Z> for TracingStage<EM, I, TE, S, Z>
where where
TE: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, TE: Executor<EM, I, S, Z> + HasObservers,
TE::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>, TE::Observers: ObserversTuple<I, S>,
S: HasExecutions S: HasExecutions
+ HasCorpus + HasCorpus<I>
+ HasNamedMetadata + HasNamedMetadata
+ HasCurrentCorpusId + HasCurrentCorpusId
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
<S::Corpus as Corpus>::Input: Input, I: Input,
{ {
#[inline] #[inline]
fn perform( fn perform(
@ -103,7 +103,7 @@ where
} }
} }
impl<EM, TE, S, Z> Named for TracingStage<EM, TE, S, Z> { impl<EM, I, TE, S, Z> Named for TracingStage<EM, I, TE, S, Z> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
@ -114,7 +114,7 @@ static mut TRACING_STAGE_ID: usize = 0;
/// The name for tracing stage /// The name for tracing stage
pub static TRACING_STAGE_NAME: &str = "tracing"; pub static TRACING_STAGE_NAME: &str = "tracing";
impl<EM, TE, S, Z> TracingStage<EM, TE, S, Z> { impl<EM, I, TE, S, Z> TracingStage<EM, I, TE, S, Z> {
/// Creates a new default stage /// Creates a new default stage
pub fn new(tracer_executor: TE) -> Self { pub fn new(tracer_executor: TE) -> Self {
// unsafe but impossible that you create two threads both instantiating this instance // unsafe but impossible that you create two threads both instantiating this instance
@ -144,9 +144,9 @@ impl<EM, TE, S, Z> TracingStage<EM, TE, S, Z> {
/// 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, SOT, S, Z> { pub struct ShadowTracingStage<E, EM, I, SOT, S, Z> {
name: Cow<'static, str>, name: Cow<'static, str>,
phantom: PhantomData<(E, EM, SOT, S, Z)>, phantom: PhantomData<(E, EM, I, SOT, S, Z)>,
} }
/// The counter for giving this stage unique id /// The counter for giving this stage unique id
@ -154,31 +154,39 @@ static mut SHADOW_TRACING_STAGE_ID: usize = 0;
/// Name for shadow tracing stage /// Name for shadow tracing stage
pub static SHADOW_TRACING_STAGE_NAME: &str = "shadow"; pub static SHADOW_TRACING_STAGE_NAME: &str = "shadow";
impl<E, EM, SOT, S, Z> Named for ShadowTracingStage<E, EM, SOT, S, Z> { impl<E, EM, I, SOT, S, Z> Named for ShadowTracingStage<E, EM, I, SOT, S, Z> {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
&self.name &self.name
} }
} }
impl<E, EM, SOT, S, Z> Stage<ShadowExecutor<E, S, SOT>, EM, S, Z> impl<E, EM, I, SOT, S, Z> Stage<ShadowExecutor<E, I, S, SOT>, EM, S, Z>
for ShadowTracingStage<E, EM, SOT, S, Z> for ShadowTracingStage<E, EM, I, SOT, S, Z>
where where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>, E::Observers: ObserversTuple<I, S>,
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>, SOT: ObserversTuple<I, S>,
S: HasExecutions S: HasExecutions
+ HasCorpus + HasCorpus<I>
+ HasNamedMetadata + HasNamedMetadata
+ Debug + Debug
+ HasCurrentTestcase + HasCurrentTestcase<I>
+ HasCurrentCorpusId + HasCurrentCorpusId
+ MaybeHasClientPerfMonitor, + MaybeHasClientPerfMonitor,
{ {
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
RetryCountRestartHelper::no_retry(state, &self.name)
}
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
RetryCountRestartHelper::clear_progress(state, &self.name)
}
#[inline] #[inline]
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut ShadowExecutor<E, S, SOT>, executor: &mut ShadowExecutor<E, I, S, SOT>,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -209,24 +217,16 @@ where
Ok(()) Ok(())
} }
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
RetryCountRestartHelper::no_retry(state, &self.name)
} }
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> { impl<E, EM, I, SOT, S, Z> ShadowTracingStage<E, EM, I, SOT, S, Z>
RetryCountRestartHelper::clear_progress(state, &self.name)
}
}
impl<E, EM, SOT, S, Z> ShadowTracingStage<E, EM, SOT, S, Z>
where where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers, E: Executor<EM, I, S, Z> + HasObservers,
S: HasExecutions + HasCorpus, S: HasExecutions + HasCorpus<I>,
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>, SOT: ObserversTuple<I, S>,
{ {
/// Creates a new default stage /// Creates a new default stage
pub fn new(_executor: &mut ShadowExecutor<E, S, SOT>) -> Self { pub fn new(_executor: &mut ShadowExecutor<E, I, S, SOT>) -> Self {
// unsafe but impossible that you create two threads both instantiating this instance // unsafe but impossible that you create two threads both instantiating this instance
let stage_id = unsafe { let stage_id = unsafe {
let ret = SHADOW_TRACING_STAGE_ID; let ret = SHADOW_TRACING_STAGE_ID;

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