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:
parent
d4add04f87
commit
f8ad61e14a
2
.github/workflows/build_and_test.yml
vendored
2
.github/workflows/build_and_test.yml
vendored
@ -290,7 +290,7 @@ jobs:
|
||||
- ./fuzzers/structure_aware/forkserver_simple_nautilus
|
||||
|
||||
# In-process
|
||||
# - ./fuzzers/fuzz_anything/cargo_fuzz # Revive after they fix rustc
|
||||
- ./fuzzers/fuzz_anything/cargo_fuzz
|
||||
# - ./fuzzers/inprocess/dynamic_analysis
|
||||
- ./fuzzers/inprocess/fuzzbench
|
||||
- ./fuzzers/inprocess/fuzzbench_text
|
||||
|
@ -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
|
||||
- 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.
|
||||
- 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
|
||||
pub struct X<A>
|
||||
where
|
||||
@ -35,9 +35,8 @@ pub struct X<A>
|
||||
{
|
||||
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
|
||||
pub struct X<A>
|
||||
where
|
||||
@ -45,17 +44,37 @@ pub struct X<A>
|
||||
{
|
||||
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
|
||||
pub trait X
|
||||
{
|
||||
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.
|
||||
```rust
|
||||
pub trait X<A, B, C> // <- this trait have 3 generics, A, B, and C
|
||||
|
@ -14,7 +14,9 @@
|
||||
- Trait restrictions have been simplified
|
||||
- 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 `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
|
||||
- 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`
|
||||
|
@ -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
|
||||
S: HasCorpus + HasExecutions,
|
||||
<S::Corpus as Corpus>::Input: HasTargetBytes,
|
||||
S: HasCorpus<I> + HasExecutions,
|
||||
I: HasTargetBytes,
|
||||
{
|
||||
fn run_target(
|
||||
&mut self,
|
||||
_fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
_mgr: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, libafl::Error> {
|
||||
// We need to keep track of the exec count.
|
||||
*state.executions_mut() += 1;
|
||||
|
@ -13,7 +13,10 @@ use libafl::{
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback},
|
||||
fuzzer::{Fuzzer, StdFuzzer},
|
||||
inputs::{BytesInput, HasTargetBytes},
|
||||
mutators::{StdScheduledMutator, UnicodeCategoryRandMutator, UnicodeSubcategoryRandMutator},
|
||||
mutators::{
|
||||
StdScheduledMutator, UnicodeCategoryRandMutator, UnicodeInput,
|
||||
UnicodeSubcategoryRandMutator,
|
||||
},
|
||||
observers::StdMapObserver,
|
||||
schedulers::QueueScheduler,
|
||||
stages::{mutational::StdMutationalStage, UnicodeIdentificationStage},
|
||||
@ -134,7 +137,7 @@ pub fn main() {
|
||||
));
|
||||
let mut stages = tuple_list!(
|
||||
UnicodeIdentificationStage::new(),
|
||||
StdMutationalStage::transforming(mutator)
|
||||
StdMutationalStage::<_, _, UnicodeInput, BytesInput, _, _, _>::transforming(mutator)
|
||||
);
|
||||
|
||||
fuzzer
|
||||
|
@ -1,11 +1,10 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use libafl::{
|
||||
corpus::{Corpus, Testcase},
|
||||
corpus::Testcase,
|
||||
executors::ExitKind,
|
||||
feedbacks::{Feedback, MapIndexesMetadata, StateInitializer},
|
||||
schedulers::{MinimizerScheduler, TestcaseScore},
|
||||
state::HasCorpus,
|
||||
Error, HasMetadata,
|
||||
};
|
||||
use libafl_bolts::{Named, SerdeAny};
|
||||
@ -20,14 +19,11 @@ pub struct PacketLenMetadata {
|
||||
|
||||
pub struct PacketLenTestcaseScore {}
|
||||
|
||||
impl<S> TestcaseScore<S> for PacketLenTestcaseScore
|
||||
impl<I, S> TestcaseScore<I, S> for PacketLenTestcaseScore
|
||||
where
|
||||
S: HasMetadata + HasCorpus,
|
||||
S: HasMetadata,
|
||||
{
|
||||
fn compute(
|
||||
_state: &S,
|
||||
entry: &mut Testcase<<S::Corpus as Corpus>::Input>,
|
||||
) -> Result<f64, Error> {
|
||||
fn compute(_state: &S, entry: &mut Testcase<I>) -> Result<f64, Error> {
|
||||
Ok(entry
|
||||
.metadata_map()
|
||||
.get::<PacketLenMetadata>()
|
||||
@ -35,8 +31,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub type PacketLenMinimizerScheduler<CS, S> =
|
||||
MinimizerScheduler<CS, PacketLenTestcaseScore, MapIndexesMetadata, S>;
|
||||
pub type PacketLenMinimizerScheduler<CS, I, S> =
|
||||
MinimizerScheduler<CS, PacketLenTestcaseScore, I, MapIndexesMetadata, S>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
||||
pub struct PacketLenFeedback {
|
||||
|
@ -96,7 +96,7 @@ unsafe fn fuzz(
|
||||
let shmem_provider = StdShMemProvider::new()?;
|
||||
|
||||
let mut run_client = |state: Option<_>,
|
||||
mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
client_description: ClientDescription| {
|
||||
// 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()) {
|
||||
(|state: Option<_>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
_client_description| {
|
||||
let gum = Gum::obtain();
|
||||
|
||||
@ -231,7 +231,7 @@ unsafe fn fuzz(
|
||||
})(state, mgr, client_description)
|
||||
} else if options.cmplog && options.cmplog_cores.contains(client_description.core_id()) {
|
||||
(|state: Option<_>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
_client_description| {
|
||||
let gum = Gum::obtain();
|
||||
|
||||
@ -367,7 +367,7 @@ unsafe fn fuzz(
|
||||
})(state, mgr, client_description)
|
||||
} else {
|
||||
(|state: Option<_>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
_client_description| {
|
||||
let gum = Gum::obtain();
|
||||
|
||||
|
@ -81,7 +81,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
};
|
||||
|
||||
let mut run_client = |state: Option<_>,
|
||||
mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
client_description: ClientDescription| {
|
||||
// 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()) {
|
||||
(|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _>, _client_description| {
|
||||
(|state: Option<_>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
_client_description| {
|
||||
let gum = Gum::obtain();
|
||||
|
||||
let coverage = CoverageRuntime::new();
|
||||
|
@ -78,7 +78,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
let shmem_provider = StdShMemProvider::new()?;
|
||||
|
||||
let mut run_client = |state: Option<_>,
|
||||
mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
client_description: ClientDescription| {
|
||||
// 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()) {
|
||||
(|state: Option<_>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
_client_description| {
|
||||
let gum = Gum::obtain();
|
||||
|
||||
@ -214,7 +214,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
})(state, mgr, client_description)
|
||||
} else if options.cmplog && options.cmplog_cores.contains(client_description.core_id()) {
|
||||
(|state: Option<_>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
_client_description| {
|
||||
let gum = Gum::obtain();
|
||||
|
||||
@ -344,7 +344,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
|
||||
})(state, mgr, client_description)
|
||||
} else {
|
||||
(|state: Option<_>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
_client_description| {
|
||||
let gum = Gum::obtain();
|
||||
|
||||
|
@ -9,8 +9,7 @@ use clap::{builder::Str, Parser};
|
||||
use libafl::{
|
||||
corpus::{Corpus, InMemoryCorpus},
|
||||
events::{
|
||||
launcher::Launcher, ClientDescription, EventConfig, EventRestarter,
|
||||
LlmpRestartingEventManager, ManagerExit,
|
||||
launcher::Launcher, ClientDescription, EventConfig, LlmpRestartingEventManager, ManagerExit,
|
||||
},
|
||||
executors::ExitKind,
|
||||
fuzzer::StdFuzzer,
|
||||
@ -31,7 +30,7 @@ use libafl_bolts::{
|
||||
use libafl_qemu::{
|
||||
elf::EasyElf,
|
||||
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,
|
||||
};
|
||||
|
||||
@ -124,7 +123,7 @@ pub fn fuzz() {
|
||||
env::remove_var("LD_LIBRARY_PATH");
|
||||
|
||||
let mut run_client = |state: Option<_>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
mut mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
client_description: ClientDescription| {
|
||||
let mut cov_path = options.coverage_path.clone();
|
||||
|
||||
|
@ -23,7 +23,7 @@ use crate::{
|
||||
|
||||
#[expect(clippy::module_name_repetitions)]
|
||||
pub type ClientState =
|
||||
StdState<BytesInput, InMemoryOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>;
|
||||
StdState<InMemoryOnDiskCorpus<BytesInput>, BytesInput, StdRand, OnDiskCorpus<BytesInput>>;
|
||||
|
||||
pub struct Client<'a> {
|
||||
options: &'a FuzzerOptions,
|
||||
|
@ -52,13 +52,15 @@ use typed_builder::TypedBuilder;
|
||||
use crate::{harness::Harness, options::FuzzerOptions};
|
||||
|
||||
pub type ClientState =
|
||||
StdState<BytesInput, InMemoryOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>;
|
||||
StdState<InMemoryOnDiskCorpus<BytesInput>, BytesInput, StdRand, OnDiskCorpus<BytesInput>>;
|
||||
|
||||
#[cfg(feature = "simplemgr")]
|
||||
pub type ClientMgr<M> = SimpleEventManager<M, ClientState>;
|
||||
#[cfg(not(feature = "simplemgr"))]
|
||||
pub type ClientMgr<M> =
|
||||
MonitorTypedEventManager<LlmpRestartingEventManager<(), ClientState, StdShMemProvider>, M>;
|
||||
pub type ClientMgr<M> = MonitorTypedEventManager<
|
||||
LlmpRestartingEventManager<(), BytesInput, ClientState, StdShMemProvider>,
|
||||
M,
|
||||
>;
|
||||
|
||||
#[derive(TypedBuilder)]
|
||||
pub struct Instance<'a, M: Monitor> {
|
||||
@ -321,7 +323,7 @@ impl<M: Monitor> Instance<'_, M> {
|
||||
stages: &mut ST,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
Z: Fuzzer<E, ClientMgr<M>, ClientState, ST>
|
||||
Z: Fuzzer<E, ClientMgr<M>, BytesInput, ClientState, ST>
|
||||
+ Evaluator<E, ClientMgr<M>, BytesInput, ClientState>,
|
||||
ST: StagesTuple<E, ClientMgr<M>, ClientState, Z>,
|
||||
{
|
||||
|
@ -376,7 +376,7 @@ fn fuzz(
|
||||
|
||||
let cb = |_fuzzer: &mut _,
|
||||
_executor: &mut _,
|
||||
state: &mut StdState<_, InMemoryOnDiskCorpus<_>, _, _>,
|
||||
state: &mut StdState<InMemoryOnDiskCorpus<_>, _, _, _>,
|
||||
_event_manager: &mut _|
|
||||
-> Result<bool, Error> {
|
||||
let testcase = state.current_testcase()?;
|
||||
|
@ -6,7 +6,6 @@ use std::{
|
||||
};
|
||||
|
||||
use libafl::{
|
||||
corpus::Corpus,
|
||||
executors::{Executor, ExitKind, HasObservers, HasTimeout},
|
||||
state::HasCorpus,
|
||||
Error,
|
||||
@ -253,25 +252,23 @@ fn check_file_found(file: &Path, perm: u32) -> bool {
|
||||
}
|
||||
|
||||
#[cfg(feature = "nyx")]
|
||||
pub enum SupportedExecutors<S, OT, FSV, NYX> {
|
||||
Forkserver(FSV, PhantomData<(S, OT, NYX)>),
|
||||
pub enum SupportedExecutors<FSV, I, OT, NYX> {
|
||||
Forkserver(FSV, PhantomData<(FSV, I, OT)>),
|
||||
Nyx(NYX),
|
||||
}
|
||||
|
||||
#[cfg(feature = "nyx")]
|
||||
impl<S, OT, FSV, NYX, EM, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z>
|
||||
for SupportedExecutors<S, OT, FSV, NYX>
|
||||
impl<S, I, OT, FSV, NYX, EM, Z> Executor<EM, I, S, Z> for SupportedExecutors<FSV, I, OT, NYX>
|
||||
where
|
||||
S: HasCorpus,
|
||||
NYX: Executor<EM, <S::Corpus as Corpus>::Input, S, Z>,
|
||||
FSV: Executor<EM, <S::Corpus as Corpus>::Input, S, Z>,
|
||||
NYX: Executor<EM, I, S, Z>,
|
||||
FSV: Executor<EM, I, S, Z>,
|
||||
{
|
||||
fn run_target(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
mgr: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input),
|
||||
@ -282,7 +279,7 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
NYX: HasObservers<Observers = OT>,
|
||||
FSV: HasObservers<Observers = OT>,
|
||||
@ -308,7 +305,7 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
FSV: HasTimeout,
|
||||
NYX: HasTimeout,
|
||||
@ -330,23 +327,22 @@ where
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nyx"))]
|
||||
pub enum SupportedExecutors<S, OT, FSV> {
|
||||
Forkserver(FSV, PhantomData<(S, OT)>),
|
||||
pub enum SupportedExecutors<FSV, I, OT, S> {
|
||||
Forkserver(FSV, PhantomData<(I, OT, S)>),
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nyx"))]
|
||||
impl<S, OT, FSV, EM, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z>
|
||||
for SupportedExecutors<S, OT, FSV>
|
||||
impl<S, I, OT, FSV, EM, Z> Executor<EM, I, S, Z> for SupportedExecutors<FSV, I, OT, S>
|
||||
where
|
||||
S: HasCorpus,
|
||||
FSV: Executor<EM, <S::Corpus as Corpus>::Input, S, Z>,
|
||||
S: HasCorpus<I>,
|
||||
FSV: Executor<EM, I, S, Z>,
|
||||
{
|
||||
fn run_target(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
mgr: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
match self {
|
||||
Self::Forkserver(fsrv, _) => fsrv.run_target(fuzzer, state, mgr, input),
|
||||
@ -355,7 +351,7 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
FSV: HasObservers<Observers = OT>,
|
||||
{
|
||||
@ -376,7 +372,7 @@ where
|
||||
}
|
||||
|
||||
#[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
|
||||
FSV: HasTimeout,
|
||||
{
|
||||
|
@ -4,10 +4,9 @@ use std::{
|
||||
};
|
||||
|
||||
use libafl::{
|
||||
corpus::{Corpus, Testcase},
|
||||
corpus::Testcase,
|
||||
executors::ExitKind,
|
||||
feedbacks::{Feedback, FeedbackFactory, StateInitializer},
|
||||
state::HasCorpus,
|
||||
};
|
||||
use libafl_bolts::{Error, Named};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -53,18 +52,16 @@ impl<F> Named 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>
|
||||
for CustomFilepathToTestcaseFeedback<F>
|
||||
impl<F, EM, I, OT, S> Feedback<EM, I, OT, S> for CustomFilepathToTestcaseFeedback<F>
|
||||
where
|
||||
S: HasCorpus,
|
||||
F: FnMut(&mut S, &mut Testcase<<S::Corpus as Corpus>::Input>, &Path) -> Result<(), Error>,
|
||||
F: FnMut(&mut S, &mut Testcase<I>, &Path) -> Result<(), Error>,
|
||||
{
|
||||
#[inline]
|
||||
fn is_interesting(
|
||||
&mut self,
|
||||
_state: &mut S,
|
||||
_manager: &mut EM,
|
||||
_input: &<S::Corpus as Corpus>::Input,
|
||||
_input: &I,
|
||||
_observers: &OT,
|
||||
_exit_kind: &ExitKind,
|
||||
) -> Result<bool, Error> {
|
||||
@ -76,7 +73,7 @@ where
|
||||
state: &mut S,
|
||||
_manager: &mut EM,
|
||||
_observers: &OT,
|
||||
testcase: &mut Testcase<<S::Corpus as Corpus>::Input>,
|
||||
testcase: &mut Testcase<I>,
|
||||
) -> Result<(), Error> {
|
||||
(self.func)(state, testcase, &self.out_dir)?;
|
||||
Ok(())
|
||||
|
@ -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>
|
||||
where
|
||||
S: HasCorpus,
|
||||
S::Corpus: Corpus<Input = I>,
|
||||
S: HasCorpus<I>,
|
||||
I: Input,
|
||||
{
|
||||
#[inline]
|
||||
|
@ -73,12 +73,13 @@ use crate::{
|
||||
};
|
||||
|
||||
pub type LibaflFuzzState =
|
||||
StdState<BytesInput, CachedOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>;
|
||||
StdState<CachedOnDiskCorpus<BytesInput>, BytesInput, StdRand, OnDiskCorpus<BytesInput>>;
|
||||
|
||||
#[cfg(not(feature = "fuzzbench"))]
|
||||
type LibaflFuzzManager = CentralizedEventManager<
|
||||
LlmpRestartingEventManager<(), LibaflFuzzState, StdShMemProvider>,
|
||||
LlmpRestartingEventManager<(), BytesInput, LibaflFuzzState, StdShMemProvider>,
|
||||
(),
|
||||
BytesInput,
|
||||
LibaflFuzzState,
|
||||
StdShMemProvider,
|
||||
>;
|
||||
@ -521,7 +522,7 @@ define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
|
||||
);
|
||||
|
||||
// Run our fuzzer; WITH CmpLog
|
||||
run_fuzzer_with_stages(
|
||||
run_fuzzer_with_stages::<_, _, BytesInput, _, _, _>(
|
||||
opt,
|
||||
&mut fuzzer,
|
||||
&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_fuzzer_with_stages(
|
||||
run_fuzzer_with_stages::<_, _, BytesInput, _, _, _>(
|
||||
opt,
|
||||
&mut fuzzer,
|
||||
&mut stages,
|
||||
@ -648,7 +649,7 @@ pub fn fuzzer_target_mode(opt: &Opt) -> Cow<'static, str> {
|
||||
#[derive(Debug, Serialize, Deserialize, SerdeAny)]
|
||||
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,
|
||||
fuzzer: &mut Z,
|
||||
stages: &mut ST,
|
||||
@ -657,7 +658,7 @@ pub fn run_fuzzer_with_stages<E, EM, S, ST, Z>(
|
||||
mgr: &mut EM,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
Z: Fuzzer<E, EM, S, ST>,
|
||||
Z: Fuzzer<E, EM, I, S, ST>,
|
||||
EM: ProgressReporter<S>,
|
||||
ST: StagesTuple<E, EM, S, Z>,
|
||||
S: HasLastReportTime + HasExecutions + HasMetadata,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use libafl::{
|
||||
corpus::Corpus,
|
||||
events::{Event, EventManagerHook},
|
||||
state::{HasCorpus, Stoppable},
|
||||
state::Stoppable,
|
||||
Error,
|
||||
};
|
||||
use libafl_bolts::ClientId;
|
||||
@ -11,15 +10,15 @@ pub struct LibAflFuzzEventHook {
|
||||
exit_on_solution: bool,
|
||||
}
|
||||
|
||||
impl<S> EventManagerHook<<S::Corpus as Corpus>::Input, S> for LibAflFuzzEventHook
|
||||
impl<I, S> EventManagerHook<I, S> for LibAflFuzzEventHook
|
||||
where
|
||||
S: HasCorpus + Stoppable,
|
||||
S: Stoppable,
|
||||
{
|
||||
fn pre_exec(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
_client_id: ClientId,
|
||||
event: &Event<<S::Corpus as Corpus>::Input>,
|
||||
event: &Event<I>,
|
||||
) -> Result<bool, Error> {
|
||||
if self.exit_on_solution && matches!(event, Event::Objective { .. }) {
|
||||
// TODO: dump state
|
||||
|
@ -13,19 +13,17 @@ pub enum SupportedSchedulers<Q, W> {
|
||||
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
|
||||
Q: Scheduler<<S::Corpus as Corpus>::Input, S>
|
||||
+ RemovableScheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
W: Scheduler<<S::Corpus as Corpus>::Input, S>
|
||||
+ RemovableScheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus + HasTestcase,
|
||||
Q: Scheduler<I, S> + RemovableScheduler<I, S>,
|
||||
W: Scheduler<I, S> + RemovableScheduler<I, S>,
|
||||
S: HasTestcase<I>,
|
||||
{
|
||||
fn on_remove(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
testcase: &Option<Testcase<<S::Corpus as Corpus>::Input>>,
|
||||
testcase: &Option<Testcase<I>>,
|
||||
) -> Result<(), Error> {
|
||||
match self {
|
||||
Self::Queue(queue, _) => queue.on_remove(state, id, testcase),
|
||||
@ -33,12 +31,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn on_replace(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
prev: &Testcase<<S::Corpus as Corpus>::Input>,
|
||||
) -> Result<(), Error> {
|
||||
fn on_replace(&mut self, state: &mut S, id: CorpusId, prev: &Testcase<I>) -> Result<(), Error> {
|
||||
match self {
|
||||
Self::Queue(queue, _) => queue.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
|
||||
Q: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
W: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus + HasTestcase,
|
||||
Q: Scheduler<I, S>,
|
||||
W: Scheduler<I, S>,
|
||||
S: HasCorpus<I> + HasTestcase<I>,
|
||||
{
|
||||
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
match self {
|
||||
@ -82,12 +75,7 @@ where
|
||||
Self::Weighted(weighted, _) => weighted.next(state),
|
||||
}
|
||||
}
|
||||
fn on_evaluation<OTB>(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
observers: &OTB,
|
||||
) -> Result<(), Error>
|
||||
fn on_evaluation<OTB>(&mut self, state: &mut S, input: &I, observers: &OTB) -> Result<(), Error>
|
||||
where
|
||||
OTB: MatchName,
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ use libafl::{
|
||||
feedback_or,
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
||||
fuzzer::{Fuzzer, StdFuzzer},
|
||||
inputs::{BytesInput, HasTargetBytes},
|
||||
inputs::{BytesInput, GeneralizedInputMetadata, HasTargetBytes},
|
||||
monitors::SimpleMonitor,
|
||||
mutators::{
|
||||
grimoire::{
|
||||
@ -604,7 +604,10 @@ fn fuzz_text(
|
||||
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
|
||||
let scheduler = IndexesLenTimeMinimizerScheduler::new(
|
||||
|
@ -141,7 +141,7 @@ pub extern "C" fn libafl_main() {
|
||||
|
||||
let mut secondary_run_client =
|
||||
|state: Option<_>,
|
||||
mut mgr: CentralizedEventManager<_, _, _, _>,
|
||||
mut mgr: CentralizedEventManager<_, _, _, _, _>,
|
||||
_client_description: ClientDescription| {
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer =
|
||||
|
@ -219,7 +219,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
|
||||
let orig_size = state.corpus().count();
|
||||
let msg = "Started distillation...".to_string();
|
||||
<LlmpRestartingEventManager<_, _, _> as EventFirer<BytesInput, _>>::log(
|
||||
<LlmpRestartingEventManager<_, _, _, _> as EventFirer<BytesInput, _>>::log(
|
||||
&mut restarting_mgr,
|
||||
&mut state,
|
||||
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)?;
|
||||
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 state,
|
||||
LogSeverity::Info,
|
||||
|
@ -162,7 +162,7 @@ pub extern "C" fn libafl_main() {
|
||||
);
|
||||
|
||||
let mut run_client = |state: Option<_>,
|
||||
mut restarting_mgr: LlmpRestartingEventManager<_, _, _>,
|
||||
mut restarting_mgr: LlmpRestartingEventManager<_, _, _, _>,
|
||||
client_description: ClientDescription| {
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer =
|
||||
|
@ -8,7 +8,7 @@ use libafl::{
|
||||
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback},
|
||||
fuzzer::{Evaluator, Fuzzer, StdFuzzer},
|
||||
inputs::{BytesInput, HasTargetBytes},
|
||||
inputs::{BytesInput, GeneralizedInputMetadata, HasTargetBytes},
|
||||
monitors::SimpleMonitor,
|
||||
mutators::{
|
||||
havoc_mutations, scheduled::StdScheduledMutator, GrimoireExtensionMutator,
|
||||
@ -157,7 +157,9 @@ pub fn main() {
|
||||
let mut stages = tuple_list!(
|
||||
generalization,
|
||||
StdMutationalStage::new(mutator),
|
||||
StdMutationalStage::transforming(grimoire_mutator)
|
||||
StdMutationalStage::<_, _, GeneralizedInputMetadata, BytesInput, _, _, _>::transforming(
|
||||
grimoire_mutator
|
||||
)
|
||||
);
|
||||
|
||||
for input in initial_inputs {
|
||||
|
@ -9,7 +9,7 @@ use libafl_bolts::ClientId;
|
||||
pub fn main() {
|
||||
let mut monitor = TuiMonitor::builder().build();
|
||||
|
||||
let client_stats = ClientStats {
|
||||
let _client_stats = ClientStats {
|
||||
corpus_size: 1024,
|
||||
executions: 512,
|
||||
..ClientStats::default()
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! 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 core::cell::RefCell;
|
||||
use core::cell::{Ref, RefCell, RefMut};
|
||||
use std::path::Path;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -55,12 +55,11 @@ where
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<I> Corpus for CachedOnDiskCorpus<I>
|
||||
|
||||
impl<I> Corpus<I> for CachedOnDiskCorpus<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
type Input = I;
|
||||
|
||||
/// Returns the number of all enabled entries
|
||||
#[inline]
|
||||
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.
|
||||
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)?;
|
||||
self.cached_indexes.borrow_mut().retain(|e| *e != id);
|
||||
Ok(testcase)
|
||||
@ -113,7 +112,7 @@ where
|
||||
}
|
||||
/// Get by id; considers both enabled and disabled testcases
|
||||
#[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)? };
|
||||
self.cache_testcase(testcase, id)?;
|
||||
Ok(testcase)
|
||||
@ -169,25 +168,25 @@ where
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> HasTestcase for CachedOnDiskCorpus<I>
|
||||
impl<I> HasTestcase<I> for CachedOnDiskCorpus<I>
|
||||
where
|
||||
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())
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! In-memory corpus, keeps all test cases in memory at all times
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::RefCell;
|
||||
use core::cell::{Ref, RefCell, RefMut};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -314,9 +314,7 @@ pub struct InMemoryCorpus<I> {
|
||||
current: Option<CorpusId>,
|
||||
}
|
||||
|
||||
impl<I> Corpus for InMemoryCorpus<I> {
|
||||
type Input = I;
|
||||
|
||||
impl<I> Corpus<I> for InMemoryCorpus<I> {
|
||||
/// Returns the number of all enabled entries
|
||||
#[inline]
|
||||
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
|
||||
#[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);
|
||||
if testcase.is_none() {
|
||||
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
|
||||
#[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);
|
||||
if testcase.is_none() {
|
||||
testcase = self.storage.disabled.get(id);
|
||||
@ -400,17 +398,17 @@ impl<I> Corpus for InMemoryCorpus<I> {
|
||||
&mut self.current
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next(&self, id: CorpusId) -> Option<CorpusId> {
|
||||
self.storage.enabled.next(id)
|
||||
}
|
||||
|
||||
/// Peek the next free corpus id
|
||||
#[inline]
|
||||
fn peek_free_id(&self) -> CorpusId {
|
||||
self.storage.peek_free_id()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next(&self, id: CorpusId) -> Option<CorpusId> {
|
||||
self.storage.enabled.next(id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn prev(&self, id: CorpusId) -> Option<CorpusId> {
|
||||
self.storage.enabled.prev(id)
|
||||
@ -443,29 +441,23 @@ impl<I> Corpus for InMemoryCorpus<I> {
|
||||
}
|
||||
|
||||
#[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.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn store_input_from(&self, _: &Testcase<Self::Input>) -> Result<(), Error> {
|
||||
fn store_input_from(&self, _: &Testcase<I>) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> HasTestcase for InMemoryCorpus<I> {
|
||||
fn testcase(
|
||||
&self,
|
||||
id: CorpusId,
|
||||
) -> Result<core::cell::Ref<Testcase<<Self::Corpus as Corpus>::Input>>, Error> {
|
||||
impl<I> HasTestcase<I> for InMemoryCorpus<I> {
|
||||
fn testcase(&self, id: CorpusId) -> Result<Ref<Testcase<I>>, Error> {
|
||||
Ok(self.get(id)?.borrow())
|
||||
}
|
||||
|
||||
fn testcase_mut(
|
||||
&self,
|
||||
id: CorpusId,
|
||||
) -> Result<core::cell::RefMut<Testcase<<Self::Corpus as Corpus>::Input>>, Error> {
|
||||
fn testcase_mut(&self, id: CorpusId) -> Result<RefMut<Testcase<I>>, Error> {
|
||||
Ok(self.get(id)?.borrow_mut())
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
//! which only stores a certain number of [`Testcase`]s and removes additional ones in a FIFO manner.
|
||||
|
||||
use alloc::string::String;
|
||||
use core::cell::RefCell;
|
||||
use core::cell::{Ref, RefCell, RefMut};
|
||||
use std::{
|
||||
fs,
|
||||
fs::{File, OpenOptions},
|
||||
@ -59,12 +59,10 @@ pub struct InMemoryOnDiskCorpus<I> {
|
||||
locking: bool,
|
||||
}
|
||||
|
||||
impl<I> Corpus for InMemoryOnDiskCorpus<I>
|
||||
impl<I> Corpus<I> for InMemoryOnDiskCorpus<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
type Input = I;
|
||||
|
||||
/// Returns the number of all enabled entries
|
||||
#[inline]
|
||||
fn count(&self) -> usize {
|
||||
@ -182,7 +180,7 @@ where
|
||||
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() {
|
||||
let Some(file_path) = testcase.file_path().as_ref() else {
|
||||
return Err(Error::illegal_argument(
|
||||
@ -195,7 +193,7 @@ where
|
||||
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
|
||||
let Some(file_path) = testcase.file_path() else {
|
||||
return Err(Error::illegal_argument(
|
||||
@ -211,21 +209,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> HasTestcase for InMemoryOnDiskCorpus<I>
|
||||
impl<I> HasTestcase<I> for InMemoryOnDiskCorpus<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
fn testcase(
|
||||
&self,
|
||||
id: CorpusId,
|
||||
) -> Result<core::cell::Ref<Testcase<<Self as Corpus>::Input>>, Error> {
|
||||
fn testcase(&self, id: CorpusId) -> Result<Ref<Testcase<I>>, Error> {
|
||||
Ok(self.get(id)?.borrow())
|
||||
}
|
||||
|
||||
fn testcase_mut(
|
||||
&self,
|
||||
id: CorpusId,
|
||||
) -> Result<core::cell::RefMut<Testcase<<Self as Corpus>::Input>>, Error> {
|
||||
fn testcase_mut(&self, id: CorpusId) -> Result<RefMut<Testcase<I>>, Error> {
|
||||
Ok(self.get(id)?.borrow_mut())
|
||||
}
|
||||
}
|
||||
@ -242,7 +234,7 @@ impl<I> InMemoryOnDiskCorpus<I> {
|
||||
/// If you don't want metadata, use [`InMemoryOnDiskCorpus::no_meta`].
|
||||
/// 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>
|
||||
where
|
||||
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.
|
||||
///
|
||||
/// 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>(
|
||||
dir_path: P,
|
||||
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
|
||||
/// 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>(
|
||||
dir_path: P,
|
||||
meta_format: Option<OnDiskMetadataFormat>,
|
||||
@ -286,7 +278,7 @@ impl<I> InMemoryOnDiskCorpus<I> {
|
||||
|
||||
/// 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>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
|
@ -29,16 +29,16 @@ use crate::{
|
||||
///
|
||||
/// Algorithm based on WMOPT: <https://hexhive.epfl.ch/publications/files/21ISSTA2.pdf>
|
||||
#[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>,
|
||||
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.
|
||||
pub type StdCorpusMinimizer<C, E, O, S, T> =
|
||||
MapCorpusMinimizer<C, E, O, S, T, LenTimeMulTestcaseScore>;
|
||||
pub type StdCorpusMinimizer<C, E, I, O, S, T> =
|
||||
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
|
||||
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
|
||||
for<'a> O: MapObserver<Entry = T> + AsIter<'a, Item = T>,
|
||||
C: AsRef<O>,
|
||||
S: HasMetadata + HasCorpus + HasExecutions,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
I: Input,
|
||||
S: HasMetadata + HasCorpus<I> + HasExecutions,
|
||||
T: Copy + Hash + Eq,
|
||||
TS: TestcaseScore<S>,
|
||||
TS: TestcaseScore<I, S>,
|
||||
{
|
||||
/// Do the minimization
|
||||
#[expect(clippy::too_many_lines)]
|
||||
@ -71,12 +71,11 @@ where
|
||||
state: &mut S,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
CS: Scheduler<<S::Corpus as Corpus>::Input, S>
|
||||
+ RemovableScheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
Z: HasScheduler<<S::Corpus as Corpus>::Input, S, Scheduler = CS>,
|
||||
E: Executor<EM, I, S, Z> + HasObservers,
|
||||
E::Observers: ObserversTuple<I, S>,
|
||||
CS: Scheduler<I, S> + RemovableScheduler<I, S>,
|
||||
EM: EventFirer<I, S>,
|
||||
Z: HasScheduler<I, S, Scheduler = CS>,
|
||||
{
|
||||
// don't delete this else it won't work after restart
|
||||
let current = *state.corpus().current();
|
||||
|
@ -1,5 +1,11 @@
|
||||
//! 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 use testcase::{HasTestcase, SchedulerTestcaseMetadata, Testcase};
|
||||
|
||||
@ -23,15 +29,11 @@ pub use cached::CachedOnDiskCorpus;
|
||||
|
||||
#[cfg(all(feature = "cmin", unix))]
|
||||
pub mod minimizer;
|
||||
use core::{cell::RefCell, fmt};
|
||||
|
||||
pub mod nop;
|
||||
#[cfg(all(feature = "cmin", unix))]
|
||||
pub use minimizer::*;
|
||||
pub use nop::NopCorpus;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
/// An abstraction for the index that identify a testcase in the corpus
|
||||
#[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
|
||||
pub trait Corpus: Sized {
|
||||
/// The type of input contained in this corpus
|
||||
type Input;
|
||||
|
||||
pub trait Corpus<I>: Sized {
|
||||
/// Returns the number of all enabled entries
|
||||
fn count(&self) -> usize;
|
||||
|
||||
@ -120,26 +119,22 @@ pub trait Corpus: Sized {
|
||||
}
|
||||
|
||||
/// 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
|
||||
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.
|
||||
fn replace(
|
||||
&mut self,
|
||||
id: CorpusId,
|
||||
testcase: Testcase<Self::Input>,
|
||||
) -> Result<Testcase<Self::Input>, Error>;
|
||||
fn replace(&mut self, id: CorpusId, testcase: Testcase<I>) -> Result<Testcase<I>, Error>;
|
||||
|
||||
/// 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
|
||||
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
|
||||
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
|
||||
fn current(&self) -> &Option<CorpusId>;
|
||||
@ -163,11 +158,12 @@ pub trait Corpus: Sized {
|
||||
fn last(&self) -> Option<CorpusId>;
|
||||
|
||||
/// An iterator over very active corpus id
|
||||
fn ids(&self) -> CorpusIdIterator<'_, Self> {
|
||||
fn ids(&self) -> CorpusIdIterator<'_, Self, I> {
|
||||
CorpusIdIterator {
|
||||
corpus: self,
|
||||
cur: self.first(),
|
||||
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,
|
||||
/// if necessary, and if was not already loaded (`== 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.
|
||||
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.
|
||||
fn cloned_input_for_id(&self, id: CorpusId) -> Result<Self::Input, Error>
|
||||
fn cloned_input_for_id(&self, id: CorpusId) -> Result<I, Error>
|
||||
where
|
||||
Self::Input: Clone,
|
||||
I: Clone,
|
||||
{
|
||||
let mut testcase = self.get(id)?.borrow_mut();
|
||||
Ok(testcase.load_input(self)?.clone())
|
||||
@ -213,18 +209,16 @@ pub trait HasCurrentCorpusId {
|
||||
|
||||
/// [`Iterator`] over the ids of a [`Corpus`]
|
||||
#[derive(Debug)]
|
||||
pub struct CorpusIdIterator<'a, C>
|
||||
where
|
||||
C: Corpus,
|
||||
{
|
||||
pub struct CorpusIdIterator<'a, C, I> {
|
||||
corpus: &'a C,
|
||||
cur: Option<CorpusId>,
|
||||
cur_back: Option<CorpusId>,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<C> Iterator for CorpusIdIterator<'_, C>
|
||||
impl<C, I> Iterator for CorpusIdIterator<'_, C, I>
|
||||
where
|
||||
C: Corpus,
|
||||
C: Corpus<I>,
|
||||
{
|
||||
type Item = CorpusId;
|
||||
|
||||
@ -238,9 +232,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> DoubleEndedIterator for CorpusIdIterator<'_, C>
|
||||
impl<C, I> DoubleEndedIterator for CorpusIdIterator<'_, C, I>
|
||||
where
|
||||
C: Corpus,
|
||||
C: Corpus<I>,
|
||||
{
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
if let Some(cur_back) = self.cur_back {
|
||||
|
@ -15,8 +15,7 @@ pub struct NopCorpus<I> {
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<I> Corpus for NopCorpus<I> {
|
||||
type Input = I;
|
||||
impl<I> Corpus<I> for NopCorpus<I> {
|
||||
/// Returns the number of all enabled entries
|
||||
#[inline]
|
||||
fn count(&self) -> usize {
|
||||
@ -76,12 +75,6 @@ impl<I> Corpus for NopCorpus<I> {
|
||||
&self.empty
|
||||
}
|
||||
|
||||
/// Peek the next free corpus id
|
||||
#[inline]
|
||||
fn peek_free_id(&self) -> CorpusId {
|
||||
CorpusId::from(0_usize)
|
||||
}
|
||||
|
||||
/// Current testcase scheduled (mutable)
|
||||
#[inline]
|
||||
fn current_mut(&mut self) -> &mut Option<CorpusId> {
|
||||
@ -93,6 +86,12 @@ impl<I> Corpus for NopCorpus<I> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Peek the next free corpus id
|
||||
#[inline]
|
||||
fn peek_free_id(&self) -> CorpusId {
|
||||
CorpusId::from(0_usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn prev(&self, _id: CorpusId) -> Option<CorpusId> {
|
||||
None
|
||||
@ -121,12 +120,12 @@ impl<I> Corpus for NopCorpus<I> {
|
||||
}
|
||||
|
||||
#[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"))
|
||||
}
|
||||
|
||||
#[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"))
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! 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.
|
||||
//! 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.
|
||||
|
||||
use alloc::string::String;
|
||||
@ -56,11 +56,10 @@ pub struct OnDiskCorpus<I> {
|
||||
inner: CachedOnDiskCorpus<I>,
|
||||
}
|
||||
|
||||
impl<I> Corpus for OnDiskCorpus<I>
|
||||
impl<I> Corpus<I> for OnDiskCorpus<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
type Input = I;
|
||||
/// Returns the number of all enabled entries
|
||||
#[inline]
|
||||
fn count(&self) -> usize {
|
||||
@ -96,12 +95,6 @@ where
|
||||
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
|
||||
#[inline]
|
||||
fn remove(&mut self, id: CorpusId) -> Result<Testcase<I>, Error> {
|
||||
@ -137,6 +130,12 @@ where
|
||||
self.inner.next(id)
|
||||
}
|
||||
|
||||
/// Peek the next free corpus id
|
||||
#[inline]
|
||||
fn peek_free_id(&self) -> CorpusId {
|
||||
self.inner.peek_free_id()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn prev(&self, id: CorpusId) -> Option<CorpusId> {
|
||||
self.inner.prev(id)
|
||||
@ -164,17 +163,17 @@ where
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> HasTestcase for OnDiskCorpus<I>
|
||||
impl<I> HasTestcase<I> for OnDiskCorpus<I>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
|
@ -15,24 +15,18 @@ use libafl_bolts::{serdeany::SerdeAnyMap, HasLen};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
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`].
|
||||
/// 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`].
|
||||
/// For a normal state, this should return a [`Testcase`] in the corpus, not the objectives.
|
||||
fn testcase(
|
||||
&self,
|
||||
id: CorpusId,
|
||||
) -> Result<Ref<Testcase<<Self::Corpus as Corpus>::Input>>, Error>;
|
||||
fn testcase(&self, id: CorpusId) -> Result<Ref<Testcase<I>>, Error>;
|
||||
|
||||
/// 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.
|
||||
fn testcase_mut(
|
||||
&self,
|
||||
id: CorpusId,
|
||||
) -> Result<RefMut<Testcase<<Self::Corpus as Corpus>::Input>>, Error>;
|
||||
fn testcase_mut(&self, id: CorpusId) -> Result<RefMut<Testcase<I>>, Error>;
|
||||
}
|
||||
|
||||
/// An entry in the [`Testcase`] Corpus
|
||||
@ -87,7 +81,7 @@ impl<I> HasMetadata for Testcase<I> {
|
||||
/// Impl of a testcase
|
||||
impl<I> Testcase<I> {
|
||||
/// 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)?;
|
||||
Ok(self.input.as_ref().unwrap())
|
||||
}
|
||||
@ -358,7 +352,7 @@ where
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
Some(i) => {
|
||||
let l = i.len();
|
||||
|
@ -29,7 +29,6 @@ use super::{CanSerializeObserver, ManagerExit, NopEventManager};
|
||||
use crate::events::llmp::COMPRESS_THRESHOLD;
|
||||
use crate::{
|
||||
common::HasMetadata,
|
||||
corpus::Corpus,
|
||||
events::{
|
||||
serialize_observers_adaptive, std_maybe_report_progress, std_report_progress,
|
||||
AdaptiveSerializer, Event, EventConfig, EventFirer, EventManagerHooksTuple, EventManagerId,
|
||||
@ -39,9 +38,7 @@ use crate::{
|
||||
fuzzer::{EvaluatorObservers, ExecutionProcessor},
|
||||
inputs::{Input, NopInput},
|
||||
observers::TimeObserver,
|
||||
state::{
|
||||
HasCorpus, HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor, NopState, Stoppable,
|
||||
},
|
||||
state::{HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor, NopState, Stoppable},
|
||||
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
|
||||
#[derive(Debug)]
|
||||
pub struct CentralizedEventManager<EM, EMH, S, SP>
|
||||
pub struct CentralizedEventManager<EM, EMH, I, S, SP>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -61,10 +58,10 @@ where
|
||||
time_ref: Option<Handle<TimeObserver>>,
|
||||
hooks: EMH,
|
||||
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`]
|
||||
#[must_use]
|
||||
pub fn builder() -> CentralizedEventManagerBuilder {
|
||||
@ -98,13 +95,13 @@ impl CentralizedEventManagerBuilder {
|
||||
}
|
||||
|
||||
/// Creates a new [`CentralizedEventManager`].
|
||||
pub fn build_from_client<EM, EMH, S, SP>(
|
||||
pub fn build_from_client<EM, EMH, I, S, SP>(
|
||||
self,
|
||||
inner: EM,
|
||||
hooks: EMH,
|
||||
client: LlmpClient<SP>,
|
||||
time_obs: Option<Handle<TimeObserver>>,
|
||||
) -> Result<CentralizedEventManager<EM, EMH, S, SP>, Error>
|
||||
) -> Result<CentralizedEventManager<EM, EMH, I, S, SP>, Error>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -124,14 +121,14 @@ impl CentralizedEventManagerBuilder {
|
||||
///
|
||||
/// If the port is not yet bound, it will act as a broker; otherwise, it
|
||||
/// 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,
|
||||
inner: EM,
|
||||
hooks: EMH,
|
||||
shmem_provider: SP,
|
||||
port: u16,
|
||||
time_obs: Option<Handle<TimeObserver>>,
|
||||
) -> Result<CentralizedEventManager<EM, EMH, S, SP>, Error>
|
||||
) -> Result<CentralizedEventManager<EM, EMH, I, S, SP>, Error>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -141,14 +138,14 @@ impl CentralizedEventManagerBuilder {
|
||||
|
||||
/// If a client respawns, it may reuse the existing connection, previously
|
||||
/// 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,
|
||||
inner: EM,
|
||||
hooks: EMH,
|
||||
shmem_provider: SP,
|
||||
env_name: &str,
|
||||
time_obs: Option<Handle<TimeObserver>>,
|
||||
) -> Result<CentralizedEventManager<EM, EMH, S, SP>, Error>
|
||||
) -> Result<CentralizedEventManager<EM, EMH, I, S, SP>, Error>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -157,14 +154,14 @@ impl CentralizedEventManagerBuilder {
|
||||
}
|
||||
|
||||
/// 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,
|
||||
inner: EM,
|
||||
hooks: EMH,
|
||||
shmem_provider: SP,
|
||||
description: &LlmpClientDescription,
|
||||
time_obs: Option<Handle<TimeObserver>>,
|
||||
) -> Result<CentralizedEventManager<EM, EMH, S, SP>, Error>
|
||||
) -> Result<CentralizedEventManager<EM, EMH, I, S, SP>, Error>
|
||||
where
|
||||
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
|
||||
EM: AdaptiveSerializer,
|
||||
SP: ShMemProvider,
|
||||
@ -209,25 +206,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<EM, EMH, S, SP> EventFirer<<S::Corpus as Corpus>::Input, S>
|
||||
for CentralizedEventManager<EM, EMH, S, SP>
|
||||
impl<EM, EMH, I, S, SP> EventFirer<I, S> for CentralizedEventManager<EM, EMH, I, S, SP>
|
||||
where
|
||||
EM: HasEventManagerId + EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
EMH: EventManagerHooksTuple<<<S as HasCorpus>::Corpus as Corpus>::Input, S>,
|
||||
EM: HasEventManagerId + EventFirer<I, S>,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
S: HasCorpus + Stoppable,
|
||||
<<S as HasCorpus>::Corpus as Corpus>::Input: Input,
|
||||
S: Stoppable,
|
||||
I: Input,
|
||||
{
|
||||
fn should_send(&self) -> bool {
|
||||
self.inner.should_send()
|
||||
}
|
||||
|
||||
#[expect(clippy::match_same_arms)]
|
||||
fn fire(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
mut event: Event<<S::Corpus as Corpus>::Input>,
|
||||
) -> Result<(), Error> {
|
||||
fn fire(&mut self, state: &mut S, mut event: Event<I>) -> Result<(), Error> {
|
||||
if !self.is_main {
|
||||
// secondary node
|
||||
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
|
||||
SP: ShMemProvider,
|
||||
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
|
||||
EM: AdaptiveSerializer,
|
||||
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
|
||||
EM: ManagerExit,
|
||||
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
|
||||
E: HasObservers,
|
||||
E::Observers: DeserializeOwned,
|
||||
EM: EventProcessor<E, S, Z> + HasEventManagerId + EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus + Stoppable,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
EM: EventProcessor<E, S, Z> + HasEventManagerId + EventFirer<I, S>,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
S: Stoppable,
|
||||
I: Input,
|
||||
SP: ShMemProvider,
|
||||
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S>
|
||||
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
|
||||
Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
|
||||
{
|
||||
fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error> {
|
||||
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
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S> + HasEventManagerId,
|
||||
EMH: EventManagerHooksTuple<<<S as HasCorpus>::Corpus as Corpus>::Input, S>,
|
||||
S: HasExecutions
|
||||
+ HasMetadata
|
||||
+ HasLastReportTime
|
||||
+ Stoppable
|
||||
+ HasCorpus
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
EM: EventFirer<I, S> + HasEventManagerId,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
S: HasExecutions + HasMetadata + HasLastReportTime + Stoppable + MaybeHasClientPerfMonitor,
|
||||
I: Input,
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
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
|
||||
EM: HasEventManagerId,
|
||||
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
|
||||
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
|
||||
EM: HasEventManagerId + EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus + Stoppable,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
EM: HasEventManagerId + EventFirer<I, S>,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
S: Stoppable,
|
||||
I: Input,
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
#[cfg(feature = "llmp_compression")]
|
||||
fn forward_to_main<I>(&mut self, event: &Event<I>) -> Result<(), Error>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
fn forward_to_main(&mut self, event: &Event<I>) -> Result<(), Error> {
|
||||
let serialized = postcard::to_allocvec(event)?;
|
||||
let flags = LLMP_FLAG_INITIALIZED;
|
||||
|
||||
@ -434,10 +417,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "llmp_compression"))]
|
||||
fn forward_to_main<I>(&mut self, event: &Event<I>) -> Result<(), Error>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
fn forward_to_main(&mut self, event: &Event<I>) -> Result<(), Error> {
|
||||
let serialized = postcard::to_allocvec(event)?;
|
||||
self.client.send_buf(_LLMP_TAG_TO_MAIN, &serialized)?;
|
||||
Ok(())
|
||||
@ -452,8 +432,7 @@ where
|
||||
where
|
||||
E: HasObservers,
|
||||
E::Observers: DeserializeOwned,
|
||||
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S>
|
||||
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
|
||||
Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
|
||||
{
|
||||
// TODO: Get around local event copy by moving handle_in_client
|
||||
let self_id = self.client.sender().id();
|
||||
@ -478,7 +457,7 @@ where
|
||||
} else {
|
||||
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());
|
||||
self.handle_in_main(fuzzer, executor, state, client_id, event)?;
|
||||
count += 1;
|
||||
@ -493,13 +472,12 @@ where
|
||||
executor: &mut E,
|
||||
state: &mut S,
|
||||
client_id: ClientId,
|
||||
event: Event<<S::Corpus as Corpus>::Input>,
|
||||
event: Event<I>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
E: HasObservers,
|
||||
E::Observers: DeserializeOwned,
|
||||
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S>
|
||||
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
|
||||
Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
|
||||
{
|
||||
log::debug!("handle_in_main!");
|
||||
|
||||
@ -594,14 +572,3 @@ where
|
||||
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();
|
||||
}
|
||||
}*/
|
||||
|
@ -51,14 +51,12 @@ use {libafl_bolts::os::startable_self, std::process::Stdio};
|
||||
#[cfg(all(unix, feature = "fork", feature = "multi_machine"))]
|
||||
use crate::events::multi_machine::{NodeDescriptor, TcpMultiMachineHooks};
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
events::{
|
||||
llmp::{LlmpRestartingEventManager, LlmpShouldSaveState, ManagerKind, RestartingMgr},
|
||||
EventConfig, EventManagerHooksTuple,
|
||||
},
|
||||
monitors::Monitor,
|
||||
observers::TimeObserver,
|
||||
state::HasCorpus,
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -214,15 +212,15 @@ where
|
||||
{
|
||||
/// Launch the broker and the clients and fuzz
|
||||
#[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
|
||||
S: DeserializeOwned + HasCorpus + Serialize,
|
||||
<S::Corpus as Corpus>::Input: DeserializeOwned,
|
||||
CF: FnOnce(
|
||||
Option<S>,
|
||||
LlmpRestartingEventManager<(), S, SP>,
|
||||
LlmpRestartingEventManager<(), I, S, SP>,
|
||||
ClientDescription,
|
||||
) -> Result<(), Error>,
|
||||
I: DeserializeOwned,
|
||||
S: DeserializeOwned + Serialize,
|
||||
{
|
||||
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
|
||||
#[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
|
||||
S: DeserializeOwned + HasCorpus + Serialize,
|
||||
<S::Corpus as Corpus>::Input: DeserializeOwned,
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S> + Clone + Copy,
|
||||
S: DeserializeOwned + Serialize,
|
||||
I: DeserializeOwned,
|
||||
EMH: EventManagerHooksTuple<I, S> + Clone + Copy,
|
||||
CF: FnOnce(
|
||||
Option<S>,
|
||||
LlmpRestartingEventManager<EMH, S, SP>,
|
||||
LlmpRestartingEventManager<EMH, I, S, SP>,
|
||||
ClientDescription,
|
||||
) -> Result<(), Error>,
|
||||
{
|
||||
@ -314,7 +312,7 @@ where
|
||||
ClientDescription::new(index, overcommit_id, bind_to);
|
||||
|
||||
// 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())
|
||||
.broker_port(self.broker_port)
|
||||
.kind(ManagerKind::Client {
|
||||
@ -341,7 +339,7 @@ where
|
||||
log::info!("I am broker!!.");
|
||||
|
||||
// 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())
|
||||
.monitor(Some(self.monitor.clone()))
|
||||
.broker_port(self.broker_port)
|
||||
@ -383,18 +381,18 @@ where
|
||||
/// Launch the broker and the clients and fuzz
|
||||
#[cfg(any(windows, not(feature = "fork")))]
|
||||
#[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
|
||||
S: DeserializeOwned + HasCorpus + Serialize,
|
||||
<S::Corpus as Corpus>::Input: DeserializeOwned,
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S> + Clone + Copy,
|
||||
CF: FnOnce(
|
||||
Option<S>,
|
||||
LlmpRestartingEventManager<EMH, S, SP>,
|
||||
LlmpRestartingEventManager<EMH, I, S, SP>,
|
||||
ClientDescription,
|
||||
) -> 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);
|
||||
|
||||
@ -403,7 +401,7 @@ where
|
||||
let client_description = ClientDescription::from_safe_string(&core_conf);
|
||||
// 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())
|
||||
.broker_port(self.broker_port)
|
||||
.kind(ManagerKind::Client {
|
||||
@ -423,7 +421,7 @@ where
|
||||
// I am a broker
|
||||
// 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![];
|
||||
|
||||
log::info!("spawning on cores: {:?}", self.cores);
|
||||
@ -504,7 +502,7 @@ where
|
||||
if self.spawn_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())
|
||||
.monitor(Some(self.monitor.clone()))
|
||||
.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
|
||||
pub type StdCentralizedInnerMgr<S, SP> = LlmpRestartingEventManager<(), S, SP>;
|
||||
pub type StdCentralizedInnerMgr<I, S, SP> = LlmpRestartingEventManager<(), I, S, SP>;
|
||||
|
||||
#[cfg(all(unix, feature = "fork"))]
|
||||
impl<CF, MF, MT, SP> CentralizedLauncher<'_, CF, MF, MT, SP>
|
||||
@ -631,25 +629,25 @@ where
|
||||
SP: ShMemProvider + 'static,
|
||||
{
|
||||
/// Launch a standard Centralized-based fuzzer
|
||||
pub fn launch<S>(&mut self) -> Result<(), Error>
|
||||
pub fn launch<I, S>(&mut self) -> Result<(), Error>
|
||||
where
|
||||
S: DeserializeOwned + HasCorpus + Serialize,
|
||||
<S::Corpus as Corpus>::Input: DeserializeOwned + Input + Send + Sync + 'static,
|
||||
S: DeserializeOwned + Serialize,
|
||||
I: DeserializeOwned + Input + Send + Sync + 'static,
|
||||
CF: FnOnce(
|
||||
Option<S>,
|
||||
CentralizedEventManager<StdCentralizedInnerMgr<S, SP>, (), S, SP>,
|
||||
CentralizedEventManager<StdCentralizedInnerMgr<I, S, SP>, (), I, S, SP>,
|
||||
ClientDescription,
|
||||
) -> Result<(), Error>,
|
||||
MF: FnOnce(
|
||||
Option<S>,
|
||||
CentralizedEventManager<StdCentralizedInnerMgr<S, SP>, (), S, SP>,
|
||||
CentralizedEventManager<StdCentralizedInnerMgr<I, S, SP>, (), I, S, SP>,
|
||||
ClientDescription,
|
||||
) -> Result<(), Error>,
|
||||
{
|
||||
let restarting_mgr_builder =
|
||||
|centralized_launcher: &Self, client_description: ClientDescription| {
|
||||
// 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())
|
||||
.broker_port(centralized_launcher.broker_port)
|
||||
.kind(ManagerKind::Client { client_description })
|
||||
@ -675,23 +673,22 @@ where
|
||||
/// Launch a Centralized-based fuzzer.
|
||||
/// - `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.
|
||||
pub fn launch_generic<EM, EMB, S>(
|
||||
pub fn launch_generic<EM, EMB, I, S>(
|
||||
&mut self,
|
||||
main_inner_mgr_builder: EMB,
|
||||
secondary_inner_mgr_builder: EMB,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
S: HasCorpus,
|
||||
<S::Corpus as Corpus>::Input: Input + Send + Sync + 'static,
|
||||
I: Input + Send + Sync + 'static,
|
||||
CF: FnOnce(
|
||||
Option<S>,
|
||||
CentralizedEventManager<EM, (), S, SP>,
|
||||
CentralizedEventManager<EM, (), I, S, SP>,
|
||||
ClientDescription,
|
||||
) -> Result<(), Error>,
|
||||
EMB: FnOnce(&Self, ClientDescription) -> Result<(Option<S>, EM), Error>,
|
||||
MF: FnOnce(
|
||||
Option<S>,
|
||||
CentralizedEventManager<EM, (), S, SP>, // No broker_hooks for centralized EM
|
||||
CentralizedEventManager<EM, (), I, S, SP>, // No broker_hooks for centralized EM
|
||||
ClientDescription,
|
||||
) -> Result<(), Error>,
|
||||
{
|
||||
@ -835,7 +832,7 @@ where
|
||||
} = unsafe {
|
||||
TcpMultiMachineHooks::builder()
|
||||
.node_descriptor(self.multi_machine_node_descriptor.clone())
|
||||
.build::<<S::Corpus as Corpus>::Input>()?
|
||||
.build::<I>()?
|
||||
};
|
||||
|
||||
let mut brokers = Brokers::new();
|
||||
@ -845,13 +842,12 @@ where
|
||||
brokers.add(Box::new({
|
||||
#[cfg(feature = "multi_machine")]
|
||||
let centralized_hooks = tuple_list!(
|
||||
CentralizedLlmpHook::<<S::Corpus as Corpus>::Input>::new()?,
|
||||
CentralizedLlmpHook::<I>::new()?,
|
||||
multi_machine_receiver_hook,
|
||||
);
|
||||
|
||||
#[cfg(not(feature = "multi_machine"))]
|
||||
let centralized_hooks =
|
||||
tuple_list!(CentralizedLlmpHook::<<S::Corpus as Corpus>::Input>::new()?);
|
||||
let centralized_hooks = tuple_list!(CentralizedLlmpHook::<I>::new()?);
|
||||
|
||||
// TODO switch to false after solving the bug
|
||||
let mut broker = LlmpBroker::with_keep_pages_attach_to_tcp(
|
||||
@ -875,13 +871,11 @@ where
|
||||
log::info!("I am broker!!.");
|
||||
|
||||
#[cfg(not(feature = "multi_machine"))]
|
||||
let llmp_hook = tuple_list!(StdLlmpEventHook::<<S::Corpus as Corpus>::Input, MT>::new(
|
||||
self.monitor.clone()
|
||||
)?);
|
||||
let llmp_hook = tuple_list!(StdLlmpEventHook::<I, MT>::new(self.monitor.clone())?);
|
||||
|
||||
#[cfg(feature = "multi_machine")]
|
||||
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,
|
||||
);
|
||||
|
||||
|
@ -34,7 +34,6 @@ use crate::events::llmp::COMPRESS_THRESHOLD;
|
||||
#[cfg(feature = "std")]
|
||||
use crate::events::{serialize_observers_adaptive, CanSerializeObserver};
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
events::{
|
||||
llmp::{LLMP_TAG_EVENT_TO_BOTH, _LLMP_TAG_EVENT_TO_BROKER},
|
||||
std_maybe_report_progress, std_on_restart, std_report_progress, AdaptiveSerializer, Event,
|
||||
@ -47,8 +46,8 @@ use crate::{
|
||||
observers::TimeObserver,
|
||||
stages::HasCurrentStageId,
|
||||
state::{
|
||||
HasCorpus, HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor,
|
||||
NopState, Stoppable,
|
||||
HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor, NopState,
|
||||
Stoppable,
|
||||
},
|
||||
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,
|
||||
/// using low-level message passing, `llmp`.
|
||||
pub struct LlmpEventManager<EMH, S, SP>
|
||||
pub struct LlmpEventManager<EMH, I, S, SP>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -80,11 +79,11 @@ where
|
||||
serializations_cnt: usize,
|
||||
should_serialize_cnt: usize,
|
||||
pub(crate) time_ref: Option<Handle<TimeObserver>>,
|
||||
phantom: PhantomData<S>,
|
||||
phantom: PhantomData<(I, S)>,
|
||||
event_buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl LlmpEventManager<(), NopState<NopInput>, NopShMemProvider> {
|
||||
impl LlmpEventManager<(), NopState<NopInput>, NopInput, NopShMemProvider> {
|
||||
/// Creates a builder for [`LlmpEventManager`]
|
||||
#[must_use]
|
||||
pub fn builder() -> LlmpEventManagerBuilder<()> {
|
||||
@ -133,12 +132,12 @@ impl<EMH> LlmpEventManagerBuilder<EMH> {
|
||||
}
|
||||
|
||||
/// Create a manager from a raw LLMP client
|
||||
pub fn build_from_client<S, SP>(
|
||||
pub fn build_from_client<I, S, SP>(
|
||||
self,
|
||||
llmp: LlmpClient<SP>,
|
||||
configuration: EventConfig,
|
||||
time_ref: Option<Handle<TimeObserver>>,
|
||||
) -> Result<LlmpEventManager<EMH, S, SP>, Error>
|
||||
) -> Result<LlmpEventManager<EMH, I, S, SP>, Error>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -163,13 +162,13 @@ impl<EMH> LlmpEventManagerBuilder<EMH> {
|
||||
/// Create an LLMP event manager on a port.
|
||||
/// It expects a broker to exist on this port.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn build_on_port<S, SP>(
|
||||
pub fn build_on_port<I, S, SP>(
|
||||
self,
|
||||
shmem_provider: SP,
|
||||
port: u16,
|
||||
configuration: EventConfig,
|
||||
time_ref: Option<Handle<TimeObserver>>,
|
||||
) -> Result<LlmpEventManager<EMH, S, SP>, Error>
|
||||
) -> Result<LlmpEventManager<EMH, I, S, SP>, Error>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -180,13 +179,13 @@ impl<EMH> LlmpEventManagerBuilder<EMH> {
|
||||
/// If a client respawns, it may reuse the existing connection, previously
|
||||
/// stored by [`LlmpClient::to_env()`].
|
||||
#[cfg(feature = "std")]
|
||||
pub fn build_existing_client_from_env<S, SP>(
|
||||
pub fn build_existing_client_from_env<I, S, SP>(
|
||||
self,
|
||||
shmem_provider: SP,
|
||||
env_name: &str,
|
||||
configuration: EventConfig,
|
||||
time_ref: Option<Handle<TimeObserver>>,
|
||||
) -> Result<LlmpEventManager<EMH, S, SP>, Error>
|
||||
) -> Result<LlmpEventManager<EMH, I, S, SP>, Error>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -195,13 +194,13 @@ impl<EMH> LlmpEventManagerBuilder<EMH> {
|
||||
}
|
||||
|
||||
/// 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,
|
||||
shmem_provider: SP,
|
||||
description: &LlmpClientDescription,
|
||||
configuration: EventConfig,
|
||||
time_ref: Option<Handle<TimeObserver>>,
|
||||
) -> Result<LlmpEventManager<EMH, S, SP>, Error>
|
||||
) -> Result<LlmpEventManager<EMH, I, S, SP>, Error>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -211,7 +210,7 @@ impl<EMH> LlmpEventManagerBuilder<EMH> {
|
||||
}
|
||||
|
||||
#[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
|
||||
SP: ShMemProvider,
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -344,16 +343,15 @@ where
|
||||
executor: &mut E,
|
||||
state: &mut S,
|
||||
client_id: ClientId,
|
||||
event: Event<<S::Corpus as Corpus>::Input>,
|
||||
event: Event<I>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
S: HasCorpus + HasImported + Stoppable,
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
S: HasImported + Stoppable,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
I: Input,
|
||||
E: HasObservers,
|
||||
E::Observers: DeserializeOwned,
|
||||
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S>
|
||||
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
|
||||
Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
|
||||
{
|
||||
log::trace!("Got event in client: {} from {client_id:?}", event.name());
|
||||
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.
|
||||
/// The other side may free up all allocated memory.
|
||||
/// 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
|
||||
I: Serialize,
|
||||
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
|
||||
SP: ShMemProvider,
|
||||
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
|
||||
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
|
||||
E: HasObservers,
|
||||
E::Observers: DeserializeOwned,
|
||||
S: HasCorpus + HasImported + Stoppable,
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
<S::Corpus as Corpus>::Input: DeserializeOwned + Input,
|
||||
S: HasImported + Stoppable,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
I: DeserializeOwned + Input,
|
||||
SP: ShMemProvider,
|
||||
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S>
|
||||
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
|
||||
Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
|
||||
{
|
||||
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
|
||||
@ -543,7 +540,7 @@ where
|
||||
} else {
|
||||
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());
|
||||
|
||||
// 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
|
||||
S: HasExecutions + HasLastReportTime + HasMetadata + HasCorpus + MaybeHasClientPerfMonitor,
|
||||
S: HasExecutions + HasLastReportTime + HasMetadata + MaybeHasClientPerfMonitor,
|
||||
SP: ShMemProvider,
|
||||
<S::Corpus as Corpus>::Input: Serialize,
|
||||
I: Serialize,
|
||||
{
|
||||
fn maybe_report_progress(
|
||||
&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
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
|
@ -15,11 +15,10 @@ use libafl_bolts::{
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
events::{Event, EventFirer},
|
||||
fuzzer::EvaluatorObservers,
|
||||
inputs::{Input, InputConverter, NopInput, NopInputConverter},
|
||||
state::{HasCorpus, NopState},
|
||||
state::NopState,
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -83,7 +82,7 @@ impl LlmpShouldSaveState {
|
||||
}
|
||||
|
||||
/// 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
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -94,11 +93,12 @@ where
|
||||
compressor: GzipCompressor,
|
||||
converter: Option<IC>,
|
||||
converter_back: Option<ICB>,
|
||||
phantom: PhantomData<S>,
|
||||
phantom: PhantomData<(I, S)>,
|
||||
}
|
||||
|
||||
impl
|
||||
LlmpEventConverter<
|
||||
NopInput,
|
||||
NopInputConverter<NopInput>,
|
||||
NopInputConverter<NopInput>,
|
||||
NopState<NopInput>,
|
||||
@ -134,12 +134,12 @@ impl LlmpEventConverterBuilder {
|
||||
}
|
||||
|
||||
/// 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,
|
||||
llmp: LlmpClient<SP>,
|
||||
converter: Option<IC>,
|
||||
converter_back: Option<ICB>,
|
||||
) -> Result<LlmpEventConverter<IC, ICB, S, SP>, Error>
|
||||
) -> Result<LlmpEventConverter<I, IC, ICB, S, SP>, Error>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -157,13 +157,13 @@ impl LlmpEventConverterBuilder {
|
||||
|
||||
/// Create a client from port and the input converters
|
||||
#[cfg(feature = "std")]
|
||||
pub fn build_on_port<IC, ICB, S, SP>(
|
||||
pub fn build_on_port<I, IC, ICB, S, SP>(
|
||||
self,
|
||||
shmem_provider: SP,
|
||||
port: u16,
|
||||
converter: Option<IC>,
|
||||
converter_back: Option<ICB>,
|
||||
) -> Result<LlmpEventConverter<IC, ICB, S, SP>, Error>
|
||||
) -> Result<LlmpEventConverter<I, IC, ICB, S, SP>, Error>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -182,13 +182,13 @@ impl LlmpEventConverterBuilder {
|
||||
|
||||
/// If a client respawns, it may reuse the existing connection, previously stored by [`LlmpClient::to_env()`].
|
||||
#[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,
|
||||
shmem_provider: SP,
|
||||
env_name: &str,
|
||||
converter: Option<IC>,
|
||||
converter_back: Option<ICB>,
|
||||
) -> Result<LlmpEventConverter<IC, ICB, S, SP>, Error>
|
||||
) -> Result<LlmpEventConverter<I, IC, ICB, S, SP>, Error>
|
||||
where
|
||||
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
|
||||
SP: ShMemProvider,
|
||||
ICB: Debug,
|
||||
IC: Debug,
|
||||
ICB: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
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
|
||||
S: HasCorpus,
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
// TODO other new_* routines
|
||||
@ -265,8 +264,8 @@ where
|
||||
event: Event<DI>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
ICB: InputConverter<To = <S::Corpus as Corpus>::Input, From = DI>,
|
||||
Z: EvaluatorObservers<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
ICB: InputConverter<To = I, From = DI>,
|
||||
Z: EvaluatorObservers<E, EM, I, S>,
|
||||
{
|
||||
match event {
|
||||
Event::NewTestcase {
|
||||
@ -308,9 +307,9 @@ where
|
||||
manager: &mut EM,
|
||||
) -> Result<usize, Error>
|
||||
where
|
||||
ICB: InputConverter<To = <S::Corpus as Corpus>::Input, From = DI>,
|
||||
ICB: InputConverter<To = I, From = DI>,
|
||||
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
|
||||
let self_id = self.llmp.sender().id();
|
||||
@ -345,11 +344,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<IC, ICB, S, SP> EventFirer<<S::Corpus as Corpus>::Input, S>
|
||||
for LlmpEventConverter<IC, ICB, S, SP>
|
||||
impl<I, IC, ICB, S, SP> EventFirer<I, S> for LlmpEventConverter<I, IC, ICB, S, SP>
|
||||
where
|
||||
IC: InputConverter<From = <S::Corpus as Corpus>::Input>,
|
||||
S: HasCorpus,
|
||||
IC: InputConverter<From = I>,
|
||||
SP: ShMemProvider,
|
||||
IC::To: Serialize,
|
||||
{
|
||||
@ -362,11 +359,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "llmp_compression")]
|
||||
fn fire(
|
||||
&mut self,
|
||||
_state: &mut S,
|
||||
event: Event<<S::Corpus as Corpus>::Input>,
|
||||
) -> Result<(), Error> {
|
||||
fn fire(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> {
|
||||
if self.converter.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
@ -418,11 +411,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "llmp_compression"))]
|
||||
fn fire(
|
||||
&mut self,
|
||||
_state: &mut S,
|
||||
event: Event<<S::Corpus as Corpus>::Input>,
|
||||
) -> Result<(), Error> {
|
||||
fn fire(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> {
|
||||
if self.converter.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ use typed_builder::TypedBuilder;
|
||||
use crate::events::EVENTMGR_SIGHANDLER_STATE;
|
||||
use crate::{
|
||||
common::HasMetadata,
|
||||
corpus::Corpus,
|
||||
events::{
|
||||
launcher::ClientDescription, serialize_observers_adaptive, std_maybe_report_progress,
|
||||
std_report_progress, AdaptiveSerializer, CanSerializeObserver, Event, EventConfig,
|
||||
@ -47,28 +46,25 @@ use crate::{
|
||||
monitors::Monitor,
|
||||
observers::TimeObserver,
|
||||
stages::HasCurrentStageId,
|
||||
state::{
|
||||
HasCorpus, HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor,
|
||||
Stoppable,
|
||||
},
|
||||
state::{HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor, Stoppable},
|
||||
Error,
|
||||
};
|
||||
|
||||
/// A manager that can restart on the fly, storing states in-between (in `on_restart`)
|
||||
#[derive(Debug)]
|
||||
pub struct LlmpRestartingEventManager<EMH, S, SP>
|
||||
pub struct LlmpRestartingEventManager<EMH, I, S, SP>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
/// 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
|
||||
staterestorer: StateRestorer<SP>,
|
||||
/// Decide if the state restorer must save the serialized state
|
||||
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
|
||||
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
|
||||
S: HasExecutions
|
||||
+ HasLastReportTime
|
||||
+ HasMetadata
|
||||
+ HasCorpus
|
||||
+ Serialize
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
S: HasExecutions + HasLastReportTime + HasMetadata + Serialize + MaybeHasClientPerfMonitor,
|
||||
SP: ShMemProvider,
|
||||
<S::Corpus as Corpus>::Input: Serialize,
|
||||
I: Serialize,
|
||||
{
|
||||
fn maybe_report_progress(
|
||||
&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
|
||||
I: Serialize,
|
||||
S: HasCorpus + Serialize,
|
||||
S: Serialize,
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
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> {
|
||||
@ -145,12 +136,12 @@ where
|
||||
}
|
||||
|
||||
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")]
|
||||
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
|
||||
SP: ShMemProvider,
|
||||
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
|
||||
SP: ShMemProvider,
|
||||
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
|
||||
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
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
E: HasObservers,
|
||||
E::Observers: DeserializeOwned,
|
||||
S: HasCorpus + HasImported + Stoppable + Serialize,
|
||||
<S::Corpus as Corpus>::Input: DeserializeOwned + Input,
|
||||
S::Corpus: Serialize,
|
||||
S: HasImported + Stoppable + Serialize,
|
||||
I: DeserializeOwned + Input,
|
||||
SP: ShMemProvider,
|
||||
Z: ExecutionProcessor<
|
||||
LlmpEventManager<EMH, S, SP>,
|
||||
<S::Corpus as Corpus>::Input,
|
||||
E::Observers,
|
||||
S,
|
||||
> + EvaluatorObservers<E, LlmpEventManager<EMH, S, SP>, <S::Corpus as Corpus>::Input, S>,
|
||||
Z: ExecutionProcessor<LlmpEventManager<EMH, I, S, SP>, I, E::Observers, S>
|
||||
+ EvaluatorObservers<E, LlmpEventManager<EMH, I, S, SP>, I, S>,
|
||||
{
|
||||
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)?;
|
||||
@ -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
|
||||
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)
|
||||
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
|
||||
SP: ShMemProvider,
|
||||
S: Serialize,
|
||||
{
|
||||
/// 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 {
|
||||
llmp_mgr,
|
||||
staterestorer,
|
||||
@ -263,7 +252,7 @@ where
|
||||
|
||||
/// Create a new runner specifying if it must save the serialized state on restart.
|
||||
pub fn with_save_state(
|
||||
llmp_mgr: LlmpEventManager<EMH, S, SP>,
|
||||
llmp_mgr: LlmpEventManager<EMH, I, S, SP>,
|
||||
staterestorer: StateRestorer<SP>,
|
||||
save_state: LlmpShouldSaveState,
|
||||
) -> 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 restarter will spawn a new process each time the child crashes or timeouts.
|
||||
#[expect(clippy::type_complexity)]
|
||||
pub fn setup_restarting_mgr_std<MT, S>(
|
||||
pub fn setup_restarting_mgr_std<I, MT, S>(
|
||||
monitor: MT,
|
||||
broker_port: u16,
|
||||
configuration: EventConfig,
|
||||
) -> Result<
|
||||
(
|
||||
Option<S>,
|
||||
LlmpRestartingEventManager<(), S, StdShMemProvider>,
|
||||
LlmpRestartingEventManager<(), I, S, StdShMemProvider>,
|
||||
),
|
||||
Error,
|
||||
>
|
||||
where
|
||||
MT: Monitor + Clone,
|
||||
S: HasCorpus + Serialize + DeserializeOwned,
|
||||
<S::Corpus as Corpus>::Input: DeserializeOwned,
|
||||
S: Serialize + DeserializeOwned,
|
||||
I: DeserializeOwned,
|
||||
{
|
||||
RestartingMgr::builder()
|
||||
.shmem_provider(StdShMemProvider::new()?)
|
||||
@ -347,7 +336,7 @@ where
|
||||
/// The restarter will spawn a new process each time the child crashes or timeouts.
|
||||
/// This one, additionally uses the timeobserver for the adaptive serialization
|
||||
#[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,
|
||||
broker_port: u16,
|
||||
configuration: EventConfig,
|
||||
@ -355,14 +344,14 @@ pub fn setup_restarting_mgr_std_adaptive<MT, S>(
|
||||
) -> Result<
|
||||
(
|
||||
Option<S>,
|
||||
LlmpRestartingEventManager<(), S, StdShMemProvider>,
|
||||
LlmpRestartingEventManager<(), I, S, StdShMemProvider>,
|
||||
),
|
||||
Error,
|
||||
>
|
||||
where
|
||||
MT: Monitor + Clone,
|
||||
S: HasCorpus + Serialize + DeserializeOwned,
|
||||
<S::Corpus as Corpus>::Input: DeserializeOwned,
|
||||
S: Serialize + DeserializeOwned,
|
||||
I: DeserializeOwned,
|
||||
{
|
||||
RestartingMgr::builder()
|
||||
.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` will start a new process each time the child crashes or times out.
|
||||
#[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
|
||||
/// manager.
|
||||
shmem_provider: SP,
|
||||
@ -415,20 +404,22 @@ pub struct RestartingMgr<EMH, MT, S, SP> {
|
||||
#[builder(default = None)]
|
||||
time_ref: Option<Handle<TimeObserver>>,
|
||||
#[builder(setter(skip), default = PhantomData)]
|
||||
phantom_data: PhantomData<(EMH, S)>,
|
||||
phantom_data: PhantomData<(EMH, I, S)>,
|
||||
}
|
||||
|
||||
#[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
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S> + Copy + Clone,
|
||||
EMH: EventManagerHooksTuple<I, S> + Copy + Clone,
|
||||
SP: ShMemProvider,
|
||||
S: HasCorpus + Serialize + DeserializeOwned,
|
||||
<S::Corpus as Corpus>::Input: DeserializeOwned,
|
||||
S: Serialize + DeserializeOwned,
|
||||
I: DeserializeOwned,
|
||||
MT: Monitor + Clone,
|
||||
{
|
||||
/// 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
|
||||
let (staterestorer, new_shmem_provider, core_id) = if std::env::var(_ENV_FUZZER_SENDER)
|
||||
.is_err()
|
||||
@ -458,9 +449,7 @@ where
|
||||
match connection {
|
||||
LlmpConnection::IsBroker { broker } => {
|
||||
let llmp_hook =
|
||||
StdLlmpEventHook::<<S::Corpus as Corpus>::Input, MT>::new(
|
||||
self.monitor.take().unwrap(),
|
||||
)?;
|
||||
StdLlmpEventHook::<I, MT>::new(self.monitor.take().unwrap())?;
|
||||
|
||||
// Yep, broker. Just loop here.
|
||||
log::info!(
|
||||
@ -475,7 +464,7 @@ where
|
||||
return Err(Error::shutting_down());
|
||||
}
|
||||
LlmpConnection::IsClient { client } => {
|
||||
let mgr: LlmpEventManager<EMH, S, SP> = LlmpEventManager::builder()
|
||||
let mgr: LlmpEventManager<EMH, I, S, SP> = LlmpEventManager::builder()
|
||||
.hooks(self.hooks)
|
||||
.build_from_client(
|
||||
client,
|
||||
|
@ -45,11 +45,10 @@ use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
executors::ExitKind,
|
||||
inputs::Input,
|
||||
monitors::UserStats,
|
||||
state::{HasCorpus, HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor},
|
||||
state::{HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
|
||||
@ -489,10 +488,10 @@ where
|
||||
|
||||
/// Default implementation of [`ProgressReporter::report_progress`] for implementors with the
|
||||
/// 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
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasExecutions + HasLastReportTime + HasCorpus + MaybeHasClientPerfMonitor,
|
||||
EM: EventFirer<I, S>,
|
||||
S: HasExecutions + HasLastReportTime + MaybeHasClientPerfMonitor,
|
||||
{
|
||||
let executions = *state.executions();
|
||||
let cur = current_time();
|
||||
|
@ -22,7 +22,6 @@ use super::{std_on_restart, ProgressReporter};
|
||||
#[cfg(all(unix, feature = "std", not(miri)))]
|
||||
use crate::events::EVENTMGR_SIGHANDLER_STATE;
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
events::{
|
||||
std_maybe_report_progress, std_report_progress, BrokerEventResult, CanSerializeObserver,
|
||||
Event, EventFirer, EventManagerId, EventProcessor, EventRestarter, HasEventManagerId,
|
||||
@ -30,7 +29,7 @@ use crate::{
|
||||
},
|
||||
monitors::Monitor,
|
||||
stages::HasCurrentStageId,
|
||||
state::{HasCorpus, HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor, Stoppable},
|
||||
state::{HasExecutions, HasLastReportTime, MaybeHasClientPerfMonitor, Stoppable},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
@ -141,13 +140,7 @@ impl<I, MT, S> ProgressReporter<S> for SimpleEventManager<I, MT, S>
|
||||
where
|
||||
I: Debug,
|
||||
MT: Monitor,
|
||||
S: HasMetadata
|
||||
+ HasExecutions
|
||||
+ HasLastReportTime
|
||||
+ Stoppable
|
||||
+ HasCorpus
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
S::Corpus: Corpus<Input = I>,
|
||||
S: HasMetadata + HasExecutions + HasLastReportTime + Stoppable + MaybeHasClientPerfMonitor,
|
||||
{
|
||||
fn maybe_report_progress(
|
||||
&mut self,
|
||||
@ -383,13 +376,7 @@ where
|
||||
I: Debug,
|
||||
MT: Monitor,
|
||||
SP: ShMemProvider,
|
||||
S: HasExecutions
|
||||
+ HasMetadata
|
||||
+ HasLastReportTime
|
||||
+ Stoppable
|
||||
+ HasCorpus
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
S::Corpus: Corpus<Input = I>,
|
||||
S: HasExecutions + HasMetadata + HasLastReportTime + Stoppable + MaybeHasClientPerfMonitor,
|
||||
{
|
||||
fn maybe_report_progress(
|
||||
&mut self,
|
||||
@ -435,7 +422,7 @@ where
|
||||
/// 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>
|
||||
where
|
||||
S: DeserializeOwned + Serialize + HasCorpus + HasSolutions,
|
||||
S: DeserializeOwned + Serialize + HasSolutions<I>,
|
||||
MT: Debug,
|
||||
{
|
||||
// We start ourself as child process to actually fuzz
|
||||
|
@ -42,7 +42,6 @@ use super::{std_maybe_report_progress, std_report_progress, ManagerExit};
|
||||
#[cfg(all(unix, not(miri)))]
|
||||
use crate::events::EVENTMGR_SIGHANDLER_STATE;
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
events::{
|
||||
std_on_restart, BrokerEventResult, Event, EventConfig, EventFirer, EventManagerHooksTuple,
|
||||
EventManagerId, EventProcessor, EventRestarter, HasEventManagerId, ProgressReporter,
|
||||
@ -53,10 +52,7 @@ use crate::{
|
||||
monitors::Monitor,
|
||||
observers::ObserversTuple,
|
||||
stages::HasCurrentStageId,
|
||||
state::{
|
||||
HasCorpus, HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor,
|
||||
Stoppable,
|
||||
},
|
||||
state::{HasExecutions, HasImported, HasLastReportTime, MaybeHasClientPerfMonitor, Stoppable},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
|
||||
@ -409,7 +405,7 @@ where
|
||||
}
|
||||
|
||||
/// 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
|
||||
throttle: Option<Duration>,
|
||||
/// 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
|
||||
/// from nodes with other configurations.
|
||||
configuration: EventConfig,
|
||||
phantom: PhantomData<S>,
|
||||
phantom: PhantomData<(I, S)>,
|
||||
}
|
||||
|
||||
impl<S> TcpEventManager<(), S> {
|
||||
impl<I, S> TcpEventManager<(), I, S> {
|
||||
/// Create a builder for [`TcpEventManager`]
|
||||
#[must_use]
|
||||
pub fn builder() -> TcpEventManagerBuilder<(), S> {
|
||||
pub fn builder() -> TcpEventManagerBuilder<(), I, S> {
|
||||
TcpEventManagerBuilder::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for `TcpEventManager`
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TcpEventManagerBuilder<EMH, S> {
|
||||
pub struct TcpEventManagerBuilder<EMH, I, S> {
|
||||
throttle: Option<Duration>,
|
||||
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 {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> TcpEventManagerBuilder<(), S> {
|
||||
impl<I, S> TcpEventManagerBuilder<(), I, S> {
|
||||
/// Set the constructor
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
@ -463,7 +459,7 @@ impl<S> TcpEventManagerBuilder<(), S> {
|
||||
|
||||
/// Set the hooks
|
||||
#[must_use]
|
||||
pub fn hooks<EMH>(self, hooks: EMH) -> TcpEventManagerBuilder<EMH, S> {
|
||||
pub fn hooks<EMH>(self, hooks: EMH) -> TcpEventManagerBuilder<EMH, I, S> {
|
||||
TcpEventManagerBuilder {
|
||||
throttle: self.throttle,
|
||||
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
|
||||
#[must_use]
|
||||
pub fn throttle(mut self, throttle: Duration) -> Self {
|
||||
@ -486,7 +482,7 @@ impl<EMH, S> TcpEventManagerBuilder<EMH, S> {
|
||||
addr: &A,
|
||||
client_id: ClientId,
|
||||
configuration: EventConfig,
|
||||
) -> Result<TcpEventManager<EMH, S>, Error> {
|
||||
) -> Result<TcpEventManager<EMH, I, S>, Error> {
|
||||
let mut tcp = TcpStream::connect(addr)?;
|
||||
|
||||
let mut our_client_id_buf = client_id.0.to_le_bytes();
|
||||
@ -521,7 +517,7 @@ impl<EMH, S> TcpEventManagerBuilder<EMH, S> {
|
||||
port: u16,
|
||||
client_id: ClientId,
|
||||
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)
|
||||
}
|
||||
|
||||
@ -534,13 +530,13 @@ impl<EMH, S> TcpEventManagerBuilder<EMH, S> {
|
||||
addr: &A,
|
||||
env_name: &str,
|
||||
configuration: EventConfig,
|
||||
) -> Result<TcpEventManager<EMH, S>, Error> {
|
||||
) -> Result<TcpEventManager<EMH, I, S>, Error> {
|
||||
let this_id = ClientId(str::parse::<u32>(&env::var(env_name)?)?);
|
||||
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 {
|
||||
let mut debug_struct = f.debug_struct("TcpEventManager");
|
||||
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.
|
||||
fn drop(&mut self) {
|
||||
self.await_restart_safe();
|
||||
}
|
||||
}
|
||||
|
||||
impl<EMH, S> TcpEventManager<EMH, S>
|
||||
impl<EMH, I, S> TcpEventManager<EMH, I, S>
|
||||
where
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasExecutions + HasMetadata + HasImported + HasCorpus + Stoppable,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
S: HasExecutions + HasMetadata + HasImported + Stoppable,
|
||||
{
|
||||
/// Write the client id for a client `EventManager` to env vars
|
||||
pub fn to_env(&self, env_name: &str) {
|
||||
@ -578,14 +574,13 @@ where
|
||||
executor: &mut E,
|
||||
state: &mut S,
|
||||
client_id: ClientId,
|
||||
event: Event<<S::Corpus as Corpus>::Input>,
|
||||
event: Event<I>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
E: Executor<Self, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
E::Observers: Serialize + ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
E: Executor<Self, I, S, Z> + HasObservers,
|
||||
E::Observers: Serialize + ObserversTuple<I, S>,
|
||||
for<'a> E::Observers: Deserialize<'a>,
|
||||
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S>
|
||||
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
|
||||
Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
|
||||
{
|
||||
if !self.hooks.pre_exec_all(state, client_id, &event)? {
|
||||
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.
|
||||
/// The other side may free up all allocated memory.
|
||||
/// 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
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus,
|
||||
<S::Corpus as Corpus>::Input: Serialize,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
I: Serialize,
|
||||
{
|
||||
fn should_send(&self) -> bool {
|
||||
if let Some(throttle) = self.throttle {
|
||||
@ -655,11 +649,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn fire(
|
||||
&mut self,
|
||||
_state: &mut S,
|
||||
event: Event<<S::Corpus as Corpus>::Input>,
|
||||
) -> Result<(), Error> {
|
||||
fn fire(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> {
|
||||
let serialized = postcard::to_allocvec(&event)?;
|
||||
|
||||
#[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
|
||||
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
|
||||
E: HasObservers + Executor<Self, <S::Corpus as Corpus>::Input, S, Z>,
|
||||
E::Observers: Serialize + ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
E: HasObservers + Executor<Self, I, S, Z>,
|
||||
E::Observers: Serialize + ObserversTuple<I, S>,
|
||||
for<'a> E::Observers: Deserialize<'a>,
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasExecutions + HasMetadata + HasImported + HasCorpus + Stoppable,
|
||||
<S::Corpus as Corpus>::Input: DeserializeOwned,
|
||||
Z: ExecutionProcessor<Self, <S::Corpus as Corpus>::Input, E::Observers, S>
|
||||
+ EvaluatorObservers<E, Self, <S::Corpus as Corpus>::Input, S>,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
S: HasExecutions + HasMetadata + HasImported + Stoppable,
|
||||
I: DeserializeOwned,
|
||||
Z: ExecutionProcessor<Self, I, E::Observers, S> + EvaluatorObservers<E, Self, I, S>,
|
||||
{
|
||||
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
|
||||
@ -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.
|
||||
/// Otherwise, the OS may already have removed the shared maps.
|
||||
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
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
<S::Corpus as Corpus>::Input: Serialize,
|
||||
S: HasExecutions + HasMetadata + HasLastReportTime + HasCorpus + MaybeHasClientPerfMonitor,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
I: Serialize,
|
||||
S: HasExecutions + HasMetadata + HasLastReportTime + MaybeHasClientPerfMonitor,
|
||||
{
|
||||
fn maybe_report_progress(
|
||||
&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.
|
||||
fn mgr_id(&self) -> EventManagerId {
|
||||
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`)
|
||||
#[derive(Debug)]
|
||||
pub struct TcpRestartingEventManager<EMH, S, SP>
|
||||
pub struct TcpRestartingEventManager<EMH, I, S, SP>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
/// 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
|
||||
staterestorer: StateRestorer<SP>,
|
||||
/// Decide if the state restorer must save the serialized state
|
||||
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
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasMetadata + HasExecutions + HasLastReportTime + HasCorpus + MaybeHasClientPerfMonitor,
|
||||
<S::Corpus as Corpus>::Input: Serialize,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
S: HasMetadata + HasExecutions + HasLastReportTime + MaybeHasClientPerfMonitor,
|
||||
I: Serialize,
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
fn maybe_report_progress(
|
||||
@ -833,23 +822,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<EMH, S, SP> EventFirer<<S::Corpus as Corpus>::Input, S>
|
||||
for TcpRestartingEventManager<EMH, S, SP>
|
||||
impl<EMH, I, S, SP> EventFirer<I, S> for TcpRestartingEventManager<EMH, I, S, SP>
|
||||
where
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus,
|
||||
<S::Corpus as Corpus>::Input: Serialize,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
I: Serialize,
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
fn should_send(&self) -> bool {
|
||||
self.tcp_mgr.should_send()
|
||||
}
|
||||
|
||||
fn fire(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
event: Event<<S::Corpus as Corpus>::Input>,
|
||||
) -> Result<(), Error> {
|
||||
fn fire(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error> {
|
||||
// Check if we are going to crash in the event, in which case we store our current state for the next runner
|
||||
self.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
|
||||
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
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus + HasExecutions + HasCurrentStageId + Serialize,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
S: HasExecutions + HasCurrentStageId + Serialize,
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
/// 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
|
||||
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>,
|
||||
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasExecutions + HasMetadata + HasImported + HasCorpus + Stoppable,
|
||||
<S::Corpus as Corpus>::Input: DeserializeOwned,
|
||||
E::Observers: ObserversTuple<I, S> + Serialize,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
I: DeserializeOwned,
|
||||
S: HasExecutions + HasMetadata + HasImported + Stoppable,
|
||||
SP: ShMemProvider,
|
||||
Z: ExecutionProcessor<TcpEventManager<EMH, S>, <S::Corpus as Corpus>::Input, E::Observers, S>
|
||||
+ EvaluatorObservers<E, TcpEventManager<EMH, S>, <S::Corpus as Corpus>::Input, S>,
|
||||
Z: ExecutionProcessor<TcpEventManager<EMH, I, S>, I, E::Observers, 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> {
|
||||
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
|
||||
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)
|
||||
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
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus,
|
||||
EMH: EventManagerHooksTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
//CE: CustomEvent<I>,
|
||||
{
|
||||
/// 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 {
|
||||
tcp_mgr,
|
||||
staterestorer,
|
||||
@ -955,7 +936,7 @@ where
|
||||
|
||||
/// Create a new runner specifying if it must save the serialized state on restart.
|
||||
pub fn with_save_state(
|
||||
tcp_mgr: TcpEventManager<EMH, S>,
|
||||
tcp_mgr: TcpEventManager<EMH, I, S>,
|
||||
staterestorer: StateRestorer<SP>,
|
||||
save_state: bool,
|
||||
) -> 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 restarter will spawn a new process each time the child crashes or timeouts.
|
||||
#[expect(clippy::type_complexity)]
|
||||
pub fn setup_restarting_mgr_tcp<MT, S>(
|
||||
pub fn setup_restarting_mgr_tcp<I, MT, S>(
|
||||
monitor: MT,
|
||||
broker_port: u16,
|
||||
configuration: EventConfig,
|
||||
) -> Result<
|
||||
(
|
||||
Option<S>,
|
||||
TcpRestartingEventManager<(), S, StdShMemProvider>,
|
||||
TcpRestartingEventManager<(), I, S, StdShMemProvider>,
|
||||
),
|
||||
Error,
|
||||
>
|
||||
where
|
||||
MT: Monitor + Clone,
|
||||
S: HasExecutions + HasMetadata + HasImported + HasCorpus + DeserializeOwned + Stoppable,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
S: HasExecutions + HasMetadata + HasImported + DeserializeOwned + Stoppable,
|
||||
I: Input,
|
||||
{
|
||||
TcpRestartingMgr::builder()
|
||||
.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` will start a new process each time the child crashes or times out.
|
||||
#[derive(TypedBuilder, Debug)]
|
||||
pub struct TcpRestartingMgr<EMH, MT, S, SP>
|
||||
pub struct TcpRestartingMgr<EMH, I, MT, S, SP>
|
||||
where
|
||||
MT: Monitor,
|
||||
S: DeserializeOwned,
|
||||
SP: ShMemProvider + 'static,
|
||||
MT: Monitor,
|
||||
{
|
||||
/// The shared memory provider to use for the broker or client spawned by the restarting
|
||||
/// manager.
|
||||
@ -1065,25 +1046,26 @@ where
|
||||
/// The hooks for `handle_in_client`
|
||||
hooks: EMH,
|
||||
#[builder(setter(skip), default = PhantomData)]
|
||||
phantom_data: PhantomData<S>,
|
||||
phantom_data: PhantomData<(I, S)>,
|
||||
}
|
||||
|
||||
#[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
|
||||
EMH: EventManagerHooksTuple<<S::Corpus as Corpus>::Input, S> + Copy + Clone,
|
||||
SP: ShMemProvider,
|
||||
S: HasExecutions + HasMetadata + HasImported + HasCorpus + DeserializeOwned + Stoppable,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
EMH: EventManagerHooksTuple<I, S> + Copy + Clone,
|
||||
I: Input,
|
||||
MT: Monitor + Clone,
|
||||
SP: ShMemProvider,
|
||||
S: HasExecutions + HasMetadata + HasImported + DeserializeOwned + Stoppable,
|
||||
{
|
||||
/// 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
|
||||
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>,
|
||||
_remote_broker_addr| {
|
||||
let broker_things = |mut broker: TcpEventBroker<I, MT>, _remote_broker_addr| {
|
||||
if let Some(exit_cleanly_after) = self.exit_cleanly_after {
|
||||
broker.set_exit_cleanly_after(exit_cleanly_after);
|
||||
}
|
||||
@ -1097,11 +1079,10 @@ where
|
||||
let connection = create_nonblocking_listener(("127.0.0.1", self.broker_port));
|
||||
match connection {
|
||||
Ok(listener) => {
|
||||
let event_broker =
|
||||
TcpEventBroker::<<S::Corpus as Corpus>::Input, MT>::with_listener(
|
||||
listener,
|
||||
self.monitor.take().unwrap(),
|
||||
);
|
||||
let event_broker = TcpEventBroker::<I, MT>::with_listener(
|
||||
listener,
|
||||
self.monitor.take().unwrap(),
|
||||
);
|
||||
|
||||
// Yep, broker. Just loop here.
|
||||
log::info!(
|
||||
@ -1129,7 +1110,7 @@ where
|
||||
}
|
||||
}
|
||||
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),
|
||||
self.monitor.take().unwrap(),
|
||||
)?;
|
||||
|
@ -49,11 +49,10 @@ use super::HasTimeout;
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::executors::hooks::ExecutorHooksTuple;
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
executors::{Executor, ExitKind, HasObservers},
|
||||
inputs::HasTargetBytes,
|
||||
observers::{ObserversTuple, StdErrObserver, StdOutObserver},
|
||||
state::{HasCorpus, HasExecutions},
|
||||
state::HasExecutions,
|
||||
std::borrow::ToOwned,
|
||||
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.
|
||||
/// 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
|
||||
configurer: T,
|
||||
/// The observers used by this executor
|
||||
observers: OT,
|
||||
hooks: HT,
|
||||
phantom: PhantomData<S>,
|
||||
phantom_child: PhantomData<C>,
|
||||
phantom: PhantomData<(C, I, S)>,
|
||||
}
|
||||
|
||||
impl CommandExecutor<(), (), ()> {
|
||||
impl CommandExecutor<(), (), (), ()> {
|
||||
/// Creates a builder for a new [`CommandExecutor`],
|
||||
/// backed by a [`StdCommandConfigurator`]
|
||||
/// 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
|
||||
T: 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
|
||||
pub fn inner(&mut self) -> &mut T {
|
||||
&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
|
||||
impl<OT, S, T> CommandExecutor<OT, S, T>
|
||||
impl<I, OT, S, T> CommandExecutor<I, OT, S, T>
|
||||
where
|
||||
S: HasExecutions + HasCorpus,
|
||||
T: CommandConfigurator<<S::Corpus as Corpus>::Input> + Debug,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasExecutions,
|
||||
T: CommandConfigurator<I> + Debug,
|
||||
OT: ObserversTuple<I, S>,
|
||||
{
|
||||
fn execute_input_with_command(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
) -> Result<ExitKind, Error> {
|
||||
fn execute_input_with_command(&mut self, state: &mut S, input: &I) -> Result<ExitKind, Error> {
|
||||
use wait_timeout::ChildExt;
|
||||
|
||||
*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
|
||||
S: HasExecutions + HasCorpus,
|
||||
T: CommandConfigurator<<S::Corpus as Corpus>::Input> + Debug,
|
||||
OT: MatchName + ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasExecutions,
|
||||
T: CommandConfigurator<I> + Debug,
|
||||
OT: MatchName + ObserversTuple<I, S>,
|
||||
{
|
||||
fn run_target(
|
||||
&mut self,
|
||||
_fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
_mgr: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
self.execute_input_with_command(state, input)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
S: HasCorpus,
|
||||
T: CommandConfigurator<<S::Corpus as Corpus>::Input>,
|
||||
T: CommandConfigurator<I>,
|
||||
{
|
||||
#[inline]
|
||||
fn timeout(&self) -> Duration {
|
||||
@ -426,13 +419,12 @@ where
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl<EM, OT, S, T, Z, HT> Executor<EM, <S::Corpus as Corpus>::Input, S, Z>
|
||||
for CommandExecutor<OT, S, T, HT, Pid>
|
||||
impl<EM, I, OT, S, T, Z, HT> Executor<EM, I, S, Z> for CommandExecutor<I, OT, S, T, HT, Pid>
|
||||
where
|
||||
S: HasCorpus + HasExecutions,
|
||||
T: CommandConfigurator<<S::Corpus as Corpus>::Input, Pid> + Debug,
|
||||
OT: MatchName + ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
HT: ExecutorHooksTuple<I, S>,
|
||||
OT: MatchName + ObserversTuple<I, S>,
|
||||
S: HasExecutions,
|
||||
T: CommandConfigurator<I, Pid> + Debug,
|
||||
{
|
||||
/// Linux specific low level implementation, to directly handle `fork`, `exec` and use linux
|
||||
/// `ptrace`
|
||||
@ -444,7 +436,7 @@ where
|
||||
_fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
_mgr: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
*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
|
||||
S: HasCorpus,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
{
|
||||
type Observers = OT;
|
||||
|
||||
@ -683,14 +674,13 @@ impl CommandExecutorBuilder {
|
||||
}
|
||||
|
||||
/// Builds the `CommandExecutor`
|
||||
pub fn build<OT, S>(
|
||||
pub fn build<I, OT, S>(
|
||||
&self,
|
||||
observers: OT,
|
||||
) -> Result<CommandExecutor<OT, S, StdCommandConfigurator>, Error>
|
||||
) -> Result<CommandExecutor<I, OT, S, StdCommandConfigurator>, Error>
|
||||
where
|
||||
S: HasCorpus,
|
||||
<S::Corpus as Corpus>::Input: HasTargetBytes,
|
||||
OT: MatchName + ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
I: HasTargetBytes,
|
||||
OT: MatchName + ObserversTuple<I, S>,
|
||||
{
|
||||
let Some(program) = &self.program else {
|
||||
return Err(Error::illegal_argument(
|
||||
@ -737,9 +727,12 @@ impl CommandExecutorBuilder {
|
||||
timeout: self.timeout,
|
||||
command,
|
||||
};
|
||||
Ok(<StdCommandConfigurator as CommandConfigurator<
|
||||
<S::Corpus as Corpus>::Input,
|
||||
>>::into_executor::<OT, S>(configurator, observers))
|
||||
Ok(
|
||||
<StdCommandConfigurator as CommandConfigurator<I>>::into_executor::<OT, S>(
|
||||
configurator,
|
||||
observers,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -747,7 +740,7 @@ impl CommandExecutorBuilder {
|
||||
/// # Example
|
||||
/// ```
|
||||
/// 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;
|
||||
/// #[derive(Debug)]
|
||||
/// struct MyExecutor;
|
||||
@ -779,8 +772,7 @@ impl CommandExecutorBuilder {
|
||||
///
|
||||
/// fn make_executor<EM, S, Z>() -> impl Executor<EM, BytesInput, S, Z>
|
||||
/// where
|
||||
/// S: HasCorpus + HasExecutions,
|
||||
/// S::Corpus: Corpus<Input = BytesInput>
|
||||
/// S: HasExecutions,
|
||||
/// {
|
||||
/// MyExecutor.into_executor(())
|
||||
/// }
|
||||
@ -816,13 +808,12 @@ pub trait CommandConfigurator<I, C = Child>: Sized {
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
configurer: self,
|
||||
observers,
|
||||
hooks: (),
|
||||
phantom: PhantomData,
|
||||
phantom_child: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -831,13 +822,12 @@ pub trait CommandConfigurator<I, C = Child>: Sized {
|
||||
self,
|
||||
observers: OT,
|
||||
hooks: HT,
|
||||
) -> CommandExecutor<OT, S, Self, HT, C> {
|
||||
) -> CommandExecutor<I, OT, S, Self, HT, C> {
|
||||
CommandExecutor {
|
||||
configurer: self,
|
||||
observers,
|
||||
hooks,
|
||||
phantom: PhantomData,
|
||||
phantom_child: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -890,7 +880,7 @@ mod tests {
|
||||
executor
|
||||
.run_target(
|
||||
&mut NopFuzzer::new(),
|
||||
&mut NopState::new(),
|
||||
&mut NopState::<NopInput>::new(),
|
||||
&mut mgr,
|
||||
&BytesInput::new(b"test".to_vec()),
|
||||
)
|
||||
|
@ -19,23 +19,21 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::HasTimeout;
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
executors::{Executor, ExitKind, HasObservers},
|
||||
observers::{DifferentialObserversTuple, ObserversTuple},
|
||||
state::HasCorpus,
|
||||
Error,
|
||||
};
|
||||
|
||||
/// A [`DiffExecutor`] wraps a primary executor, forwarding its methods, and a secondary one
|
||||
#[derive(Debug)]
|
||||
pub struct DiffExecutor<A, B, DOT, OTA, OTB, S> {
|
||||
pub struct DiffExecutor<A, B, DOT, I, OTA, OTB, S> {
|
||||
primary: A,
|
||||
secondary: B,
|
||||
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.
|
||||
pub fn new(primary: A, secondary: B, observers: DOT) -> 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>
|
||||
for DiffExecutor<A, B, DOT, A::Observers, B::Observers, S>
|
||||
impl<A, B, DOT, EM, I, S, Z> Executor<EM, I, S, Z>
|
||||
for DiffExecutor<A, B, DOT, I, A::Observers, B::Observers, S>
|
||||
where
|
||||
A: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
B: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
<A as HasObservers>::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
<B as HasObservers>::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
DOT: DifferentialObserversTuple<A::Observers, B::Observers, <S::Corpus as Corpus>::Input, S>
|
||||
+ MatchName,
|
||||
S: HasCorpus,
|
||||
A: Executor<EM, I, S, Z> + HasObservers,
|
||||
B: Executor<EM, I, S, Z> + HasObservers,
|
||||
<A as HasObservers>::Observers: ObserversTuple<I, S>,
|
||||
<B as HasObservers>::Observers: ObserversTuple<I, S>,
|
||||
DOT: DifferentialObserversTuple<A::Observers, B::Observers, I, S> + MatchName,
|
||||
{
|
||||
fn run_target(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
mgr: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
self.observers(); // update in advance
|
||||
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
|
||||
A: 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
|
||||
A: HasObservers<Observers = OTA>,
|
||||
B: HasObservers<Observers = OTB>,
|
||||
DOT: DifferentialObserversTuple<OTA, OTB, <S::Corpus as Corpus>::Input, S> + MatchName,
|
||||
OTA: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
OTB: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus,
|
||||
DOT: DifferentialObserversTuple<OTA, OTB, I, S> + MatchName,
|
||||
OTA: ObserversTuple<I, S>,
|
||||
OTB: ObserversTuple<I, S>,
|
||||
{
|
||||
type Observers = ProxyObserversTuple<OTA, OTB, DOT>;
|
||||
|
||||
|
@ -43,12 +43,11 @@ use crate::observers::{
|
||||
get_asan_runtime_flags, get_asan_runtime_flags_with_log_path, AsanBacktraceObserver,
|
||||
};
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
executors::{Executor, ExitKind, HasObservers},
|
||||
inputs::{BytesInput, Input, NopTargetBytesConverter, TargetBytesConverter},
|
||||
inputs::{BytesInput, HasTargetBytes, Input, NopTargetBytesConverter, TargetBytesConverter},
|
||||
mutators::Tokens,
|
||||
observers::{MapObserver, Observer, ObserversTuple},
|
||||
state::{HasCorpus, HasExecutions},
|
||||
state::HasExecutions,
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -607,7 +606,7 @@ impl Forkserver {
|
||||
///
|
||||
/// 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>
|
||||
pub struct ForkserverExecutor<TC, OT, S, SP>
|
||||
pub struct ForkserverExecutor<I, OT, S, SP, TC>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
@ -619,7 +618,7 @@ where
|
||||
forkserver: Forkserver,
|
||||
observers: OT,
|
||||
map: Option<SP::ShMem>,
|
||||
phantom: PhantomData<S>,
|
||||
phantom: PhantomData<(I, S)>,
|
||||
map_size: Option<usize>,
|
||||
min_input_size: usize,
|
||||
max_input_size: usize,
|
||||
@ -629,7 +628,7 @@ where
|
||||
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
|
||||
TC: Debug,
|
||||
OT: Debug,
|
||||
@ -649,7 +648,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl ForkserverExecutor<(), (), (), UnixShMemProvider> {
|
||||
impl ForkserverExecutor<(), (), (), UnixShMemProvider, ()> {
|
||||
/// Builder for `ForkserverExecutor`
|
||||
#[must_use]
|
||||
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
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus,
|
||||
OT: ObserversTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
TC: TargetBytesConverter,
|
||||
TC: TargetBytesConverter<I>,
|
||||
{
|
||||
/// The `target` binary that's going to run.
|
||||
pub fn target(&self) -> &OsString {
|
||||
@ -698,7 +696,7 @@ where
|
||||
|
||||
/// Execute input and increase the execution counter.
|
||||
#[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
|
||||
S: HasExecutions,
|
||||
{
|
||||
@ -709,7 +707,7 @@ where
|
||||
|
||||
/// Execute input, but side-step the execution counter.
|
||||
#[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 last_run_timed_out = self.forkserver.last_run_timed_out_raw();
|
||||
@ -839,13 +837,14 @@ where
|
||||
/// in case no input file is specified.
|
||||
/// If `debug_child` is set, the child will print to `stdout`/`stderr`.
|
||||
#[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
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
TC: TargetBytesConverter,
|
||||
OT: ObserversTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
TC: TargetBytesConverter<I>,
|
||||
{
|
||||
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.
|
||||
#[expect(clippy::pedantic)]
|
||||
pub fn build_dynamic_map<A, MO, OT, S>(
|
||||
#[expect(clippy::pedantic, clippy::type_complexity)]
|
||||
pub fn build_dynamic_map<A, MO, OT, I, S>(
|
||||
mut self,
|
||||
mut map_observer: A,
|
||||
other_observers: OT,
|
||||
) -> Result<ForkserverExecutor<TC, (A, OT), S, SP>, Error>
|
||||
) -> Result<ForkserverExecutor<I, (A, OT), S, SP, TC>, Error>
|
||||
where
|
||||
A: Observer<I, S> + AsMut<MO>,
|
||||
I: Input + HasTargetBytes,
|
||||
MO: MapObserver + Truncate, // TODO maybe enforce Entry = u8 for the cov map
|
||||
A: Observer<<S::Corpus as Corpus>::Input, S> + AsMut<MO>,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Prepend<MO>,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
S: HasCorpus,
|
||||
OT: ObserversTuple<I, S> + Prepend<MO>,
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
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> {
|
||||
/// 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,
|
||||
target_bytes_converter: TC2,
|
||||
) -> 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>
|
||||
for ForkserverExecutor<TC, OT, S, SP>
|
||||
impl<EM, I, OT, S, SP, TC, Z> Executor<EM, I, S, Z> for ForkserverExecutor<I, OT, S, SP, TC>
|
||||
where
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
S: HasCorpus + HasExecutions,
|
||||
TC: TargetBytesConverter<Input = <S::Corpus as Corpus>::Input>,
|
||||
S: HasExecutions,
|
||||
TC: TargetBytesConverter<I>,
|
||||
{
|
||||
#[inline]
|
||||
fn run_target(
|
||||
@ -1593,13 +1590,13 @@ where
|
||||
_fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
_mgr: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
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
|
||||
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
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus,
|
||||
OT: ObserversTuple<I, S>,
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
type Observers = OT;
|
||||
@ -1677,7 +1673,7 @@ mod tests {
|
||||
.coverage_map_size(MAP_SIZE)
|
||||
.debug_child(false)
|
||||
.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
|
||||
let result = match executor {
|
||||
|
@ -23,15 +23,15 @@ use windows::Win32::System::Threading::{CRITICAL_SECTION, PTP_TIMER};
|
||||
use crate::executors::hooks::timer::TimerStruct;
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
use crate::executors::hooks::unix::unix_signal_handler;
|
||||
#[cfg(any(unix, windows))]
|
||||
use crate::{corpus::Corpus, inputs::Input, observers::ObserversTuple, state::HasCurrentTestcase};
|
||||
use crate::{
|
||||
events::{EventFirer, EventRestarter},
|
||||
executors::{hooks::ExecutorHook, inprocess::HasInProcessHooks, Executor, HasObservers},
|
||||
feedbacks::Feedback,
|
||||
state::{HasCorpus, HasExecutions, HasSolutions},
|
||||
state::{HasExecutions, HasSolutions},
|
||||
Error, HasObjective,
|
||||
};
|
||||
#[cfg(any(unix, windows))]
|
||||
use crate::{inputs::Input, observers::ObserversTuple, state::HasCurrentTestcase};
|
||||
|
||||
/// The inmem executor's handlers.
|
||||
#[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>
|
||||
where
|
||||
S: HasCorpus,
|
||||
{
|
||||
impl<I, S> ExecutorHook<I, S> for InProcessHooks<I, S> {
|
||||
fn init(&mut self, _state: &mut S) {}
|
||||
/// Call before running a target.
|
||||
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>,
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
I: Input + Clone,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
{
|
||||
// # Safety
|
||||
// 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>,
|
||||
I: Input + Clone,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
{
|
||||
let ret;
|
||||
@ -330,7 +325,7 @@ impl<I, S> InProcessHooks<I, S> {
|
||||
E: Executor<EM, I, S, Z> + HasObservers + HasInProcessHooks<I, S>,
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasExecutions + HasSolutions + HasCorpus,
|
||||
S: HasExecutions + HasSolutions<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
{
|
||||
#[cfg_attr(miri, allow(unused_variables))]
|
||||
|
@ -3,10 +3,10 @@ use alloc::vec::Vec;
|
||||
use core::{
|
||||
ffi::c_void,
|
||||
marker::PhantomData,
|
||||
mem::transmute,
|
||||
ptr::null,
|
||||
sync::atomic::{compiler_fence, Ordering},
|
||||
};
|
||||
use std::intrinsics::transmute;
|
||||
|
||||
#[cfg(not(miri))]
|
||||
use libafl_bolts::os::unix_signals::setup_signal_handler;
|
||||
@ -21,7 +21,6 @@ use crate::{
|
||||
HasObservers,
|
||||
},
|
||||
observers::ObserversTuple,
|
||||
state::HasCorpus,
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -35,10 +34,7 @@ pub struct InChildProcessHooks<I, S> {
|
||||
phantom: PhantomData<(I, S)>,
|
||||
}
|
||||
|
||||
impl<I, S> ExecutorHook<I, S> for InChildProcessHooks<I, S>
|
||||
where
|
||||
S: HasCorpus,
|
||||
{
|
||||
impl<I, S> ExecutorHook<I, S> for InChildProcessHooks<I, S> {
|
||||
/// Init this hook
|
||||
fn init(&mut self, _state: &mut S) {}
|
||||
|
||||
@ -61,7 +57,6 @@ impl<I, S> InChildProcessHooks<I, S> {
|
||||
where
|
||||
E: HasObservers,
|
||||
E::Observers: ObserversTuple<I, S>,
|
||||
S: HasCorpus,
|
||||
{
|
||||
#[cfg_attr(miri, allow(unused_variables, unused_unsafe))]
|
||||
unsafe {
|
||||
|
@ -10,7 +10,7 @@ use num_traits::SaturatingAdd;
|
||||
use serde::Serialize;
|
||||
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
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@ -36,18 +36,18 @@ pub struct IntelPTHook<T> {
|
||||
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
|
||||
S: Serialize + HasCorpus,
|
||||
S: Serialize,
|
||||
T: SaturatingAdd + From<u8> + Debug,
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
pt.disable_tracing().unwrap();
|
||||
|
||||
|
@ -9,7 +9,6 @@ pub mod unix_signal_handler {
|
||||
use libc::siginfo_t;
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
events::{EventFirer, EventRestarter},
|
||||
executors::{
|
||||
common_signals,
|
||||
@ -21,7 +20,7 @@ pub mod unix_signal_handler {
|
||||
fuzzer::HasObjective,
|
||||
inputs::Input,
|
||||
observers::ObserversTuple,
|
||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions},
|
||||
state::{HasCurrentTestcase, HasExecutions, HasSolutions},
|
||||
};
|
||||
|
||||
pub(crate) type HandlerFuncPtr = unsafe fn(
|
||||
@ -83,8 +82,7 @@ pub mod unix_signal_handler {
|
||||
E::Observers: ObserversTuple<I, S>,
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
I: Input + Clone,
|
||||
{
|
||||
@ -133,10 +131,9 @@ pub mod unix_signal_handler {
|
||||
E::Observers: ObserversTuple<I, S>,
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
I: Input + Clone,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
{
|
||||
// this stuff is for batch timeout
|
||||
if !data.executor_ptr.is_null()
|
||||
@ -190,10 +187,9 @@ pub mod unix_signal_handler {
|
||||
E::Observers: ObserversTuple<I, S>,
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
I: Input + Clone,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
{
|
||||
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
|
||||
let _context = _context.map(|p| {
|
||||
|
@ -9,7 +9,6 @@ pub mod windows_asan_handler {
|
||||
};
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
events::{EventFirer, EventRestarter},
|
||||
executors::{
|
||||
hooks::inprocess::GLOBAL_STATE, inprocess::run_observers_and_save_state, Executor,
|
||||
@ -19,7 +18,7 @@ pub mod windows_asan_handler {
|
||||
fuzzer::HasObjective,
|
||||
inputs::Input,
|
||||
observers::ObserversTuple,
|
||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions},
|
||||
state::{HasCurrentTestcase, HasExecutions, HasSolutions},
|
||||
};
|
||||
|
||||
/// # Safety
|
||||
@ -31,8 +30,7 @@ pub mod windows_asan_handler {
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
I: Input + Clone,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
{
|
||||
let data = &raw mut GLOBAL_STATE;
|
||||
@ -127,7 +125,6 @@ pub mod windows_exception_handler {
|
||||
};
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
events::{EventFirer, EventRestarter},
|
||||
executors::{
|
||||
hooks::inprocess::{HasTimeout, InProcessExecutorHandlerData, GLOBAL_STATE},
|
||||
@ -138,7 +135,7 @@ pub mod windows_exception_handler {
|
||||
fuzzer::HasObjective,
|
||||
inputs::Input,
|
||||
observers::ObserversTuple,
|
||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions},
|
||||
state::{HasCurrentTestcase, HasExecutions, HasSolutions},
|
||||
};
|
||||
|
||||
pub(crate) type HandlerFuncPtr =
|
||||
@ -189,8 +186,7 @@ pub mod windows_exception_handler {
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
I: Input + Clone,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
{
|
||||
let old_hook = panic::take_hook();
|
||||
@ -252,9 +248,8 @@ pub mod windows_exception_handler {
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
I: Input + Clone,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
{
|
||||
let data: &mut InProcessExecutorHandlerData =
|
||||
&mut *(global_state as *mut InProcessExecutorHandlerData);
|
||||
@ -322,9 +317,8 @@ pub mod windows_exception_handler {
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
I: Input + Clone,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
{
|
||||
// Have we set a timer_before?
|
||||
if data.ptp_timer.is_some() {
|
||||
|
@ -15,7 +15,6 @@ use crate::executors::hooks::inprocess::HasTimeout;
|
||||
#[cfg(all(windows, feature = "std"))]
|
||||
use crate::executors::hooks::inprocess::HasTimeout;
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
events::{EventFirer, EventRestarter},
|
||||
executors::{
|
||||
hooks::{
|
||||
@ -29,7 +28,7 @@ use crate::{
|
||||
fuzzer::HasObjective,
|
||||
inputs::Input,
|
||||
observers::ObserversTuple,
|
||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions},
|
||||
state::{HasCurrentTestcase, HasExecutions, HasSolutions},
|
||||
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>
|
||||
where
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus,
|
||||
{
|
||||
/// 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
|
||||
HT: ExecutorHooksTuple<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)
|
||||
pub fn generic<E, EM, OF, Z>(
|
||||
@ -148,8 +146,7 @@ where
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
I: Input + Clone,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasCurrentTestcase + HasCorpus + HasSolutions,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
S: HasCurrentTestcase<I> + HasSolutions<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
{
|
||||
Self::with_timeout_generic::<E, EM, OF, Z>(
|
||||
@ -178,8 +175,7 @@ where
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
I: Input + Clone,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasCurrentTestcase + HasCorpus + HasSolutions,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
S: HasCurrentTestcase<I> + HasSolutions<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
{
|
||||
let mut me = Self::with_timeout_generic::<E, EM, OF, Z>(
|
||||
@ -210,9 +206,8 @@ where
|
||||
E::Observers: ObserversTuple<I, S>,
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasCurrentTestcase + HasCorpus + HasSolutions,
|
||||
S: HasCurrentTestcase<I> + HasSolutions<I>,
|
||||
Z: HasObjective<Objective = OF>,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
I: Input + Clone,
|
||||
{
|
||||
let default = InProcessHooks::new::<E, EM, OF, Z>(timeout)?;
|
||||
|
@ -77,7 +77,7 @@ where
|
||||
impl<EM, H, HB, HT, I, OT, S, Z> Executor<EM, I, S, Z>
|
||||
for GenericInProcessExecutor<H, HB, HT, I, OT, S>
|
||||
where
|
||||
S: HasCorpus + HasExecutions,
|
||||
S: HasExecutions,
|
||||
OT: ObserversTuple<I, S>,
|
||||
HT: ExecutorHooksTuple<I, S>,
|
||||
HB: BorrowMut<H>,
|
||||
@ -124,8 +124,7 @@ impl<'a, H, I, OT, S> InProcessExecutor<'a, H, I, OT, S>
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind + Sized,
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus + HasCurrentTestcase + HasExecutions + HasSolutions,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
S: HasCurrentTestcase<I> + HasExecutions + HasSolutions<I>,
|
||||
I: Input,
|
||||
{
|
||||
/// Create a new in mem executor with the default timeout (5 sec)
|
||||
@ -227,8 +226,7 @@ where
|
||||
HB: BorrowMut<H>,
|
||||
HT: ExecutorHooksTuple<I, S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus + HasCurrentTestcase + HasExecutions + HasSolutions,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
S: HasCurrentTestcase<I> + HasExecutions + HasSolutions<I>,
|
||||
I: Input,
|
||||
{
|
||||
/// 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>,
|
||||
EM: EventFirer<I, S> + EventRestarter<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>,
|
||||
I: Input + Clone,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
{
|
||||
let mut observers = executor.observers_mut();
|
||||
|
||||
@ -443,9 +440,8 @@ where
|
||||
E::Observers: ObserversTuple<I, S>,
|
||||
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
I: Input + Clone,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
Z: HasObjective<Objective = OF> + ExecutionProcessor<EM, I, E::Observers, S>,
|
||||
{
|
||||
let data = &raw mut GLOBAL_STATE;
|
||||
|
@ -11,7 +11,6 @@ use core::{
|
||||
use libafl_bolts::tuples::{tuple_list, RefIndexable};
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
events::{EventFirer, EventRestarter},
|
||||
executors::{
|
||||
hooks::{inprocess::InProcessHooks, ExecutorHooksTuple},
|
||||
@ -22,7 +21,7 @@ use crate::{
|
||||
fuzzer::HasObjective,
|
||||
inputs::Input,
|
||||
observers::ObserversTuple,
|
||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions},
|
||||
state::{HasCurrentTestcase, HasExecutions, HasSolutions},
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -74,7 +73,7 @@ where
|
||||
HB: BorrowMut<H>,
|
||||
HT: ExecutorHooksTuple<I, S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus + HasExecutions,
|
||||
S: HasExecutions,
|
||||
{
|
||||
fn run_target(
|
||||
&mut self,
|
||||
@ -106,7 +105,6 @@ where
|
||||
HB: BorrowMut<H>,
|
||||
HT: ExecutorHooksTuple<I, S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus,
|
||||
{
|
||||
type Observers = OT;
|
||||
#[inline]
|
||||
@ -124,9 +122,8 @@ impl<'a, H, I, OT, S, ES> StatefulInProcessExecutor<'a, H, I, OT, S, ES>
|
||||
where
|
||||
H: FnMut(&mut ES, &mut S, &I) -> ExitKind + Sized,
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
I: Clone + Input,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
{
|
||||
/// Create a new in mem executor with the default timeout (5 sec)
|
||||
pub fn new<EM, OF, Z>(
|
||||
@ -246,8 +243,7 @@ where
|
||||
HT: ExecutorHooksTuple<I, S>,
|
||||
I: Input + Clone,
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus + HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase,
|
||||
S::Solutions: Corpus<Input = I>,
|
||||
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
|
||||
{
|
||||
/// Create a new in mem executor with the default timeout (5 sec)
|
||||
pub fn generic<EM, OF, Z>(
|
||||
|
@ -28,7 +28,6 @@ use crate::{
|
||||
ExitKind, HasObservers,
|
||||
},
|
||||
observers::ObserversTuple,
|
||||
state::HasCorpus,
|
||||
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>
|
||||
where
|
||||
HT: ExecutorHooksTuple<I, S>,
|
||||
S: HasCorpus,
|
||||
SP: ShMemProvider,
|
||||
OT: ObserversTuple<I, S>,
|
||||
{
|
||||
@ -201,7 +199,6 @@ impl<HT, I, OT, S, SP, EM, Z> GenericInProcessForkExecutorInner<HT, I, OT, S, SP
|
||||
where
|
||||
HT: ExecutorHooksTuple<I, S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus,
|
||||
{
|
||||
#[inline]
|
||||
/// This function marks the boundary between the fuzzer and the target.
|
||||
|
@ -19,7 +19,7 @@ use crate::{
|
||||
inprocess_fork::inner::GenericInProcessForkExecutorInner, Executor, ExitKind, HasObservers,
|
||||
},
|
||||
observers::ObserversTuple,
|
||||
state::{HasCorpus, HasExecutions},
|
||||
state::HasExecutions,
|
||||
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>
|
||||
where
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus,
|
||||
{
|
||||
/// The constructor for `InProcessForkExecutor`
|
||||
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>
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind + Sized,
|
||||
S: HasCorpus + HasExecutions,
|
||||
S: HasExecutions,
|
||||
SP: ShMemProvider,
|
||||
HT: ExecutorHooksTuple<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
|
||||
HT: ExecutorHooksTuple<I, S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus,
|
||||
{
|
||||
/// Creates a new [`GenericInProcessForkExecutor`] with custom hooks
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
|
@ -20,7 +20,7 @@ use crate::{
|
||||
ExitKind, HasObservers,
|
||||
},
|
||||
observers::ObserversTuple,
|
||||
state::{HasCorpus, HasExecutions},
|
||||
state::HasExecutions,
|
||||
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>
|
||||
where
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus,
|
||||
{
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
/// The constructor for `InProcessForkExecutor`
|
||||
@ -99,7 +98,7 @@ impl<EM, H, HT, I, OT, S, SP, Z, ES> Executor<EM, I, S, Z>
|
||||
where
|
||||
H: FnMut(&mut ES, &I) -> ExitKind + Sized,
|
||||
HT: ExecutorHooksTuple<I, S>,
|
||||
S: HasCorpus + HasExecutions,
|
||||
S: HasExecutions,
|
||||
SP: ShMemProvider,
|
||||
OT: ObserversTuple<I, S>,
|
||||
{
|
||||
@ -138,7 +137,6 @@ impl<'a, H, HT, I, OT, S, SP, ES, EM, Z>
|
||||
where
|
||||
HT: ExecutorHooksTuple<I, S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus,
|
||||
{
|
||||
/// Creates a new [`StatefulGenericInProcessForkExecutor`] with custom hooks
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
|
@ -10,23 +10,21 @@ use libafl_bolts::tuples::RefIndexable;
|
||||
|
||||
use super::HasTimeout;
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
executors::{Executor, ExitKind, HasObservers},
|
||||
observers::ObserversTuple,
|
||||
state::HasCorpus,
|
||||
Error,
|
||||
};
|
||||
|
||||
/// 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
|
||||
executor: E,
|
||||
/// The shadow observers
|
||||
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
|
||||
E: 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
|
||||
E: HasObservers,
|
||||
S: HasCorpus,
|
||||
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
SOT: ObserversTuple<I, S>,
|
||||
{
|
||||
/// Create a new `ShadowExecutor`, wrapping the given `executor`.
|
||||
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>
|
||||
for ShadowExecutor<E, S, SOT>
|
||||
impl<E, EM, I, S, SOT, Z> Executor<EM, I, S, Z> for ShadowExecutor<E, I, S, SOT>
|
||||
where
|
||||
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
S: HasCorpus,
|
||||
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
E: Executor<EM, I, S, Z> + HasObservers,
|
||||
SOT: ObserversTuple<I, S>,
|
||||
{
|
||||
fn run_target(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
mgr: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
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
|
||||
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
|
||||
E: HasObservers,
|
||||
S: HasCorpus,
|
||||
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
SOT: ObserversTuple<I, S>,
|
||||
{
|
||||
type Observers = E::Observers;
|
||||
#[inline]
|
||||
|
@ -5,41 +5,37 @@ use core::{fmt::Debug, marker::PhantomData};
|
||||
use libafl_bolts::tuples::RefIndexable;
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
executors::{Executor, ExitKind, HasObservers},
|
||||
observers::ObserversTuple,
|
||||
state::HasCorpus,
|
||||
Error,
|
||||
};
|
||||
|
||||
/// A wrapper for any [`Executor`] to make it implement [`HasObservers`] using a given [`ObserversTuple`].
|
||||
#[derive(Debug)]
|
||||
pub struct WithObservers<E, OT, S> {
|
||||
pub struct WithObservers<E, I, OT, S> {
|
||||
executor: E,
|
||||
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
|
||||
S: HasCorpus,
|
||||
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z>,
|
||||
E: Executor<EM, I, S, Z>,
|
||||
{
|
||||
fn run_target(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
mgr: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
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
|
||||
S: HasCorpus,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
{
|
||||
type Observers = OT;
|
||||
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`].
|
||||
///
|
||||
/// If the executor already implements [`HasObservers`], then the original implementation will be overshadowed by
|
||||
|
@ -38,7 +38,7 @@ impl<S> StateInitializer<S> for CaptureTimeoutFeedback {}
|
||||
|
||||
impl<EM, I, OT, S> Feedback<EM, I, OT, S> for CaptureTimeoutFeedback
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
S: HasCorpus<I> + HasMetadata,
|
||||
I: Debug + Serialize + DeserializeOwned + Default + 'static + Clone,
|
||||
{
|
||||
#[inline]
|
||||
|
@ -21,13 +21,12 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
#[cfg(feature = "track_hit_feedbacks")]
|
||||
use crate::feedbacks::premature_last_result_err;
|
||||
use crate::{
|
||||
corpus::{Corpus, Testcase},
|
||||
corpus::Testcase,
|
||||
events::{Event, EventFirer},
|
||||
executors::ExitKind,
|
||||
feedbacks::{Feedback, HasObserverHandle, StateInitializer},
|
||||
monitors::{AggregatorOps, UserStats, UserStatsValue},
|
||||
observers::{CanTrack, MapObserver},
|
||||
state::HasCorpus,
|
||||
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>
|
||||
where
|
||||
C: CanTrack + AsRef<O>,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
EM: EventFirer<I, S>,
|
||||
N: IsNovel<O::Entry>,
|
||||
O: MapObserver + for<'it> AsIter<'it, Item = O::Entry>,
|
||||
O::Entry: 'static + Default + Debug + DeserializeOwned + Serialize,
|
||||
OT: MatchName,
|
||||
R: Reducer<O::Entry>,
|
||||
S: HasNamedMetadata + HasCorpus, // delete me
|
||||
S: HasNamedMetadata,
|
||||
{
|
||||
#[rustversion::nightly]
|
||||
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>
|
||||
where
|
||||
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>,
|
||||
OT: MatchName,
|
||||
S: HasNamedMetadata + HasCorpus,
|
||||
S: HasNamedMetadata,
|
||||
{
|
||||
fn is_interesting(
|
||||
&mut self,
|
||||
|
@ -67,8 +67,7 @@ impl<'a> NautilusFeedback<'a> {
|
||||
testcase: &mut Testcase<NautilusInput>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
S::Corpus: Corpus<Input = NautilusInput>,
|
||||
S: HasCorpus<NautilusInput> + HasMetadata,
|
||||
{
|
||||
state.corpus().load_input_into(testcase)?;
|
||||
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<'_>
|
||||
where
|
||||
S: HasMetadata + HasCorpus,
|
||||
S::Corpus: Corpus<Input = NautilusInput>,
|
||||
S: HasMetadata + HasCorpus<NautilusInput>,
|
||||
{
|
||||
fn is_interesting(
|
||||
&mut self,
|
||||
|
@ -129,9 +129,9 @@ pub trait ExecutionProcessor<EM, I, OT, S> {
|
||||
|
||||
/// Evaluates an input modifying the state of the fuzzer
|
||||
pub trait EvaluatorObservers<E, EM, I, S> {
|
||||
/// Runs the input and triggers observers and feedback,
|
||||
/// returns if is interesting an (option) the index of the new
|
||||
/// [`crate::corpus::Testcase`] in the [`crate::corpus::Corpus`]
|
||||
/// Runs the input and triggers observers and feedback.
|
||||
/// if it is interesting, returns an (option) the index of the new
|
||||
/// [`Testcase`] in the [`Corpus`]
|
||||
fn evaluate_input_with_observers(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
@ -145,7 +145,7 @@ pub trait EvaluatorObservers<E, EM, I, S> {
|
||||
/// Evaluate an input modifying the state of the fuzzer
|
||||
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
|
||||
/// 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(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
@ -155,7 +155,7 @@ pub trait Evaluator<E, EM, I, S> {
|
||||
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error>;
|
||||
|
||||
/// 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(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
@ -190,7 +190,7 @@ pub trait Evaluator<E, EM, I, S> {
|
||||
input: I,
|
||||
) -> 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.
|
||||
/// Disabled testcases are only used for splicing
|
||||
/// 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.
|
||||
pub trait Fuzzer<E, EM, S, ST> {
|
||||
pub trait Fuzzer<E, EM, I, S, ST> {
|
||||
/// Fuzz for a single iteration.
|
||||
/// Returns the index of the last fuzzed corpus item.
|
||||
/// (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)
|
||||
///
|
||||
/// 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,
|
||||
}
|
||||
|
||||
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
|
||||
S: HasCorpus,
|
||||
CS: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
CS: Scheduler<I, S>,
|
||||
{
|
||||
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>
|
||||
for StdFuzzer<CS, F, IF, OF>
|
||||
impl<CS, EM, F, I, IF, OF, OT, S> ExecutionProcessor<EM, I, OT, S> for StdFuzzer<CS, F, IF, OF>
|
||||
where
|
||||
CS: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S> + CanSerializeObserver<OT>,
|
||||
S: HasCorpus + MaybeHasClientPerfMonitor + HasCurrentTestcase + HasSolutions + HasLastFoundTime,
|
||||
F: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
|
||||
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
|
||||
CS: Scheduler<I, S>,
|
||||
EM: EventFirer<I, S> + CanSerializeObserver<OT>,
|
||||
F: Feedback<EM, I, OT, S>,
|
||||
I: Input,
|
||||
OF: Feedback<EM, I, OT, S>,
|
||||
OT: ObserversTuple<I, S> + Serialize,
|
||||
S: HasCorpus<I>
|
||||
+ MaybeHasClientPerfMonitor
|
||||
+ HasCurrentTestcase<I>
|
||||
+ HasSolutions<I>
|
||||
+ HasLastFoundTime,
|
||||
{
|
||||
fn check_results(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
observers: &OT,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<ExecuteInputResult, Error> {
|
||||
@ -357,107 +358,12 @@ where
|
||||
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
|
||||
fn process_execution(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
exec_res: &ExecuteInputResult,
|
||||
observers: &OT,
|
||||
) -> 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(())
|
||||
}
|
||||
|
||||
fn dispatch_event(
|
||||
&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, IF, OF, S> EvaluatorObservers<E, EM, <S::Corpus as Corpus>::Input, S>
|
||||
for StdFuzzer<CS, F, IF, OF>
|
||||
impl<CS, E, EM, F, I, IF, OF, S> EvaluatorObservers<E, EM, I, S> for StdFuzzer<CS, F, IF, OF>
|
||||
where
|
||||
CS: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
E: HasObservers + Executor<EM, <S::Corpus as Corpus>::Input, S, Self>,
|
||||
E::Observers: MatchName + ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S> + CanSerializeObserver<E::Observers>,
|
||||
F: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
|
||||
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
|
||||
S: HasCorpus
|
||||
+ HasSolutions
|
||||
CS: Scheduler<I, S>,
|
||||
E: HasObservers + Executor<EM, I, S, Self>,
|
||||
E::Observers: MatchName + ObserversTuple<I, S> + Serialize,
|
||||
EM: EventFirer<I, S> + CanSerializeObserver<E::Observers>,
|
||||
F: Feedback<EM, I, E::Observers, S>,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasCorpus<I>
|
||||
+ HasSolutions<I>
|
||||
+ MaybeHasClientPerfMonitor
|
||||
+ HasCurrentTestcase
|
||||
+ HasCurrentTestcase<I>
|
||||
+ HasExecutions
|
||||
+ HasLastFoundTime,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
|
||||
I: Input,
|
||||
{
|
||||
/// Process one input, adding to the respective corpora if needed and firing the right events
|
||||
#[inline]
|
||||
@ -531,7 +530,7 @@ where
|
||||
state: &mut S,
|
||||
executor: &mut E,
|
||||
manager: &mut EM,
|
||||
input: <S::Corpus as Corpus>::Input,
|
||||
input: I,
|
||||
send_events: bool,
|
||||
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
|
||||
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>
|
||||
for StdFuzzer<CS, F, IF, OF>
|
||||
impl<CS, E, EM, F, I, IF, OF, S> Evaluator<E, EM, I, S> for StdFuzzer<CS, F, IF, OF>
|
||||
where
|
||||
CS: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
E: HasObservers + Executor<EM, <S::Corpus as Corpus>::Input, S, Self>,
|
||||
E::Observers: MatchName + ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S> + CanSerializeObserver<E::Observers>,
|
||||
F: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
|
||||
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
|
||||
S: HasCorpus
|
||||
+ HasSolutions
|
||||
CS: Scheduler<I, S>,
|
||||
E: HasObservers + Executor<EM, I, S, Self>,
|
||||
E::Observers: MatchName + ObserversTuple<I, S> + Serialize,
|
||||
EM: EventFirer<I, S> + CanSerializeObserver<E::Observers>,
|
||||
F: Feedback<EM, I, E::Observers, S>,
|
||||
OF: Feedback<EM, I, E::Observers, S>,
|
||||
S: HasCorpus<I>
|
||||
+ HasSolutions<I>
|
||||
+ MaybeHasClientPerfMonitor
|
||||
+ HasCurrentTestcase
|
||||
+ HasCurrentTestcase<I>
|
||||
+ HasLastFoundTime
|
||||
+ HasExecutions,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
|
||||
IF: InputFilter<<S::Corpus as Corpus>::Input>,
|
||||
I: Input,
|
||||
IF: InputFilter<I>,
|
||||
{
|
||||
fn evaluate_filtered(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
executor: &mut E,
|
||||
manager: &mut EM,
|
||||
input: <S::Corpus as Corpus>::Input,
|
||||
input: I,
|
||||
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
|
||||
if self.input_filter.should_execute(&input) {
|
||||
self.evaluate_input(state, executor, manager, input)
|
||||
@ -623,31 +620,19 @@ where
|
||||
state: &mut S,
|
||||
executor: &mut E,
|
||||
manager: &mut EM,
|
||||
input: <S::Corpus as Corpus>::Input,
|
||||
input: I,
|
||||
send_events: bool,
|
||||
) -> Result<(ExecuteInputResult, Option<CorpusId>), Error> {
|
||||
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
|
||||
fn add_input(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
executor: &mut E,
|
||||
manager: &mut EM,
|
||||
input: <S::Corpus as Corpus>::Input,
|
||||
input: I,
|
||||
) -> Result<CorpusId, Error> {
|
||||
*state.last_found_time_mut() = current_time();
|
||||
|
||||
@ -738,17 +723,25 @@ where
|
||||
)?;
|
||||
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
|
||||
CS: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
CS: Scheduler<I, S>,
|
||||
EM: ProgressReporter<S> + EventProcessor<E, S, Self>,
|
||||
S: HasExecutions
|
||||
+ HasMetadata
|
||||
+ HasCorpus
|
||||
+ HasCorpus<I>
|
||||
+ HasLastReportTime
|
||||
+ HasTestcase
|
||||
+ HasTestcase<I>
|
||||
+ HasCurrentCorpusId
|
||||
+ HasCurrentStageId
|
||||
+ Stoppable
|
||||
@ -855,7 +848,7 @@ where
|
||||
|
||||
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)?;
|
||||
// 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`).
|
||||
@ -914,13 +907,12 @@ pub trait ExecutesInput<E, EM, I, S> {
|
||||
) -> Result<ExitKind, Error>;
|
||||
}
|
||||
|
||||
impl<CS, E, EM, F, IF, OF, S> ExecutesInput<E, EM, <S::Corpus as Corpus>::Input, S>
|
||||
for StdFuzzer<CS, F, IF, OF>
|
||||
impl<CS, E, EM, F, I, IF, OF, S> ExecutesInput<E, EM, I, S> for StdFuzzer<CS, F, IF, OF>
|
||||
where
|
||||
CS: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Self> + HasObservers,
|
||||
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasExecutions + HasCorpus + MaybeHasClientPerfMonitor,
|
||||
CS: Scheduler<I, S>,
|
||||
E: Executor<EM, I, S, Self> + HasObservers,
|
||||
E::Observers: ObserversTuple<I, S>,
|
||||
S: HasExecutions + HasCorpus<I> + MaybeHasClientPerfMonitor,
|
||||
{
|
||||
/// Runs the input and triggers observers and feedback
|
||||
fn execute_input(
|
||||
@ -928,7 +920,7 @@ where
|
||||
state: &mut S,
|
||||
executor: &mut E,
|
||||
event_mgr: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
start_timer!(state);
|
||||
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
|
||||
EM: ProgressReporter<S> + EventProcessor<E, S, Self>,
|
||||
ST: StagesTuple<E, EM, S, Self>,
|
||||
|
@ -9,7 +9,6 @@ use crate::{
|
||||
corpus::Testcase,
|
||||
inputs::BytesInput,
|
||||
stages::mutational::{MutatedTransform, MutatedTransformPost},
|
||||
state::HasCorpus,
|
||||
Error, HasMetadata,
|
||||
};
|
||||
|
||||
@ -105,10 +104,7 @@ impl GeneralizedInputMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> MutatedTransform<BytesInput, S> for GeneralizedInputMetadata
|
||||
where
|
||||
S: HasCorpus,
|
||||
{
|
||||
impl<S> MutatedTransform<BytesInput, S> for GeneralizedInputMetadata {
|
||||
type Post = Self;
|
||||
|
||||
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 {}
|
||||
|
@ -356,12 +356,9 @@ where
|
||||
}
|
||||
|
||||
/// A converter that converts from `input` to target bytes
|
||||
pub trait TargetBytesConverter {
|
||||
/// The input
|
||||
type Input;
|
||||
|
||||
pub trait TargetBytesConverter<I> {
|
||||
/// 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.
|
||||
@ -386,10 +383,11 @@ impl<I> Default for NopTargetBytesConverter<I> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: HasTargetBytes> TargetBytesConverter for NopTargetBytesConverter<I> {
|
||||
type Input = I;
|
||||
|
||||
fn to_target_bytes<'a>(&mut self, input: &'a Self::Input) -> OwnedSlice<'a, u8> {
|
||||
impl<I> TargetBytesConverter<I> for NopTargetBytesConverter<I>
|
||||
where
|
||||
I: HasTargetBytes,
|
||||
{
|
||||
fn to_target_bytes<'a>(&mut self, input: &'a I) -> OwnedSlice<'a, u8> {
|
||||
input.target_bytes()
|
||||
}
|
||||
}
|
||||
|
@ -154,10 +154,8 @@ impl<'a> NautilusTargetBytesConverter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl TargetBytesConverter for NautilusTargetBytesConverter<'_> {
|
||||
type Input = NautilusInput;
|
||||
|
||||
fn to_target_bytes<'a>(&mut self, input: &'a Self::Input) -> OwnedSlice<'a, u8> {
|
||||
impl TargetBytesConverter<NautilusInput> for NautilusTargetBytesConverter<'_> {
|
||||
fn to_target_bytes<'a>(&mut self, input: &'a NautilusInput) -> OwnedSlice<'a, u8> {
|
||||
let mut bytes = Vec::new();
|
||||
input.unparse(self.ctx, &mut bytes);
|
||||
OwnedSlice::from(bytes)
|
||||
|
@ -190,14 +190,14 @@ mod tests {
|
||||
|
||||
let state_serialized = postcard::to_allocvec(&state).unwrap();
|
||||
let state_deserialized: StdState<
|
||||
_,
|
||||
InMemoryCorpus<BytesInput>,
|
||||
_,
|
||||
StdRand,
|
||||
InMemoryCorpus<BytesInput>,
|
||||
> = postcard::from_bytes::<
|
||||
StdState<
|
||||
BytesInput,
|
||||
InMemoryCorpus<BytesInput>,
|
||||
BytesInput,
|
||||
RomuDuoJrRand,
|
||||
InMemoryCorpus<BytesInput>,
|
||||
>,
|
||||
|
@ -313,8 +313,7 @@ pub struct EncodedCrossoverInsertMutator;
|
||||
|
||||
impl<S> Mutator<EncodedInput, S> for EncodedCrossoverInsertMutator
|
||||
where
|
||||
S: HasRand + HasCorpus + HasMaxSize,
|
||||
S::Corpus: Corpus<Input = EncodedInput>,
|
||||
S: HasRand + HasCorpus<EncodedInput> + HasMaxSize,
|
||||
{
|
||||
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
|
||||
let size = input.codes().len();
|
||||
@ -397,8 +396,7 @@ pub struct EncodedCrossoverReplaceMutator;
|
||||
|
||||
impl<S> Mutator<EncodedInput, S> for EncodedCrossoverReplaceMutator
|
||||
where
|
||||
S: HasRand + HasCorpus,
|
||||
S::Corpus: Corpus<Input = EncodedInput>,
|
||||
S: HasRand + HasCorpus<EncodedInput>,
|
||||
{
|
||||
fn mutate(&mut self, state: &mut S, input: &mut EncodedInput) -> Result<MutationResult, Error> {
|
||||
let size = input.codes().len();
|
||||
|
@ -111,8 +111,7 @@ pub struct GramatronSpliceMutator;
|
||||
|
||||
impl<S> Mutator<GramatronInput, S> for GramatronSpliceMutator
|
||||
where
|
||||
S: HasRand + HasCorpus + HasMetadata,
|
||||
S::Corpus: Corpus<Input = GramatronInput>,
|
||||
S: HasRand + HasCorpus<GramatronInput> + HasMetadata,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
|
@ -4,6 +4,7 @@
|
||||
use alloc::{borrow::Cow, vec::Vec};
|
||||
use core::{
|
||||
cmp::{max, min},
|
||||
marker::PhantomData,
|
||||
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 CHOOSE_SUBINPUT_PROB: f64 = 0.5;
|
||||
|
||||
fn extend_with_random_generalized<S>(
|
||||
fn extend_with_random_generalized<I, S>(
|
||||
state: &mut S,
|
||||
items: &mut Vec<GeneralizedItem>,
|
||||
gap_indices: &mut Vec<usize>,
|
||||
) -> Result<MutationResult, Error>
|
||||
where
|
||||
S: HasMetadata + HasRand + HasCorpus,
|
||||
S: HasMetadata + HasRand + HasCorpus<I>,
|
||||
{
|
||||
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
|
||||
#[derive(Debug, Default)]
|
||||
pub struct GrimoireExtensionMutator {
|
||||
pub struct GrimoireExtensionMutator<I> {
|
||||
gap_indices: Vec<usize>,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireExtensionMutator
|
||||
impl<I, S> Mutator<GeneralizedInputMetadata, S> for GrimoireExtensionMutator<I>
|
||||
where
|
||||
S: HasMetadata + HasRand + HasCorpus,
|
||||
S: HasMetadata + HasRand + HasCorpus<I>,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
@ -137,33 +139,35 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl Named for GrimoireExtensionMutator {
|
||||
impl<I> Named for GrimoireExtensionMutator<I> {
|
||||
fn name(&self) -> &Cow<'static, str> {
|
||||
static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireExtensionMutator");
|
||||
&NAME
|
||||
}
|
||||
}
|
||||
|
||||
impl GrimoireExtensionMutator {
|
||||
impl<I> GrimoireExtensionMutator<I> {
|
||||
/// Creates a new [`GrimoireExtensionMutator`].
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
gap_indices: vec![],
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend the generalized input with another random one from the corpus
|
||||
#[derive(Debug, Default)]
|
||||
pub struct GrimoireRecursiveReplacementMutator {
|
||||
pub struct GrimoireRecursiveReplacementMutator<I> {
|
||||
scratch: Vec<GeneralizedItem>,
|
||||
gap_indices: Vec<usize>,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireRecursiveReplacementMutator
|
||||
impl<I, S> Mutator<GeneralizedInputMetadata, S> for GrimoireRecursiveReplacementMutator<I>
|
||||
where
|
||||
S: HasMetadata + HasRand + HasCorpus,
|
||||
S: HasMetadata + HasRand + HasCorpus<I>,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
@ -215,31 +219,34 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl Named for GrimoireRecursiveReplacementMutator {
|
||||
impl<I> Named for GrimoireRecursiveReplacementMutator<I> {
|
||||
fn name(&self) -> &Cow<'static, str> {
|
||||
static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireRecursiveReplacementMutator");
|
||||
&NAME
|
||||
}
|
||||
}
|
||||
|
||||
impl GrimoireRecursiveReplacementMutator {
|
||||
impl<I> GrimoireRecursiveReplacementMutator<I> {
|
||||
/// Creates a new [`GrimoireRecursiveReplacementMutator`].
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
scratch: vec![],
|
||||
gap_indices: vec![],
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace matching tokens with others from the tokens metadata
|
||||
#[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
|
||||
S: HasMetadata + HasRand + HasCorpus,
|
||||
S: HasMetadata + HasRand + HasCorpus<I>,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
@ -336,30 +343,33 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl Named for GrimoireStringReplacementMutator {
|
||||
impl<I> Named for GrimoireStringReplacementMutator<I> {
|
||||
fn name(&self) -> &Cow<'static, str> {
|
||||
static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireStringReplacementMutator");
|
||||
&NAME
|
||||
}
|
||||
}
|
||||
|
||||
impl GrimoireStringReplacementMutator {
|
||||
impl<I> GrimoireStringReplacementMutator<I> {
|
||||
/// Creates a new [`GrimoireExtensionMutator`].
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
Self {
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Randomly delete a part of the generalized input
|
||||
#[derive(Debug, Default)]
|
||||
pub struct GrimoireRandomDeleteMutator {
|
||||
pub struct GrimoireRandomDeleteMutator<I> {
|
||||
gap_indices: Vec<usize>,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<S> Mutator<GeneralizedInputMetadata, S> for GrimoireRandomDeleteMutator
|
||||
impl<I, S> Mutator<GeneralizedInputMetadata, S> for GrimoireRandomDeleteMutator<I>
|
||||
where
|
||||
S: HasMetadata + HasRand + HasCorpus,
|
||||
S: HasMetadata + HasRand + HasCorpus<I>,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
@ -400,19 +410,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl Named for GrimoireRandomDeleteMutator {
|
||||
impl<I> Named for GrimoireRandomDeleteMutator<I> {
|
||||
fn name(&self) -> &Cow<'static, str> {
|
||||
static NAME: Cow<'static, str> = Cow::Borrowed("GrimoireRandomDeleteMutator");
|
||||
&NAME
|
||||
}
|
||||
}
|
||||
|
||||
impl GrimoireRandomDeleteMutator {
|
||||
impl<I> GrimoireRandomDeleteMutator<I> {
|
||||
/// Creates a new [`GrimoireExtensionMutator`].
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
gap_indices: vec![],
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,9 +51,9 @@ pub type HavocMutationsNoCrossoverType = tuple_list_type!(
|
||||
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
|
||||
pub type MappedHavocCrossoverType<F, O> = tuple_list_type!(
|
||||
MappedCrossoverInsertMutator<F, O>,
|
||||
MappedCrossoverReplaceMutator<F, O>,
|
||||
pub type MappedHavocCrossoverType<F, I, O> = tuple_list_type!(
|
||||
MappedCrossoverInsertMutator<F, I, O>,
|
||||
MappedCrossoverReplaceMutator<F, I, O>,
|
||||
);
|
||||
|
||||
/// Tuple type of the mutations that compose the Havoc mutator
|
||||
@ -61,15 +61,15 @@ pub type HavocMutationsType =
|
||||
merge_tuple_list_type!(HavocMutationsNoCrossoverType, HavocCrossoverType);
|
||||
|
||||
/// Tuple type of the mutations that compose the Havoc mutator for mapped input types
|
||||
pub type MappedHavocMutationsType<F1, F2, O> = map_tuple_list_type!(
|
||||
merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,O>),
|
||||
pub type MappedHavocMutationsType<F1, F2, I, O> = map_tuple_list_type!(
|
||||
merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,I, O>),
|
||||
ToMappingMutator<F1>
|
||||
);
|
||||
|
||||
/// 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!(
|
||||
merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,O>),
|
||||
merge_tuple_list_type!(HavocMutationsNoCrossoverType, MappedHavocCrossoverType<F2,I, O>),
|
||||
ToOptionalMutator
|
||||
),
|
||||
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
|
||||
pub fn havoc_crossover_with_corpus_mapper<F, IO, O>(
|
||||
pub fn havoc_crossover_with_corpus_mapper<F, I, IO, O>(
|
||||
input_mapper: F,
|
||||
) -> MappedHavocCrossoverType<F, O>
|
||||
) -> MappedHavocCrossoverType<F, I, O>
|
||||
where
|
||||
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
|
||||
pub fn havoc_crossover_with_corpus_mapper_optional<F, O>(
|
||||
pub fn havoc_crossover_with_corpus_mapper_optional<F, I, O>(
|
||||
input_mapper: F,
|
||||
) -> MappedHavocCrossoverType<F, O>
|
||||
) -> MappedHavocCrossoverType<F, I, O>
|
||||
where
|
||||
F: Clone,
|
||||
{
|
||||
@ -155,7 +155,7 @@ pub fn havoc_mutations() -> HavocMutationsType {
|
||||
pub fn mapped_havoc_mutations<F1, F2, IO1, IO2, II, O>(
|
||||
current_input_mapper: F1,
|
||||
input_from_corpus_mapper: F2,
|
||||
) -> MappedHavocMutationsType<F1, F2, O>
|
||||
) -> MappedHavocMutationsType<F1, F2, IO1, O>
|
||||
where
|
||||
F1: Clone + FnMut(&mut IO1) -> &mut II,
|
||||
F2: Clone + Fn(&IO2) -> &O,
|
||||
@ -172,7 +172,7 @@ where
|
||||
pub fn optional_mapped_havoc_mutations<F1, F2, IO1, IO2, II, O>(
|
||||
current_input_mapper: F1,
|
||||
input_from_corpus_mapper: F2,
|
||||
) -> OptionMappedHavocMutationsType<F1, F2, O>
|
||||
) -> OptionMappedHavocMutationsType<F1, F2, IO1, O>
|
||||
where
|
||||
F1: Clone + FnMut(&mut IO1) -> &mut II,
|
||||
F2: Clone + Fn(&IO2) -> &O,
|
||||
|
@ -371,7 +371,7 @@ pub struct StdMOptMutator<MT> {
|
||||
impl<I, MT, S> Mutator<I, S> for StdMOptMutator<MT>
|
||||
where
|
||||
MT: MutatorsTuple<I, S>,
|
||||
S: HasRand + HasMetadata + HasCorpus + HasSolutions,
|
||||
S: HasRand + HasMetadata + HasCorpus<I> + HasSolutions<I>,
|
||||
{
|
||||
#[inline]
|
||||
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>
|
||||
where
|
||||
S: HasMetadata + HasRand + HasSolutions + HasCorpus,
|
||||
S: HasMetadata + HasRand + HasSolutions<I> + HasCorpus<I>,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
{
|
||||
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>
|
||||
where
|
||||
S: HasMetadata + HasRand + HasSolutions + HasCorpus,
|
||||
S: HasMetadata + HasRand + HasSolutions<I> + HasCorpus<I>,
|
||||
MT: MutatorsTuple<I, S>,
|
||||
{
|
||||
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>
|
||||
where
|
||||
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
|
||||
fn iterations(&self, state: &mut S, _: &I) -> u64 {
|
||||
|
@ -118,9 +118,8 @@ impl_default_multipart!(
|
||||
|
||||
impl<I, S> Mutator<MultipartInput<I>, S> for CrossoverInsertMutator
|
||||
where
|
||||
S: HasCorpus + HasMaxSize + HasRand,
|
||||
S: HasCorpus<MultipartInput<I>> + HasMaxSize + HasRand,
|
||||
I: Input + HasMutatorResizableBytes,
|
||||
S::Corpus: Corpus<Input = MultipartInput<I>>,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
@ -254,9 +253,8 @@ where
|
||||
|
||||
impl<I, S> Mutator<MultipartInput<I>, S> for CrossoverReplaceMutator
|
||||
where
|
||||
S: HasCorpus + HasMaxSize + HasRand,
|
||||
S: HasCorpus<MultipartInput<I>> + HasMaxSize + HasRand,
|
||||
I: Input + HasMutatorResizableBytes,
|
||||
S::Corpus: Corpus<Input = MultipartInput<I>>,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
|
@ -1125,9 +1125,8 @@ impl CrossoverInsertMutator {
|
||||
|
||||
impl<I, S> Mutator<I, S> for CrossoverInsertMutator
|
||||
where
|
||||
S: HasCorpus + HasRand + HasMaxSize,
|
||||
<S::Corpus as Corpus>::Input: HasMutatorBytes,
|
||||
I: HasMutatorResizableBytes,
|
||||
S: HasCorpus<I> + HasRand + HasMaxSize,
|
||||
{
|
||||
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
|
||||
let size = input.bytes().len();
|
||||
@ -1217,9 +1216,8 @@ impl CrossoverReplaceMutator {
|
||||
|
||||
impl<I, S> Mutator<I, S> for CrossoverReplaceMutator
|
||||
where
|
||||
S: HasCorpus + HasRand,
|
||||
<S::Corpus as Corpus>::Input: HasMutatorBytes,
|
||||
I: HasMutatorBytes,
|
||||
S: HasCorpus<I> + HasRand,
|
||||
{
|
||||
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
|
||||
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
|
||||
#[derive(Debug)]
|
||||
pub struct MappedCrossoverInsertMutator<F, O> {
|
||||
pub struct MappedCrossoverInsertMutator<F, I, O> {
|
||||
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`]
|
||||
pub fn new(input_mapper: F) -> 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
|
||||
S: HasCorpus + HasMaxSize + HasRand,
|
||||
I: HasMutatorResizableBytes,
|
||||
F: Fn(&I1) -> &O,
|
||||
I2: HasMutatorResizableBytes,
|
||||
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 max_size = state.max_size();
|
||||
// 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> {
|
||||
static NAME: Cow<'static, str> = Cow::Borrowed("MappedCrossoverInsertMutator");
|
||||
&NAME
|
||||
@ -1386,12 +1384,12 @@ impl<F, O> Named for MappedCrossoverInsertMutator<F, O> {
|
||||
|
||||
/// Crossover replace mutation for inputs mapped to a bytes vector
|
||||
#[derive(Debug)]
|
||||
pub struct MappedCrossoverReplaceMutator<F, O> {
|
||||
pub struct MappedCrossoverReplaceMutator<F, I, O> {
|
||||
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`]
|
||||
pub fn new(input_mapper: F) -> 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
|
||||
S: HasCorpus + HasMaxSize + HasRand,
|
||||
I: HasMutatorBytes,
|
||||
F: Fn(&I1) -> &O,
|
||||
I2: HasMutatorBytes,
|
||||
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();
|
||||
if size == 0 {
|
||||
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> {
|
||||
static NAME: Cow<'static, str> = Cow::Borrowed("MappedCrossoverReplaceMutator");
|
||||
&NAME
|
||||
@ -1492,8 +1490,7 @@ pub struct SpliceMutator;
|
||||
|
||||
impl<I, S> Mutator<I, S> for SpliceMutator
|
||||
where
|
||||
S: HasCorpus + HasRand,
|
||||
<S::Corpus as Corpus>::Input: HasMutatorBytes,
|
||||
S: HasCorpus<I> + HasRand,
|
||||
I: HasMutatorResizableBytes,
|
||||
{
|
||||
#[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 mut corpus = InMemoryCorpus::new();
|
||||
|
||||
|
@ -162,7 +162,7 @@ impl Debug for NautilusSpliceMutator<'_> {
|
||||
|
||||
impl<S> Mutator<NautilusInput, S> for NautilusSpliceMutator<'_>
|
||||
where
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
S: HasCorpus<NautilusInput> + HasMetadata + HasRand,
|
||||
{
|
||||
fn mutate(
|
||||
&mut self,
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Mutators for integer-style inputs
|
||||
|
||||
use alloc::borrow::Cow;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use libafl_bolts::{
|
||||
rands::Rand,
|
||||
@ -31,7 +32,7 @@ pub type IntMutatorsType = tuple_list_type!(
|
||||
pub type IntMutatorsCrossoverType = tuple_list_type!(CrossoverMutator);
|
||||
|
||||
/// 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
|
||||
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.
|
||||
#[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))
|
||||
}
|
||||
|
||||
@ -77,14 +80,14 @@ pub fn int_mutators() -> IntMutatorsType {
|
||||
}
|
||||
|
||||
/// 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<NegateMutator,F1>,
|
||||
MappingMutator<IncMutator,F1>,
|
||||
MappingMutator<DecMutator,F1>,
|
||||
MappingMutator<TwosComplementMutator,F1>,
|
||||
MappingMutator<RandMutator,F1>,
|
||||
MappingMutator<MappedCrossoverMutator<F2>,F1>
|
||||
MappingMutator<MappedCrossoverMutator<F2, I>,F1>
|
||||
);
|
||||
|
||||
/// 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>(
|
||||
current_input_mapper: F1,
|
||||
input_from_corpus_mapper: F2,
|
||||
) -> MappedIntMutatorsType<F1, F2>
|
||||
) -> MappedIntMutatorsType<F1, F2, IO>
|
||||
where
|
||||
F1: Clone + FnMut(&mut IO) -> &mut II,
|
||||
{
|
||||
@ -365,8 +368,7 @@ pub struct CrossoverMutator;
|
||||
|
||||
impl<I, S> Mutator<I, S> for CrossoverMutator
|
||||
where
|
||||
S: HasRand + HasCorpus,
|
||||
S::Corpus: Corpus<Input = I>,
|
||||
S: HasRand + HasCorpus<I>,
|
||||
I: Copy,
|
||||
{
|
||||
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
|
||||
#[derive(Debug)]
|
||||
pub struct MappedCrossoverMutator<F> {
|
||||
pub struct MappedCrossoverMutator<F, I> {
|
||||
input_mapper: F,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<F> MappedCrossoverMutator<F> {
|
||||
impl<F, I> MappedCrossoverMutator<F, I> {
|
||||
/// Create a new [`MappedCrossoverMutator`]
|
||||
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
|
||||
S: HasRand + HasCorpus,
|
||||
for<'b> F: Fn(&'b <S::Corpus as Corpus>::Input) -> &'b I,
|
||||
I: Clone,
|
||||
S: HasRand + HasCorpus<I>,
|
||||
for<'b> F: Fn(&'b I) -> &'b O,
|
||||
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());
|
||||
|
||||
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> {
|
||||
&Cow::Borrowed("MappedCrossoverMutator")
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ impl<SM> Named for LoggerScheduledMutator<SM> {
|
||||
|
||||
impl<I, S, SM> Mutator<I, S> for LoggerScheduledMutator<SM>
|
||||
where
|
||||
S: HasRand + HasCorpus,
|
||||
S: HasRand + HasCorpus<I>,
|
||||
SM: ScheduledMutator<I, S>,
|
||||
SM::Mutations: MutatorsTuple<I, S> + NamedTuple,
|
||||
{
|
||||
@ -258,7 +258,7 @@ where
|
||||
|
||||
impl<I, S, SM> ScheduledMutator<I, S> for LoggerScheduledMutator<SM>
|
||||
where
|
||||
S: HasRand + HasCorpus,
|
||||
S: HasRand + HasCorpus<I>,
|
||||
SM: ScheduledMutator<I, S>,
|
||||
SM::Mutations: MutatorsTuple<I, S> + NamedTuple,
|
||||
{
|
||||
|
@ -31,7 +31,7 @@ use crate::{
|
||||
},
|
||||
observers::cmp::{AFLppCmpValuesMetadata, CmpValues, CmpValuesMetadata},
|
||||
stages::TaintMetadata,
|
||||
state::{HasCorpus, HasMaxSize, HasRand},
|
||||
state::{HasMaxSize, HasRand},
|
||||
Error, HasMetadata,
|
||||
};
|
||||
|
||||
@ -1305,7 +1305,7 @@ impl AFLppRedQueen {
|
||||
|
||||
impl<I, S> MultiMutator<I, S> for AFLppRedQueen
|
||||
where
|
||||
S: HasMetadata + HasRand + HasMaxSize + HasCorpus + HasCurrentCorpusId,
|
||||
S: HasMetadata + HasRand + HasMaxSize + HasCurrentCorpusId,
|
||||
I: HasMutatorResizableBytes + From<Vec<u8>>,
|
||||
{
|
||||
#[expect(clippy::needless_range_loop, clippy::too_many_lines)]
|
||||
|
@ -10,7 +10,7 @@ use core::{
|
||||
use libafl_bolts::{rands::Rand, Error, HasLen, Named};
|
||||
|
||||
use crate::{
|
||||
corpus::{Corpus, CorpusId, HasTestcase, Testcase},
|
||||
corpus::{CorpusId, HasTestcase, Testcase},
|
||||
inputs::{BytesInput, HasMutatorBytes, HasMutatorResizableBytes},
|
||||
mutators::{rand_range, MutationResult, Mutator, Tokens},
|
||||
nonzero,
|
||||
@ -32,8 +32,7 @@ pub type UnicodeInput = (BytesInput, UnicodeIdentificationMetadata);
|
||||
|
||||
impl<S> MutatedTransform<BytesInput, S> for UnicodeInput
|
||||
where
|
||||
S: HasCorpus + HasTestcase,
|
||||
S::Corpus: Corpus<Input = BytesInput>,
|
||||
S: HasCorpus<BytesInput> + HasTestcase<BytesInput>,
|
||||
{
|
||||
type Post = UnicodeIdentificationMetadata;
|
||||
|
||||
@ -50,7 +49,7 @@ where
|
||||
|
||||
impl<S> MutatedTransformPost<S> for UnicodeIdentificationMetadata
|
||||
where
|
||||
S: HasTestcase,
|
||||
S: HasTestcase<BytesInput>,
|
||||
{
|
||||
fn post_exec(self, state: &mut S, corpus_id: Option<CorpusId>) -> Result<(), Error> {
|
||||
if let Some(corpus_id) = corpus_id {
|
||||
|
@ -104,17 +104,17 @@ impl TopAccountingMetadata {
|
||||
|
||||
/// A minimizer scheduler using coverage accounting
|
||||
#[derive(Debug)]
|
||||
pub struct CoverageAccountingScheduler<'a, CS, O> {
|
||||
pub struct CoverageAccountingScheduler<'a, CS, I, O> {
|
||||
accounting_map: &'a [u32],
|
||||
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
|
||||
CS: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
<S::Corpus as Corpus>::Input: HasLen,
|
||||
CS: Scheduler<I, S>,
|
||||
S: HasCorpus<I> + HasMetadata + HasRand,
|
||||
I: HasLen,
|
||||
O: CanTrack,
|
||||
{
|
||||
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
@ -122,12 +122,7 @@ where
|
||||
self.inner.on_add(state, id)
|
||||
}
|
||||
|
||||
fn on_evaluation<OT>(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
observers: &OT,
|
||||
) -> Result<(), Error>
|
||||
fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
|
||||
where
|
||||
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
|
||||
O: CanTrack,
|
||||
{
|
||||
@ -181,7 +176,7 @@ where
|
||||
#[expect(clippy::cast_possible_wrap)]
|
||||
pub fn update_accounting_score<S>(&self, state: &mut S, id: CorpusId) -> Result<(), Error>
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
S: HasCorpus<I> + HasMetadata,
|
||||
{
|
||||
let mut indexes = vec![];
|
||||
let mut new_favoreds = vec![];
|
||||
@ -268,7 +263,7 @@ where
|
||||
/// Cull the `Corpus`
|
||||
pub fn accounting_cull<S>(&self, state: &S) -> Result<(), Error>
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
S: HasCorpus<I> + HasMetadata,
|
||||
{
|
||||
let Some(top_rated) = state.metadata_map().get::<TopAccountingMetadata>() else {
|
||||
return Ok(());
|
||||
|
@ -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`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MinimizerScheduler<CS, F, M, S> {
|
||||
pub struct MinimizerScheduler<CS, F, I, M, S> {
|
||||
base: CS,
|
||||
skip_non_favored_prob: f64,
|
||||
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>
|
||||
for MinimizerScheduler<CS, F, M, O>
|
||||
impl<CS, F, M, I, O, S> RemovableScheduler<I, S> for MinimizerScheduler<CS, F, I, M, O>
|
||||
where
|
||||
CS: RemovableScheduler<<S::Corpus as Corpus>::Input, S>
|
||||
+ Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
F: TestcaseScore<S>,
|
||||
CS: RemovableScheduler<I, S> + Scheduler<I, S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
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`]
|
||||
fn on_replace(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
testcase: &Testcase<<S::Corpus as Corpus>::Input>,
|
||||
testcase: &Testcase<I>,
|
||||
) -> Result<(), Error> {
|
||||
self.base.on_replace(state, id, testcase)?;
|
||||
self.update_score(state, id)
|
||||
@ -104,7 +102,7 @@ where
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
testcase: &Option<Testcase<<S::Corpus as Corpus>::Input>>,
|
||||
testcase: &Option<Testcase<I>>,
|
||||
) -> Result<(), Error> {
|
||||
self.base.on_remove(state, id, testcase)?;
|
||||
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
|
||||
CS: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
F: TestcaseScore<S>,
|
||||
CS: Scheduler<I, S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
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
|
||||
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
@ -202,12 +200,7 @@ where
|
||||
}
|
||||
|
||||
/// An input has been evaluated
|
||||
fn on_evaluation<OT>(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
observers: &OT,
|
||||
) -> Result<(), Error>
|
||||
fn on_evaluation<OT>(&mut self, state: &mut S, input: &I, observers: &OT) -> Result<(), Error>
|
||||
where
|
||||
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
|
||||
M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt,
|
||||
{
|
||||
@ -251,8 +244,8 @@ where
|
||||
#[expect(clippy::cast_possible_wrap)]
|
||||
pub fn update_score<S>(&self, state: &mut S, id: CorpusId) -> Result<(), Error>
|
||||
where
|
||||
F: TestcaseScore<S>,
|
||||
S: HasCorpus + HasMetadata,
|
||||
F: TestcaseScore<I, S>,
|
||||
S: HasCorpus<I> + HasMetadata,
|
||||
{
|
||||
// Create a new top rated meta if not existing
|
||||
if state.metadata_map().get::<TopRatedsMetadata>().is_none() {
|
||||
@ -328,7 +321,7 @@ where
|
||||
/// Cull the [`Corpus`] using the [`MinimizerScheduler`]
|
||||
pub fn cull<S>(&self, state: &S) -> Result<(), Error>
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
S: HasCorpus<I> + HasMetadata,
|
||||
{
|
||||
let Some(top_rated) = state.metadata_map().get::<TopRatedsMetadata>() else {
|
||||
return Ok(());
|
||||
@ -356,7 +349,7 @@ where
|
||||
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
|
||||
CS: HasQueueCycles,
|
||||
{
|
||||
@ -364,7 +357,7 @@ where
|
||||
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
|
||||
O: CanTrack,
|
||||
{
|
||||
@ -425,10 +418,10 @@ where
|
||||
}
|
||||
|
||||
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`.
|
||||
pub type LenTimeMinimizerScheduler<CS, M, O> =
|
||||
MinimizerScheduler<CS, LenTimeMulTestcaseScore, M, O>;
|
||||
pub type LenTimeMinimizerScheduler<CS, I, M, O> =
|
||||
MinimizerScheduler<CS, LenTimeMulTestcaseScore, I, M, O>;
|
||||
|
||||
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`
|
||||
/// that exercise all the entries registered in the [`MapIndexesMetadata`].
|
||||
pub type IndexesLenTimeMinimizerScheduler<CS, O> =
|
||||
MinimizerScheduler<CS, LenTimeMulTestcaseScore, MapIndexesMetadata, O>;
|
||||
pub type IndexesLenTimeMinimizerScheduler<CS, I, O> =
|
||||
MinimizerScheduler<CS, LenTimeMulTestcaseScore, I, MapIndexesMetadata, O>;
|
||||
|
@ -66,14 +66,14 @@ pub trait RemovableScheduler<I, S> {
|
||||
}
|
||||
|
||||
/// 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,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
CS: AflScheduler,
|
||||
S: HasTestcase + HasCorpus,
|
||||
S: HasTestcase<I> + HasCorpus<I>,
|
||||
{
|
||||
let current_id = *state.corpus().current();
|
||||
|
||||
@ -131,9 +131,9 @@ where
|
||||
}
|
||||
|
||||
/// 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
|
||||
S: HasCorpus + HasTestcase,
|
||||
S: HasCorpus<I> + HasTestcase<I>,
|
||||
{
|
||||
let current_id = *state.corpus().current();
|
||||
|
||||
@ -215,7 +215,7 @@ pub struct RandScheduler<S> {
|
||||
|
||||
impl<I, S> Scheduler<I, S> for RandScheduler<S>
|
||||
where
|
||||
S: HasCorpus + HasRand,
|
||||
S: HasCorpus<I> + HasRand,
|
||||
{
|
||||
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
// Set parent id
|
||||
|
@ -326,7 +326,7 @@ impl<C, O> HasQueueCycles for PowerQueueScheduler<C, O> {
|
||||
|
||||
impl<C, I, O, S> Scheduler<I, S> for PowerQueueScheduler<C, O>
|
||||
where
|
||||
S: HasCorpus + HasMetadata + HasTestcase,
|
||||
S: HasCorpus<I> + HasMetadata + HasTestcase<I>,
|
||||
O: Hash,
|
||||
C: AsRef<O>,
|
||||
{
|
||||
|
@ -63,10 +63,10 @@ impl<F> ProbabilitySamplingScheduler<F> {
|
||||
}
|
||||
|
||||
/// 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
|
||||
F: TestcaseScore<S>,
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
F: TestcaseScore<I, S>,
|
||||
S: HasCorpus<I> + HasMetadata + HasRand,
|
||||
{
|
||||
let prob = F::compute(state, &mut *state.corpus().get(id)?.borrow_mut())?;
|
||||
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
|
||||
F: TestcaseScore<S>,
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
F: TestcaseScore<I, S>,
|
||||
S: HasCorpus<I> + HasMetadata + HasRand,
|
||||
{
|
||||
fn on_remove(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
_testcase: &Option<Testcase<<S::Corpus as Corpus>::Input>>,
|
||||
_testcase: &Option<Testcase<I>>,
|
||||
) -> Result<(), Error> {
|
||||
let meta = state
|
||||
.metadata_map_mut()
|
||||
@ -108,7 +108,7 @@ where
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
id: CorpusId,
|
||||
_prev: &Testcase<<S::Corpus as Corpus>::Input>,
|
||||
_prev: &Testcase<I>,
|
||||
) -> Result<(), Error> {
|
||||
let meta = state
|
||||
.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
|
||||
F: TestcaseScore<S>,
|
||||
S: HasCorpus + HasMetadata + HasRand,
|
||||
F: TestcaseScore<I, S>,
|
||||
S: HasCorpus<I> + HasMetadata + HasRand,
|
||||
{
|
||||
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
let current_id = *state.corpus().current();
|
||||
@ -202,14 +202,11 @@ mod tests {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UniformDistribution {}
|
||||
|
||||
impl<S> TestcaseScore<S> for UniformDistribution
|
||||
impl<I, S> TestcaseScore<I, S> for UniformDistribution
|
||||
where
|
||||
S: HasCorpus,
|
||||
S: HasCorpus<I>,
|
||||
{
|
||||
fn compute(
|
||||
_state: &S,
|
||||
_: &mut Testcase<<S::Corpus as Corpus>::Input>,
|
||||
) -> Result<f64, Error> {
|
||||
fn compute(_state: &S, _: &mut Testcase<I>) -> Result<f64, Error> {
|
||||
Ok(FACTOR)
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ impl<I, S> RemovableScheduler<I, S> for QueueScheduler {}
|
||||
|
||||
impl<I, S> Scheduler<I, S> for QueueScheduler
|
||||
where
|
||||
S: HasCorpus,
|
||||
S: HasCorpus<I>,
|
||||
{
|
||||
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
// Set parent id
|
||||
|
@ -15,13 +15,9 @@ use crate::{
|
||||
};
|
||||
|
||||
/// Compute the favor factor of a [`Testcase`]. Higher is better.
|
||||
pub trait TestcaseScore<S>
|
||||
where
|
||||
S: HasCorpus,
|
||||
{
|
||||
pub trait TestcaseScore<I, S> {
|
||||
/// Computes the favor factor of a [`Testcase`]. Higher is better.
|
||||
fn compute(state: &S, entry: &mut Testcase<<S::Corpus as Corpus>::Input>)
|
||||
-> Result<f64, Error>;
|
||||
fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error>;
|
||||
}
|
||||
|
||||
/// Multiply the testcase size with the execution time.
|
||||
@ -29,16 +25,13 @@ where
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LenTimeMulTestcaseScore {}
|
||||
|
||||
impl<S> TestcaseScore<S> for LenTimeMulTestcaseScore
|
||||
impl<I, S> TestcaseScore<I, S> for LenTimeMulTestcaseScore
|
||||
where
|
||||
S: HasCorpus,
|
||||
<S::Corpus as Corpus>::Input: HasLen,
|
||||
S: HasCorpus<I>,
|
||||
I: HasLen,
|
||||
{
|
||||
#[expect(clippy::cast_precision_loss)]
|
||||
fn compute(
|
||||
state: &S,
|
||||
entry: &mut Testcase<<S::Corpus as Corpus>::Input>,
|
||||
) -> Result<f64, Error> {
|
||||
fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error> {
|
||||
// TODO maybe enforce entry.exec_time().is_some()
|
||||
Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as f64
|
||||
* entry.load_len(state.corpus())? as f64)
|
||||
@ -55,16 +48,13 @@ const HAVOC_MAX_MULT: f64 = 64.0;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CorpusPowerTestcaseScore {}
|
||||
|
||||
impl<S> TestcaseScore<S> for CorpusPowerTestcaseScore
|
||||
impl<I, S> TestcaseScore<I, S> for CorpusPowerTestcaseScore
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
S: HasCorpus<I> + HasMetadata,
|
||||
{
|
||||
/// Compute the `power` we assign to each corpus entry
|
||||
#[expect(clippy::cast_precision_loss, clippy::too_many_lines)]
|
||||
fn compute(
|
||||
state: &S,
|
||||
entry: &mut Testcase<<S::Corpus as Corpus>::Input>,
|
||||
) -> Result<f64, Error> {
|
||||
fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error> {
|
||||
let psmeta = state.metadata::<SchedulerMetadata>()?;
|
||||
|
||||
let fuzz_mu = if let Some(strat) = psmeta.strat() {
|
||||
@ -272,16 +262,13 @@ where
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CorpusWeightTestcaseScore {}
|
||||
|
||||
impl<S> TestcaseScore<S> for CorpusWeightTestcaseScore
|
||||
impl<I, S> TestcaseScore<I, S> for CorpusWeightTestcaseScore
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
S: HasCorpus<I> + HasMetadata,
|
||||
{
|
||||
/// Compute the `weight` used in weighted corpus entry selection algo
|
||||
#[expect(clippy::cast_precision_loss)]
|
||||
fn compute(
|
||||
state: &S,
|
||||
entry: &mut Testcase<<S::Corpus as Corpus>::Input>,
|
||||
) -> Result<f64, Error> {
|
||||
fn compute(state: &S, entry: &mut Testcase<I>) -> Result<f64, Error> {
|
||||
let mut weight = 1.0;
|
||||
let psmeta = state.metadata::<SchedulerMetadata>()?;
|
||||
|
||||
|
@ -90,9 +90,9 @@ impl TuneableScheduler {
|
||||
}
|
||||
|
||||
/// Gets the current corpus entry id
|
||||
pub fn get_current<S>(state: &S) -> CorpusId
|
||||
pub fn get_current<I, S>(state: &S) -> CorpusId
|
||||
where
|
||||
S: HasCorpus,
|
||||
S: HasCorpus<I>,
|
||||
{
|
||||
state
|
||||
.corpus()
|
||||
@ -105,7 +105,7 @@ impl<I, S> RemovableScheduler<I, S> for TuneableScheduler {}
|
||||
|
||||
impl<I, S> Scheduler<I, S> for TuneableScheduler
|
||||
where
|
||||
S: HasCorpus + HasMetadata,
|
||||
S: HasCorpus<I> + HasMetadata,
|
||||
{
|
||||
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
// Set parent id
|
||||
|
@ -155,10 +155,10 @@ where
|
||||
|
||||
/// Create a new alias table when the fuzzer finds a new corpus entry
|
||||
#[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
|
||||
F: TestcaseScore<S>,
|
||||
S: HasCorpus + HasMetadata,
|
||||
F: TestcaseScore<I, S>,
|
||||
S: HasCorpus<I> + HasMetadata,
|
||||
{
|
||||
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
|
||||
C: AsRef<O> + Named,
|
||||
F: TestcaseScore<S>,
|
||||
F: TestcaseScore<I, S>,
|
||||
O: Hash,
|
||||
S: HasCorpus + HasMetadata + HasRand + HasTestcase,
|
||||
S: HasCorpus<I> + HasMetadata + HasRand + HasTestcase<I>,
|
||||
{
|
||||
/// Called when a [`Testcase`] is added to the corpus
|
||||
fn on_add(&mut self, state: &mut S, id: CorpusId) -> Result<(), Error> {
|
||||
@ -317,12 +317,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_evaluation<OT>(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
_input: &<S::Corpus as Corpus>::Input,
|
||||
observers: &OT,
|
||||
) -> Result<(), Error>
|
||||
fn on_evaluation<OT>(&mut self, state: &mut S, _input: &I, observers: &OT) -> Result<(), Error>
|
||||
where
|
||||
OT: MatchName,
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ libafl_bolts::impl_serdeany!(FuzzTime);
|
||||
/// The [`AflStatsStage`] is a Stage that calculates and writes
|
||||
/// AFL++'s `fuzzer_stats` and `plot_data` information.
|
||||
#[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>,
|
||||
stats_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,
|
||||
/// The core we are bound to
|
||||
core_id: CoreId,
|
||||
phantom_data: PhantomData<(O, E, EM, S, Z)>,
|
||||
phantom_data: PhantomData<(E, EM, I, O, S, Z)>,
|
||||
}
|
||||
|
||||
/// AFL++'s `fuzzer_stats`
|
||||
@ -236,13 +236,14 @@ pub struct AFLPlotData<'a> {
|
||||
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
|
||||
C: AsRef<O> + Named,
|
||||
E: HasObservers,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
Z: HasScheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
EM: EventFirer<I, S>,
|
||||
Z: HasScheduler<I, S>,
|
||||
S: HasImported
|
||||
+ HasCorpus
|
||||
+ HasCorpus<I>
|
||||
+ HasMetadata
|
||||
+ HasStartTime
|
||||
+ 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
|
||||
E: HasObservers,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasImported + HasCorpus + HasMetadata + HasExecutions,
|
||||
EM: EventFirer<I, S>,
|
||||
S: HasImported + HasMetadata + HasExecutions,
|
||||
C: AsRef<O> + Named,
|
||||
O: MapObserver,
|
||||
{
|
||||
/// Builder for `AflStatsStage`
|
||||
#[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()
|
||||
}
|
||||
|
||||
@ -479,13 +480,13 @@ where
|
||||
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>() {
|
||||
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 exec_time > &self.slowest_exec {
|
||||
self.slowest_exec = *exec_time;
|
||||
@ -497,7 +498,7 @@ where
|
||||
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 metadata.depth() > self.max_depth {
|
||||
self.max_depth = metadata.depth();
|
||||
@ -510,11 +511,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "track_hit_feedbacks")]
|
||||
fn maybe_update_last_crash(
|
||||
&mut self,
|
||||
testcase: &Testcase<<S::Corpus as Corpus>::Input>,
|
||||
state: &S,
|
||||
) {
|
||||
fn maybe_update_last_crash(&mut self, testcase: &Testcase<I>, state: &S) {
|
||||
#[cfg(feature = "track_hit_feedbacks")]
|
||||
if testcase
|
||||
.hit_objectives()
|
||||
@ -526,11 +523,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "track_hit_feedbacks")]
|
||||
fn maybe_update_last_hang(
|
||||
&mut self,
|
||||
testcase: &Testcase<<S::Corpus as Corpus>::Input>,
|
||||
state: &S,
|
||||
) {
|
||||
fn maybe_update_last_hang(&mut self, testcase: &Testcase<I>, state: &S) {
|
||||
if testcase
|
||||
.hit_objectives()
|
||||
.contains(&Cow::Borrowed(TIMEOUT_FEEDBACK_NAME))
|
||||
@ -652,7 +645,7 @@ pub fn get_run_cmdline() -> Cow<'static, str> {
|
||||
|
||||
/// The Builder for `AflStatsStage`
|
||||
#[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>,
|
||||
plot_file_path: Option<PathBuf>,
|
||||
core_id: Option<CoreId>,
|
||||
@ -664,16 +657,16 @@ pub struct AflStatsStageBuilder<C, E, EM, O, S, Z> {
|
||||
banner: String,
|
||||
version: 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
|
||||
E: HasObservers,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasImported + HasCorpus + HasMetadata + HasExecutions,
|
||||
C: AsRef<O> + Named,
|
||||
E: HasObservers,
|
||||
EM: EventFirer<I, S>,
|
||||
O: MapObserver,
|
||||
S: HasImported + HasMetadata + HasExecutions,
|
||||
{
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
@ -785,7 +778,8 @@ where
|
||||
/// Cannot create the plot file (if provided)
|
||||
/// No `MapObserver` supplied to the builder
|
||||
/// 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() {
|
||||
return Err(Error::illegal_argument("Must set `map_observer`"));
|
||||
}
|
||||
|
@ -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.
|
||||
#[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_name: Cow<'static, str>,
|
||||
name: Cow<'static, str>,
|
||||
stage_max: usize,
|
||||
/// If we should track stability
|
||||
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
|
||||
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers<Observers = OT>,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
E: Executor<EM, I, S, Z> + HasObservers<Observers = OT>,
|
||||
EM: EventFirer<I, S>,
|
||||
O: MapObserver,
|
||||
C: AsRef<O>,
|
||||
for<'de> <O as MapObserver>::Entry:
|
||||
Serialize + Deserialize<'de> + 'static + Default + Debug + Bounded,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus<I>
|
||||
+ HasMetadata
|
||||
+ HasNamedMetadata
|
||||
+ HasExecutions
|
||||
+ HasCurrentTestcase
|
||||
+ HasCurrentTestcase<I>
|
||||
+ HasCurrentCorpusId,
|
||||
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
I: Input,
|
||||
{
|
||||
#[inline]
|
||||
#[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
|
||||
C: AsRef<O>,
|
||||
O: MapObserver,
|
||||
for<'it> O: AsIter<'it, Item = O::Entry>,
|
||||
C: AsRef<O>,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus,
|
||||
OT: ObserversTuple<I, S>,
|
||||
{
|
||||
/// Create a new [`CalibrationStage`].
|
||||
#[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> {
|
||||
&self.name
|
||||
}
|
||||
|
@ -15,10 +15,10 @@ use libafl_bolts::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
corpus::{Corpus, HasCurrentCorpusId},
|
||||
corpus::HasCurrentCorpusId,
|
||||
events::EventFirer,
|
||||
executors::{Executor, HasObservers},
|
||||
inputs::{HasMutatorBytes, HasMutatorResizableBytes},
|
||||
inputs::HasMutatorResizableBytes,
|
||||
mutators::mutations::buffer_copy,
|
||||
nonzero,
|
||||
observers::ObserversTuple,
|
||||
@ -63,25 +63,25 @@ impl Ord for Earlier {
|
||||
pub const COLORIZATION_STAGE_NAME: &str = "colorization";
|
||||
/// The mutational stage using power schedules
|
||||
#[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>,
|
||||
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> {
|
||||
&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
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
E: HasObservers + Executor<EM, <S::Corpus as Corpus>::Input, S, Z>,
|
||||
S: HasCorpus + HasMetadata + HasRand + HasNamedMetadata + HasCurrentCorpusId,
|
||||
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
<S::Corpus as Corpus>::Input: HasMutatorResizableBytes + Clone,
|
||||
EM: EventFirer<I, S>,
|
||||
E: HasObservers + Executor<EM, I, S, Z>,
|
||||
S: HasCorpus<I> + HasMetadata + HasRand + HasNamedMetadata + HasCurrentCorpusId,
|
||||
E::Observers: ObserversTuple<I, S>,
|
||||
I: HasMutatorResizableBytes + Clone,
|
||||
O: Hash,
|
||||
C: AsRef<O> + Named,
|
||||
{
|
||||
@ -107,7 +107,7 @@ where
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
EM: EventFirer<I, S>,
|
||||
O: Hash,
|
||||
C: AsRef<O> + Named,
|
||||
E: HasObservers + Executor<EM, <S::Corpus as Corpus>::Input, S, Z>,
|
||||
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus + HasMetadata + HasRand + HasCurrentCorpusId + HasCurrentTestcase,
|
||||
<S::Corpus as Corpus>::Input: HasMutatorResizableBytes + Clone,
|
||||
E: HasObservers + Executor<EM, I, S, Z>,
|
||||
E::Observers: ObserversTuple<I, S>,
|
||||
S: HasCorpus<I> + HasMetadata + HasRand + HasCurrentCorpusId + HasCurrentTestcase<I>,
|
||||
I: HasMutatorResizableBytes + Clone,
|
||||
{
|
||||
#[inline]
|
||||
fn colorize(
|
||||
@ -167,7 +167,7 @@ where
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
observer_handle: &Handle<C>,
|
||||
) -> Result<<S::Corpus as Corpus>::Input, Error> {
|
||||
) -> Result<I, Error> {
|
||||
let mut input = state.current_input_cloned()?;
|
||||
// The backup of the input
|
||||
let backup = input.clone();
|
||||
@ -308,7 +308,7 @@ where
|
||||
executor: &mut E,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
input: &<S::Corpus as Corpus>::Input,
|
||||
input: &I,
|
||||
observer_handle: &Handle<C>,
|
||||
) -> Result<usize, Error> {
|
||||
executor.observers_mut().pre_exec_all(state, input)?;
|
||||
|
@ -15,7 +15,7 @@ use libafl_bolts::{
|
||||
#[cfg(all(feature = "concolic_mutation", feature = "introspection"))]
|
||||
use crate::monitors::PerfFeature;
|
||||
use crate::{
|
||||
corpus::{Corpus, HasCurrentCorpusId},
|
||||
corpus::HasCurrentCorpusId,
|
||||
executors::{Executor, HasObservers},
|
||||
observers::{concolic::ConcolicObserver, ObserversTuple},
|
||||
stages::{RetryCountRestartHelper, Stage, TracingStage},
|
||||
@ -32,29 +32,29 @@ use crate::{
|
||||
|
||||
/// Wraps a [`TracingStage`] to add concolic observing.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ConcolicTracingStage<'a, EM, TE, S, Z> {
|
||||
pub struct ConcolicTracingStage<'a, EM, I, TE, S, Z> {
|
||||
name: Cow<'static, str>,
|
||||
inner: TracingStage<EM, TE, S, Z>,
|
||||
inner: TracingStage<EM, I, TE, S, Z>,
|
||||
observer_handle: Handle<ConcolicObserver<'a>>,
|
||||
}
|
||||
|
||||
/// The name for concolic tracer
|
||||
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> {
|
||||
&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
|
||||
TE: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
TE::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
TE: Executor<EM, I, S, Z> + HasObservers,
|
||||
TE::Observers: ObserversTuple<I, S>,
|
||||
S: HasExecutions
|
||||
+ HasCorpus
|
||||
+ HasCorpus<I>
|
||||
+ HasNamedMetadata
|
||||
+ HasCurrentTestcase
|
||||
+ HasCurrentTestcase<I>
|
||||
+ HasCurrentCorpusId
|
||||
+ 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
|
||||
/// [`ConcolicObserver`] with the given name.
|
||||
pub fn new(
|
||||
inner: TracingStage<EM, TE, S, Z>,
|
||||
inner: TracingStage<EM, I, TE, S, Z>,
|
||||
observer_handle: Handle<ConcolicObserver<'a>>,
|
||||
) -> Self {
|
||||
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`].
|
||||
#[cfg(feature = "concolic_mutation")]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct SimpleConcolicMutationalStage<Z> {
|
||||
pub struct SimpleConcolicMutationalStage<I, Z> {
|
||||
name: Cow<'static, str>,
|
||||
phantom: PhantomData<Z>,
|
||||
phantom: PhantomData<(I, Z)>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "concolic_mutation")]
|
||||
@ -367,22 +367,22 @@ static mut SIMPLE_CONCOLIC_MUTATIONAL_ID: usize = 0;
|
||||
pub const SIMPLE_CONCOLIC_MUTATIONAL_NAME: &str = "concolicmutation";
|
||||
|
||||
#[cfg(feature = "concolic_mutation")]
|
||||
impl<Z> Named for SimpleConcolicMutationalStage<Z> {
|
||||
impl<I, Z> Named for SimpleConcolicMutationalStage<I, Z> {
|
||||
fn name(&self) -> &Cow<'static, str> {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
<S::Corpus as Corpus>::Input: HasMutatorBytes + Clone,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
I: HasMutatorBytes + Clone,
|
||||
S: HasExecutions
|
||||
+ HasCorpus
|
||||
+ HasCorpus<I>
|
||||
+ HasMetadata
|
||||
+ HasNamedMetadata
|
||||
+ HasCurrentTestcase
|
||||
+ HasCurrentTestcase<I>
|
||||
+ MaybeHasClientPerfMonitor
|
||||
+ HasCurrentCorpusId,
|
||||
{
|
||||
@ -434,7 +434,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "concolic_mutation")]
|
||||
impl<Z> SimpleConcolicMutationalStage<Z> {
|
||||
impl<I, Z> SimpleConcolicMutationalStage<I, Z> {
|
||||
#[must_use]
|
||||
/// Construct this stage
|
||||
pub fn new() -> Self {
|
||||
|
@ -35,20 +35,19 @@ impl_serdeany!(DumpToDiskMetadata);
|
||||
|
||||
/// The [`DumpToDiskStage`] is a stage that dumps the corpus and the solutions to disk
|
||||
#[derive(Debug)]
|
||||
pub struct DumpToDiskStage<CB1, CB2, EM, S, Z> {
|
||||
pub struct DumpToDiskStage<CB1, CB2, EM, I, S, Z> {
|
||||
solutions_dir: PathBuf,
|
||||
corpus_dir: PathBuf,
|
||||
to_bytes: CB1,
|
||||
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
|
||||
CB1: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &S) -> Vec<u8>,
|
||||
CB2: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &CorpusId) -> P,
|
||||
S: HasCorpus + HasSolutions + HasRand + HasMetadata,
|
||||
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
|
||||
CB1: FnMut(&Testcase<I>, &S) -> Vec<u8>,
|
||||
CB2: FnMut(&Testcase<I>, &CorpusId) -> P,
|
||||
S: HasCorpus<I> + HasSolutions<I> + HasRand + HasMetadata,
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
#[inline]
|
||||
@ -76,12 +75,10 @@ where
|
||||
}
|
||||
|
||||
/// Implementation for `DumpToDiskStage` with a default `generate_filename` function.
|
||||
impl<CB1, EM, S, Z>
|
||||
DumpToDiskStage<CB1, fn(&Testcase<<S::Corpus as Corpus>::Input>, &CorpusId) -> String, EM, S, Z>
|
||||
impl<CB1, EM, I, S, Z> DumpToDiskStage<CB1, fn(&Testcase<I>, &CorpusId) -> String, EM, I, S, Z>
|
||||
where
|
||||
S: HasCorpus + HasSolutions + HasRand + HasMetadata,
|
||||
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
S: HasSolutions<I> + HasRand + HasMetadata,
|
||||
I: Input,
|
||||
{
|
||||
/// 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>
|
||||
@ -99,10 +96,7 @@ where
|
||||
|
||||
/// Default `generate_filename` function.
|
||||
#[expect(clippy::trivially_copy_pass_by_ref)]
|
||||
fn generate_filename(
|
||||
testcase: &Testcase<<S::Corpus as Corpus>::Input>,
|
||||
id: &CorpusId,
|
||||
) -> String {
|
||||
fn generate_filename(testcase: &Testcase<I>, id: &CorpusId) -> String {
|
||||
[
|
||||
Some(id.0.to_string()),
|
||||
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
|
||||
S: HasCorpus + HasMetadata + HasSolutions,
|
||||
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
|
||||
S: HasMetadata + HasSolutions<I>,
|
||||
{
|
||||
/// Create a new [`DumpToDiskStage`] with a custom `generate_filename` function.
|
||||
pub fn new_with_custom_filenames<A, B>(
|
||||
@ -165,8 +158,9 @@ where
|
||||
#[inline]
|
||||
fn dump_state_to_disk<P: AsRef<Path>>(&mut self, state: &mut S) -> Result<(), Error>
|
||||
where
|
||||
CB1: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &S) -> Vec<u8>,
|
||||
CB2: FnMut(&Testcase<<S::Corpus as Corpus>::Input>, &CorpusId) -> P,
|
||||
S: HasCorpus<I>,
|
||||
CB1: FnMut(&Testcase<I>, &S) -> Vec<u8>,
|
||||
CB2: FnMut(&Testcase<I>, &CorpusId) -> P,
|
||||
{
|
||||
let (mut corpus_id, mut solutions_id) =
|
||||
if let Some(meta) = state.metadata_map().get::<DumpToDiskMetadata>() {
|
||||
|
@ -51,32 +51,44 @@ pub static GENERALIZATION_STAGE_NAME: &str = "generalization";
|
||||
|
||||
/// A stage that runs a tracer executor
|
||||
#[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>,
|
||||
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> {
|
||||
&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
|
||||
O: MapObserver,
|
||||
C: CanTrack + AsRef<O> + Named,
|
||||
E: Executor<EM, BytesInput, S, Z> + HasObservers,
|
||||
E::Observers: ObserversTuple<BytesInput, S>,
|
||||
O: MapObserver,
|
||||
S: HasExecutions
|
||||
+ HasMetadata
|
||||
+ HasCorpus
|
||||
+ HasCorpus<BytesInput>
|
||||
+ HasNamedMetadata
|
||||
+ HasCurrentCorpusId
|
||||
+ 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]
|
||||
#[expect(clippy::too_many_lines)]
|
||||
fn perform(
|
||||
@ -326,26 +338,13 @@ where
|
||||
|
||||
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]
|
||||
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>
|
||||
impl<C, EM, O, OT, S, Z> GeneralizationStage<C, EM, BytesInput, O, OT, S, Z>
|
||||
where
|
||||
O: MapObserver,
|
||||
C: CanTrack + AsRef<O> + Named,
|
||||
S: HasExecutions + HasMetadata + HasCorpus + MaybeHasClientPerfMonitor,
|
||||
S::Corpus: Corpus<Input = BytesInput>,
|
||||
S: HasExecutions + HasMetadata + HasCorpus<BytesInput> + MaybeHasClientPerfMonitor,
|
||||
OT: ObserversTuple<BytesInput, S>,
|
||||
{
|
||||
/// Create a new [`GeneralizationStage`].
|
||||
@ -372,7 +371,7 @@ where
|
||||
input: &BytesInput,
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
E: Executor<EM, BytesInput, S, Z> + HasObservers,
|
||||
E::Observers: ObserversTuple<BytesInput, S>,
|
||||
{
|
||||
start_timer!(state);
|
||||
@ -414,7 +413,7 @@ where
|
||||
split_char: u8,
|
||||
) -> Result<(), Error>
|
||||
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;
|
||||
while start < payload.len() {
|
||||
@ -452,7 +451,7 @@ where
|
||||
closing_char: u8,
|
||||
) -> Result<(), Error>
|
||||
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;
|
||||
while index < payload.len() {
|
||||
|
@ -6,33 +6,27 @@
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
generators::Generator,
|
||||
stages::Stage,
|
||||
state::{HasCorpus, HasRand},
|
||||
Error, Evaluator,
|
||||
};
|
||||
use crate::{generators::Generator, stages::Stage, state::HasRand, Error, Evaluator};
|
||||
|
||||
/// A [`Stage`] that generates a single input via a [`Generator`] and evaluates
|
||||
/// it using the fuzzer, possibly adding it to the corpus.
|
||||
///
|
||||
/// This stage can be used to construct black-box (e.g., grammar-based) fuzzers.
|
||||
#[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`].
|
||||
pub fn new(g: G) -> Self {
|
||||
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
|
||||
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus + HasRand,
|
||||
G: Generator<<S::Corpus as Corpus>::Input, S>,
|
||||
G: Generator<I, S>,
|
||||
S: HasRand,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
{
|
||||
#[inline]
|
||||
fn perform(
|
||||
|
@ -27,11 +27,10 @@ use crate::{
|
||||
// TODO multi mutators stage
|
||||
|
||||
/// Action performed after the un-transformed input is executed (e.g., updating metadata)
|
||||
#[expect(unused_variables)]
|
||||
pub trait MutatedTransformPost<S>: Sized {
|
||||
/// Perform any post-execution steps necessary for the transformed input (e.g., updating metadata)
|
||||
#[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(())
|
||||
}
|
||||
}
|
||||
@ -43,10 +42,7 @@ impl<S> MutatedTransformPost<S> for () {}
|
||||
///
|
||||
/// This trait is implemented such that all testcases inherently transform to their inputs, should
|
||||
/// the input be cloneable.
|
||||
pub trait MutatedTransform<I, S>: Sized
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
pub trait MutatedTransform<I, S>: Sized {
|
||||
/// Type indicating actions to be taken after the post-transformation input is executed
|
||||
type Post: MutatedTransformPost<S>;
|
||||
|
||||
@ -60,9 +56,8 @@ where
|
||||
// reflexive definition
|
||||
impl<I, S> MutatedTransform<I, S> for I
|
||||
where
|
||||
I: Input + Clone,
|
||||
S: HasCorpus,
|
||||
S::Corpus: Corpus<Input = I>,
|
||||
I: Clone,
|
||||
S: HasCorpus<I>,
|
||||
{
|
||||
type Post = ();
|
||||
|
||||
@ -101,17 +96,17 @@ pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128;
|
||||
|
||||
/// The default mutational stage
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StdMutationalStage<E, EM, I, M, S, Z> {
|
||||
pub struct StdMutationalStage<E, EM, I1, I2, M, S, Z> {
|
||||
/// The name
|
||||
name: Cow<'static, str>,
|
||||
/// The mutator(s) to use
|
||||
mutator: M,
|
||||
/// The maximum amount of iterations we should do each round
|
||||
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
|
||||
S: HasRand,
|
||||
{
|
||||
@ -140,25 +135,25 @@ static mut MUTATIONAL_STAGE_ID: usize = 0;
|
||||
/// The name for mutational stage
|
||||
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> {
|
||||
&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
|
||||
M: Mutator<I, S>,
|
||||
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus
|
||||
+ HasRand
|
||||
I1: Clone + MutatedTransform<I2, S>,
|
||||
I2: Input,
|
||||
M: Mutator<I1, S>,
|
||||
S: HasRand
|
||||
+ HasCorpus<I2>
|
||||
+ HasMetadata
|
||||
+ HasExecutions
|
||||
+ HasNamedMetadata
|
||||
+ HasCurrentCorpusId
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
Z: Evaluator<E, EM, I2, S>,
|
||||
{
|
||||
#[inline]
|
||||
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
|
||||
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus + HasRand + HasCurrentCorpusId + MaybeHasClientPerfMonitor,
|
||||
<S::Corpus as Corpus>::Input: Input + Clone,
|
||||
M: Mutator<I, S>,
|
||||
I: MutatedTransform<I, S> + Input + Clone,
|
||||
S: HasCorpus<I> + HasRand + HasCurrentCorpusId + MaybeHasClientPerfMonitor,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
{
|
||||
/// Creates a new default mutational stage
|
||||
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
|
||||
M: Mutator<I, S>,
|
||||
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus + HasRand + HasCurrentTestcase + MaybeHasClientPerfMonitor,
|
||||
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
I1: MutatedTransform<I2, S> + Clone,
|
||||
I2: Input,
|
||||
M: Mutator<I1, S>,
|
||||
S: HasCorpus<I2> + HasRand + HasCurrentCorpusId + MaybeHasClientPerfMonitor,
|
||||
Z: Evaluator<E, EM, I2, S>,
|
||||
{
|
||||
/// Creates a new transforming mutational stage with the default max iterations
|
||||
pub fn transforming(mutator: M) -> Self {
|
||||
@ -236,7 +231,16 @@ where
|
||||
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
|
||||
fn perform_mutational(
|
||||
&mut self,
|
||||
@ -256,7 +260,7 @@ where
|
||||
let num = self.iterations(state)?;
|
||||
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(());
|
||||
};
|
||||
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>
|
||||
where
|
||||
I: Clone + MutatedTransform<I, S>,
|
||||
M: MultiMutator<I, S>,
|
||||
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus + HasRand + HasNamedMetadata + HasCurrentTestcase + HasCurrentCorpusId,
|
||||
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
S: HasRand + HasNamedMetadata + HasCurrentTestcase<I> + HasCurrentCorpusId,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
{
|
||||
#[inline]
|
||||
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||
|
@ -11,10 +11,9 @@ use libafl_bolts::Named;
|
||||
#[cfg(feature = "introspection")]
|
||||
use crate::monitors::PerfFeature;
|
||||
use crate::{
|
||||
corpus::{Corpus, HasCurrentCorpusId},
|
||||
corpus::HasCurrentCorpusId,
|
||||
executors::{Executor, HasObservers},
|
||||
fuzzer::Evaluator,
|
||||
inputs::Input,
|
||||
mark_feature_time,
|
||||
mutators::{MutationResult, Mutator},
|
||||
schedulers::{testcase_score::CorpusPowerTestcaseScore, TestcaseScore},
|
||||
@ -23,7 +22,7 @@ use crate::{
|
||||
MutationalStage, RetryCountRestartHelper, Stage,
|
||||
},
|
||||
start_timer,
|
||||
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasRand, MaybeHasClientPerfMonitor},
|
||||
state::{HasCurrentTestcase, HasExecutions, HasRand, MaybeHasClientPerfMonitor},
|
||||
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>
|
||||
where
|
||||
S: HasCurrentTestcase,
|
||||
F: TestcaseScore<S>,
|
||||
S: HasCurrentTestcase<I>,
|
||||
F: TestcaseScore<I, S>,
|
||||
{
|
||||
type Mutator = M;
|
||||
/// 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>
|
||||
where
|
||||
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
F: TestcaseScore<S>,
|
||||
E: Executor<EM, I, S, Z> + HasObservers,
|
||||
F: TestcaseScore<I, S>,
|
||||
M: Mutator<I, S>,
|
||||
S: HasCorpus
|
||||
+ HasMetadata
|
||||
S: HasMetadata
|
||||
+ HasRand
|
||||
+ HasExecutions
|
||||
+ HasNamedMetadata
|
||||
+ HasCurrentTestcase
|
||||
+ HasCurrentTestcase<I>
|
||||
+ HasCurrentCorpusId
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone + Input,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
I: MutatedTransform<I, S> + Clone,
|
||||
{
|
||||
#[inline]
|
||||
#[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>
|
||||
where
|
||||
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
F: TestcaseScore<S>,
|
||||
I: Input,
|
||||
E: Executor<EM, I, S, Z> + HasObservers,
|
||||
F: TestcaseScore<I, S>,
|
||||
M: Mutator<I, S>,
|
||||
S: HasCorpus + HasMetadata + HasRand + HasCurrentTestcase + MaybeHasClientPerfMonitor,
|
||||
I: MutatedTransform<<S::Corpus as Corpus>::Input, S> + Clone + Input,
|
||||
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
S: HasMetadata + HasRand + HasCurrentTestcase<I> + MaybeHasClientPerfMonitor,
|
||||
I: MutatedTransform<I, S> + Clone,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
{
|
||||
/// Creates a new [`PowerMutationalStage`]
|
||||
pub fn new(mutator: M) -> Self {
|
||||
|
@ -23,7 +23,7 @@ pub use mutational::StdMutationalPushStage;
|
||||
|
||||
use crate::{
|
||||
common::HasNamedMetadata,
|
||||
corpus::{Corpus, CorpusId, HasCurrentCorpusId},
|
||||
corpus::{CorpusId, HasCurrentCorpusId},
|
||||
events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter},
|
||||
executors::{Executor, ExitKind, HasObservers},
|
||||
observers::ObserversTuple,
|
||||
@ -43,7 +43,7 @@ pub struct PushStageSharedState<EM, I, OT, S, Z> {
|
||||
pub fuzzer: Z,
|
||||
/// The event manager
|
||||
pub event_mgr: EM,
|
||||
/// The [`crate::observers::ObserversTuple`]
|
||||
/// The [`ObserversTuple`]
|
||||
pub observers: OT,
|
||||
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`]
|
||||
#[derive(Debug)]
|
||||
pub struct PushStageAdapter<CS, EM, OT, PS, Z> {
|
||||
pub struct PushStageAdapter<CS, EM, I, OT, PS, Z> {
|
||||
name: Cow<'static, str>,
|
||||
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`]
|
||||
/// to be used as a normal [`Stage`]
|
||||
#[must_use]
|
||||
@ -237,35 +237,43 @@ static mut PUSH_STAGE_ADAPTER_ID: usize = 0;
|
||||
/// The name for push stage adapter
|
||||
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]
|
||||
fn name(&self) -> &Cow<'static, str> {
|
||||
&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
|
||||
CS: Scheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
CS: Scheduler<I, S>,
|
||||
S: HasExecutions
|
||||
+ HasRand
|
||||
+ HasCorpus
|
||||
+ HasCorpus<I>
|
||||
+ HasLastReportTime
|
||||
+ HasCurrentCorpusId
|
||||
+ HasNamedMetadata
|
||||
+ HasMetadata,
|
||||
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers<Observers = OT>,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>
|
||||
+ EventRestarter<S>
|
||||
+ HasEventManagerId
|
||||
+ ProgressReporter<S>,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
PS: PushStage<EM, <S::Corpus as Corpus>::Input, OT, S, Z>,
|
||||
Z: ExecutesInput<E, EM, <S::Corpus as Corpus>::Input, 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>,
|
||||
E: Executor<EM, I, S, Z> + HasObservers<Observers = OT>,
|
||||
EM: EventFirer<I, S> + EventRestarter<S> + HasEventManagerId + ProgressReporter<S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
PS: PushStage<EM, I, OT, S, Z>,
|
||||
Z: ExecutesInput<E, EM, I, S>
|
||||
+ ExecutionProcessor<EM, I, OT, S>
|
||||
+ EvaluatorObservers<E, EM, I, OT>
|
||||
+ HasScheduler<I, 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(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
@ -309,15 +317,4 @@ where
|
||||
self.push_stage
|
||||
.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)
|
||||
}
|
||||
}
|
||||
|
@ -43,10 +43,10 @@ pub const DEFAULT_MUTATIONAL_MAX_ITERATIONS: usize = 128;
|
||||
///
|
||||
/// The default mutational push stage
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StdMutationalPushStage<EM, M, OT, S, Z>
|
||||
pub struct StdMutationalPushStage<EM, M, I, OT, S, Z>
|
||||
where
|
||||
S: HasCorpus,
|
||||
<S::Corpus as Corpus>::Input: Clone + Debug,
|
||||
S: HasCorpus<I>,
|
||||
I: Clone + Debug,
|
||||
{
|
||||
current_corpus_id: Option<CorpusId>,
|
||||
testcases_to_do: usize,
|
||||
@ -54,13 +54,13 @@ where
|
||||
|
||||
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
|
||||
S: HasCorpus + HasRand,
|
||||
<S::Corpus as Corpus>::Input: Clone + Debug,
|
||||
S: HasCorpus<I> + HasRand,
|
||||
I: Clone + Debug,
|
||||
{
|
||||
/// 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
|
||||
@ -76,26 +76,22 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<EM, M, OT, S, Z> PushStage<EM, <S::Corpus as Corpus>::Input, OT, S, Z>
|
||||
for StdMutationalPushStage<EM, M, OT, S, Z>
|
||||
impl<EM, M, I, OT, S, Z> PushStage<EM, I, OT, S, Z> for StdMutationalPushStage<EM, M, I, OT, S, Z>
|
||||
where
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
Z: HasScheduler<<S::Corpus as Corpus>::Input, S>
|
||||
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, OT, S>,
|
||||
S: HasCorpus + HasRand + MaybeHasClientPerfMonitor,
|
||||
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||
<S::Corpus as Corpus>::Input: Input + Clone,
|
||||
EM: EventFirer<I, S>,
|
||||
Z: HasScheduler<I, S> + ExecutionProcessor<EM, I, OT, S>,
|
||||
S: HasCorpus<I> + HasRand + MaybeHasClientPerfMonitor,
|
||||
M: Mutator<I, S>,
|
||||
OT: ObserversTuple<I, S> + Serialize,
|
||||
I: Input + Clone,
|
||||
{
|
||||
#[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
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn push_stage_helper_mut(
|
||||
&mut self,
|
||||
) -> &mut PushStageHelper<EM, <S::Corpus as Corpus>::Input, OT, S, Z> {
|
||||
fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper<EM, I, OT, S, Z> {
|
||||
&mut self.psh
|
||||
}
|
||||
|
||||
@ -125,7 +121,7 @@ where
|
||||
state: &mut S,
|
||||
_event_mgr: &mut EM,
|
||||
_observers: &mut OT,
|
||||
) -> Option<Result<<S::Corpus as Corpus>::Input, Error>> {
|
||||
) -> Option<Result<I, Error>> {
|
||||
if self.testcases_done >= self.testcases_to_do {
|
||||
// finished with this cicle.
|
||||
return None;
|
||||
@ -160,7 +156,7 @@ where
|
||||
state: &mut S,
|
||||
event_mgr: &mut EM,
|
||||
observers: &mut OT,
|
||||
last_input: <S::Corpus as Corpus>::Input,
|
||||
last_input: I,
|
||||
exit_kind: ExitKind,
|
||||
) -> Result<(), Error> {
|
||||
// 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
|
||||
EM: ProgressReporter<S> + EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus
|
||||
EM: ProgressReporter<S> + EventFirer<I, S>,
|
||||
S: HasCorpus<I>
|
||||
+ HasMetadata
|
||||
+ HasExecutions
|
||||
+ HasLastReportTime
|
||||
+ HasRand
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||
<S::Corpus as Corpus>::Input: Clone + Debug + Input,
|
||||
Z: HasScheduler<<S::Corpus as Corpus>::Input, S>
|
||||
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, OT, S>,
|
||||
OT: ObserversTuple<I, S> + Serialize,
|
||||
M: Mutator<I, S>,
|
||||
I: Clone + Debug + Input,
|
||||
Z: HasScheduler<I, S> + ExecutionProcessor<EM, I, 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()
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
EM: ProgressReporter<S> + EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus
|
||||
EM: ProgressReporter<S> + EventFirer<I, S>,
|
||||
S: HasCorpus<I>
|
||||
+ HasMetadata
|
||||
+ HasExecutions
|
||||
+ HasLastReportTime
|
||||
+ HasRand
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||
<S::Corpus as Corpus>::Input: Clone + Debug + Input,
|
||||
Z: HasScheduler<<S::Corpus as Corpus>::Input, S>
|
||||
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, OT, S>,
|
||||
OT: ObserversTuple<I, S> + Serialize,
|
||||
M: Mutator<I, S>,
|
||||
I: Clone + Debug + Input,
|
||||
Z: HasScheduler<I, S> + ExecutionProcessor<EM, I, OT, S>,
|
||||
{
|
||||
/// Creates a new default mutational stage
|
||||
#[must_use]
|
||||
#[expect(clippy::type_complexity)]
|
||||
pub fn new(
|
||||
mutator: M,
|
||||
shared_state: Rc<
|
||||
RefCell<Option<PushStageSharedState<EM, <S::Corpus as Corpus>::Input, OT, S, Z>>>,
|
||||
>,
|
||||
shared_state: Rc<RefCell<Option<PushStageSharedState<EM, I, OT, S, Z>>>>,
|
||||
exit_kind: Rc<Cell<Option<ExitKind>>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
@ -245,7 +237,7 @@ where
|
||||
}
|
||||
|
||||
/// 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 shared_state_ref = &mut (*self.push_stage_helper_mut().shared_state).borrow_mut();
|
||||
shared_state_ref.take().unwrap()
|
||||
|
@ -52,31 +52,43 @@ impl SyncFromDiskMetadata {
|
||||
|
||||
/// A stage that loads testcases from disk to sync with other fuzzers such as AFL++
|
||||
#[derive(Debug)]
|
||||
pub struct SyncFromDiskStage<CB, E, EM, S, Z> {
|
||||
pub struct SyncFromDiskStage<CB, E, EM, I, S, Z> {
|
||||
name: Cow<'static, str>,
|
||||
sync_dirs: Vec<PathBuf>,
|
||||
load_callback: CB,
|
||||
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> {
|
||||
&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
|
||||
CB: FnMut(&mut Z, &mut S, &Path) -> Result<<S::Corpus as Corpus>::Input, Error>,
|
||||
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus
|
||||
CB: FnMut(&mut Z, &mut S, &Path) -> Result<I, Error>,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
S: HasCorpus<I>
|
||||
+ HasRand
|
||||
+ HasMetadata
|
||||
+ HasNamedMetadata
|
||||
+ HasCurrentCorpusId
|
||||
+ 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]
|
||||
fn perform(
|
||||
&mut self,
|
||||
@ -136,21 +148,9 @@ where
|
||||
|
||||
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]
|
||||
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> {
|
||||
impl<CB, E, EM, I, S, Z> SyncFromDiskStage<CB, E, EM, I, S, Z> {
|
||||
/// Creates a new [`SyncFromDiskStage`]
|
||||
#[must_use]
|
||||
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
|
||||
pub type SyncFromDiskFunction<S, Z> =
|
||||
fn(&mut Z, &mut S, &Path) -> Result<<<S as HasCorpus>::Corpus as Corpus>::Input, Error>;
|
||||
pub type SyncFromDiskFunction<I, S, Z> = fn(&mut Z, &mut S, &Path) -> Result<I, 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
|
||||
S: HasCorpus,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
Z: Evaluator<E, EM, <S::Corpus as Corpus>::Input, S>,
|
||||
I: Input,
|
||||
S: HasCorpus<I>,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
{
|
||||
/// Creates a new [`SyncFromDiskStage`] invoking `Input::from_file` to load inputs
|
||||
#[must_use]
|
||||
pub fn with_from_file(sync_dirs: Vec<PathBuf>, interval: Duration) -> Self {
|
||||
fn load_callback<S: HasCorpus, Z>(
|
||||
_: &mut Z,
|
||||
_: &mut S,
|
||||
p: &Path,
|
||||
) -> Result<<S::Corpus as Corpus>::Input, Error>
|
||||
fn load_callback<I, S, Z>(_: &mut Z, _: &mut S, p: &Path) -> Result<I, Error>
|
||||
where
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
I: Input,
|
||||
S: HasCorpus<I>,
|
||||
{
|
||||
Input::from_file(p)
|
||||
}
|
||||
@ -191,7 +187,7 @@ where
|
||||
interval,
|
||||
name: Cow::Borrowed(SYNC_FROM_DISK_STAGE_NAME),
|
||||
sync_dirs,
|
||||
load_callback: load_callback::<_, _>,
|
||||
load_callback: load_callback::<_, _, _>,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -220,27 +216,38 @@ impl SyncFromBrokerMetadata {
|
||||
|
||||
/// A stage that loads testcases from disk to sync with other fuzzers such as AFL++
|
||||
#[derive(Debug)]
|
||||
pub struct SyncFromBrokerStage<IC, ICB, S, SP>
|
||||
pub struct SyncFromBrokerStage<I, IC, ICB, S, SP>
|
||||
where
|
||||
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
|
||||
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,
|
||||
<<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]
|
||||
fn perform(
|
||||
&mut self,
|
||||
@ -298,27 +305,15 @@ where
|
||||
state.introspection_monitor_mut().finish_stage();
|
||||
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]
|
||||
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>
|
||||
impl<I, IC, ICB, S, SP> SyncFromBrokerStage<I, IC, ICB, S, SP>
|
||||
where
|
||||
SP: ShMemProvider,
|
||||
{
|
||||
/// Creates a new [`SyncFromBrokerStage`]
|
||||
#[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 }
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ use crate::{
|
||||
|
||||
/// The default corpus entry minimising mutational stage
|
||||
#[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
|
||||
name: Cow<'static, str>,
|
||||
/// The mutator(s) this stage uses
|
||||
@ -54,39 +54,40 @@ pub struct StdTMinMutationalStage<E, EM, F, FF, M, S, Z> {
|
||||
runs: usize,
|
||||
/// The progress helper for this stage, keeping track of resumes after timeouts/crashes
|
||||
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
|
||||
Z: HasScheduler<<S::Corpus as Corpus>::Input, S>
|
||||
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, E::Observers, S>
|
||||
+ ExecutesInput<E, EM, <S::Corpus as Corpus>::Input, S>
|
||||
Z: HasScheduler<I, S>
|
||||
+ ExecutionProcessor<EM, I, E::Observers, S>
|
||||
+ ExecutesInput<E, EM, I, S>
|
||||
+ HasFeedback,
|
||||
Z::Scheduler: RemovableScheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
Z::Scheduler: RemovableScheduler<I, S>,
|
||||
E: HasObservers,
|
||||
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
E::Observers: ObserversTuple<I, S> + Serialize,
|
||||
EM: EventFirer<I, S>,
|
||||
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
|
||||
+ HasCorpus<I>
|
||||
+ HasExecutions
|
||||
+ HasSolutions
|
||||
+ HasCorpus
|
||||
+ HasSolutions<I>
|
||||
+ HasMaxSize
|
||||
+ HasNamedMetadata
|
||||
+ HasCurrentCorpusId
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
Z::Feedback: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
|
||||
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||
<<S as HasCorpus>::Corpus as Corpus>::Input: Input + Hash + HasLen,
|
||||
Z::Feedback: Feedback<EM, I, E::Observers, S>,
|
||||
M: Mutator<I, S>,
|
||||
I: Input + Hash + HasLen,
|
||||
{
|
||||
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
|
||||
self.restart_helper.should_restart(state, &self.name)
|
||||
}
|
||||
|
||||
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(
|
||||
@ -105,8 +106,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, EM, F, FF, M, S, Z> FeedbackFactory<F, E::Observers>
|
||||
for StdTMinMutationalStage<E, EM, F, FF, M, S, Z>
|
||||
impl<E, EM, F, FF, I, M, S, Z> FeedbackFactory<F, E::Observers>
|
||||
for StdTMinMutationalStage<E, EM, F, FF, I, M, S, Z>
|
||||
where
|
||||
E: HasObservers,
|
||||
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> {
|
||||
&self.name
|
||||
}
|
||||
@ -127,30 +128,30 @@ static mut TMIN_STAGE_ID: usize = 0;
|
||||
/// The name for tmin stage
|
||||
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
|
||||
Z: HasScheduler<<S::Corpus as Corpus>::Input, S>
|
||||
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, E::Observers, S>
|
||||
+ ExecutesInput<E, EM, <S::Corpus as Corpus>::Input, S>
|
||||
Z: HasScheduler<I, S>
|
||||
+ ExecutionProcessor<EM, I, E::Observers, S>
|
||||
+ ExecutesInput<E, EM, I, S>
|
||||
+ HasFeedback,
|
||||
Z::Scheduler: RemovableScheduler<<S::Corpus as Corpus>::Input, S>,
|
||||
Z::Scheduler: RemovableScheduler<I, S>,
|
||||
E: HasObservers,
|
||||
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S> + Serialize,
|
||||
EM: EventFirer<<S::Corpus as Corpus>::Input, S>,
|
||||
E::Observers: ObserversTuple<I, S> + Serialize,
|
||||
EM: EventFirer<I, S>,
|
||||
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
|
||||
+ HasExecutions
|
||||
+ HasSolutions
|
||||
+ HasCorpus
|
||||
+ HasSolutions<I>
|
||||
+ HasCorpus<I>
|
||||
+ HasMaxSize
|
||||
+ HasNamedMetadata
|
||||
+ HasCurrentTestcase
|
||||
+ HasCurrentTestcase<I>
|
||||
+ HasCurrentCorpusId
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
Z::Feedback: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
|
||||
M: Mutator<<S::Corpus as Corpus>::Input, S>,
|
||||
<S::Corpus as Corpus>::Input: Hash + HasLen + Input,
|
||||
Z::Feedback: Feedback<EM, I, E::Observers, S>,
|
||||
M: Mutator<I, S>,
|
||||
I: Hash + HasLen + Input,
|
||||
{
|
||||
/// The list of mutators, added to this stage (as mutable ref)
|
||||
#[inline]
|
||||
@ -189,10 +190,7 @@ where
|
||||
}
|
||||
|
||||
start_timer!(state);
|
||||
let transformed = <S::Corpus as Corpus>::Input::try_transform_from(
|
||||
state.current_testcase_mut()?.borrow_mut(),
|
||||
state,
|
||||
)?;
|
||||
let transformed = I::try_transform_from(state.current_testcase_mut()?.borrow_mut(), state)?;
|
||||
let mut base = state.current_input_cloned()?;
|
||||
// potential post operation if base is replaced by a shorter input
|
||||
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
|
||||
pub fn new(mutator: M, factory: FF, runs: usize) -> Self {
|
||||
// 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
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ObserverEqualityFactory<C, M, S> {
|
||||
pub struct ObserverEqualityFactory<C, I, M, S> {
|
||||
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
|
||||
M: Hash,
|
||||
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;
|
||||
|
||||
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>
|
||||
for ObserverEqualityFactory<C, M, S>
|
||||
impl<C, I, M, OT, S> FeedbackFactory<ObserverEqualityFeedback<C, M, S>, OT>
|
||||
for ObserverEqualityFactory<C, I, M, S>
|
||||
where
|
||||
M: Hash,
|
||||
C: AsRef<M> + Handled,
|
||||
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
S: HasCorpus,
|
||||
OT: ObserversTuple<I, S>,
|
||||
S: HasCorpus<I>,
|
||||
{
|
||||
fn create_feedback(&self, observers: &OT) -> ObserverEqualityFeedback<C, M, S> {
|
||||
let obs = observers
|
||||
|
@ -11,7 +11,7 @@ use libafl_bolts::Named;
|
||||
#[cfg(feature = "introspection")]
|
||||
use crate::monitors::PerfFeature;
|
||||
use crate::{
|
||||
corpus::{Corpus, HasCurrentCorpusId},
|
||||
corpus::HasCurrentCorpusId,
|
||||
executors::{Executor, HasObservers, ShadowExecutor},
|
||||
inputs::Input,
|
||||
mark_feature_time,
|
||||
@ -24,20 +24,20 @@ use crate::{
|
||||
|
||||
/// A stage that runs a tracer executor
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TracingStage<EM, TE, S, Z> {
|
||||
pub struct TracingStage<EM, I, TE, S, Z> {
|
||||
name: Cow<'static, str>,
|
||||
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
|
||||
TE: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
TE::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
TE: Executor<EM, I, S, Z> + HasObservers,
|
||||
TE::Observers: ObserversTuple<I, S>,
|
||||
S: HasExecutions
|
||||
+ HasCorpus
|
||||
+ HasCorpus<I>
|
||||
+ HasNamedMetadata
|
||||
+ HasCurrentTestcase
|
||||
+ HasCurrentTestcase<I>
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
{
|
||||
/// 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
|
||||
TE: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
TE::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
TE: Executor<EM, I, S, Z> + HasObservers,
|
||||
TE::Observers: ObserversTuple<I, S>,
|
||||
S: HasExecutions
|
||||
+ HasCorpus
|
||||
+ HasCorpus<I>
|
||||
+ HasNamedMetadata
|
||||
+ HasCurrentCorpusId
|
||||
+ MaybeHasClientPerfMonitor,
|
||||
<S::Corpus as Corpus>::Input: Input,
|
||||
I: Input,
|
||||
{
|
||||
#[inline]
|
||||
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> {
|
||||
&self.name
|
||||
}
|
||||
@ -114,7 +114,7 @@ static mut TRACING_STAGE_ID: usize = 0;
|
||||
/// The name for tracing stage
|
||||
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
|
||||
pub fn new(tracer_executor: TE) -> Self {
|
||||
// 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
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ShadowTracingStage<E, EM, SOT, S, Z> {
|
||||
pub struct ShadowTracingStage<E, EM, I, SOT, S, Z> {
|
||||
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
|
||||
@ -154,31 +154,39 @@ static mut SHADOW_TRACING_STAGE_ID: usize = 0;
|
||||
/// Name for shadow tracing stage
|
||||
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> {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, EM, SOT, S, Z> Stage<ShadowExecutor<E, S, SOT>, EM, S, Z>
|
||||
for ShadowTracingStage<E, EM, SOT, S, Z>
|
||||
impl<E, EM, I, SOT, S, Z> Stage<ShadowExecutor<E, I, S, SOT>, EM, S, Z>
|
||||
for ShadowTracingStage<E, EM, I, SOT, S, Z>
|
||||
where
|
||||
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
E: Executor<EM, I, S, Z> + HasObservers,
|
||||
E::Observers: ObserversTuple<I, S>,
|
||||
SOT: ObserversTuple<I, S>,
|
||||
S: HasExecutions
|
||||
+ HasCorpus
|
||||
+ HasCorpus<I>
|
||||
+ HasNamedMetadata
|
||||
+ Debug
|
||||
+ HasCurrentTestcase
|
||||
+ HasCurrentTestcase<I>
|
||||
+ HasCurrentCorpusId
|
||||
+ 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]
|
||||
fn perform(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
executor: &mut ShadowExecutor<E, S, SOT>,
|
||||
executor: &mut ShadowExecutor<E, I, S, SOT>,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
) -> Result<(), Error> {
|
||||
@ -209,24 +217,16 @@ where
|
||||
|
||||
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> {
|
||||
RetryCountRestartHelper::clear_progress(state, &self.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, EM, SOT, S, Z> ShadowTracingStage<E, EM, SOT, S, Z>
|
||||
impl<E, EM, I, SOT, S, Z> ShadowTracingStage<E, EM, I, SOT, S, Z>
|
||||
where
|
||||
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
|
||||
S: HasExecutions + HasCorpus,
|
||||
SOT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
|
||||
E: Executor<EM, I, S, Z> + HasObservers,
|
||||
S: HasExecutions + HasCorpus<I>,
|
||||
SOT: ObserversTuple<I, S>,
|
||||
{
|
||||
/// 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
|
||||
let stage_id = unsafe {
|
||||
let ret = SHADOW_TRACING_STAGE_ID;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user