Match by Ref fix (#2105)

* match by ref fix

* impl Named for Reference

* rename

* magic indexing

* whoops

* docs, clippy

* some additional CI complaints

* other libafl_qemu fixes

* missed an alloc feature

* a smattering of fixes

* use from not direct construction

* tinyinst fix

* horrible double-mutability things

* fixup nyx

* from not new

* forkserver_simple fixes

* dogfood: forkserver

* mmmm yummy dogfood

* round one CI fixes

* clippy appeasement

* deref generic impl to simplify usage

* adaptive serialization (ouch)

* remaining clippy items

* I am tired

* new not with

* fixup: aflpp tracing was not actually constructable

* fix tmin

* reduce complexity of map feedback now that we do not need to constrain

* frida fixes

* fix concolic

* type_ref => reference
This commit is contained in:
Addison Crump 2024-04-27 18:08:09 +02:00 committed by GitHub
parent 084b9b5878
commit 28c43b332f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
85 changed files with 1279 additions and 847 deletions

View File

@ -36,7 +36,7 @@ pub fn main() -> Result<(), Error> {
// Create an observation channel using the signals map
let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) };
let factory = MapEqualityFactory::with_observer(&observer);
let factory = MapEqualityFactory::new(&observer);
// Feedback to rate the interestingness of an input
let mut feedback = MaxMapFeedback::new(&observer);

View File

@ -116,7 +116,7 @@ pub fn main() {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not
@ -167,7 +167,7 @@ pub fn main() {
// Create the executor for the forkserver
let args = opt.arguments;
let observer_ref = edges_observer.type_ref();
let observer_ref = edges_observer.reference();
let mut tokens = Tokens::new();
let mut executor = ForkserverExecutor::builder()
@ -183,10 +183,7 @@ pub fn main() {
.unwrap();
if let Some(dynamic_map_size) = executor.coverage_map_size() {
executor
.observers_mut()
.match_by_ref_mut(observer_ref)
.unwrap()
executor.observers_mut()[&observer_ref]
.as_mut()
.truncate(dynamic_map_size);
}

View File

@ -12,7 +12,7 @@ use libafl::{
inputs::BytesInput,
monitors::SimpleMonitor,
mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
observers::{CanTrack, ExplicitTracking, HitcountsMapObserver, StdMapObserver, TimeObserver},
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::mutational::StdMutationalStage,
state::{HasCorpus, StdState},
@ -22,7 +22,7 @@ use libafl_bolts::{
current_nanos,
rands::StdRand,
shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::{tuple_list, MatchName, Merge},
tuples::{tuple_list, Merge, Referenceable},
AsSliceMut, Truncate,
};
use nix::sys::signal::Signal;
@ -114,7 +114,7 @@ pub fn main() {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not
@ -163,6 +163,8 @@ pub fn main() {
// Create the executor for the forkserver
let args = opt.arguments;
let observer_ref = edges_observer.reference();
let mut tokens = Tokens::new();
let mut executor = ForkserverExecutor::builder()
.program(opt.executable)
@ -177,10 +179,7 @@ pub fn main() {
.unwrap();
if let Some(dynamic_map_size) = executor.coverage_map_size() {
executor
.observers_mut()
.match_name_mut::<ExplicitTracking<HitcountsMapObserver<StdMapObserver<'_, u8, false>>, true, false>>("shared_mem")
.unwrap()
executor.observers_mut()[&observer_ref]
.as_mut()
.truncate(dynamic_map_size);
}

View File

@ -35,7 +35,7 @@ use libafl_bolts::{
#[cfg(unix)]
use libafl_frida::asan::{
asan_rt::AsanRuntime,
errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS},
errors::{AsanErrorsFeedback, AsanErrorsObserver},
};
use libafl_frida::{
cmplog_rt::CmpLogRuntime,
@ -123,6 +123,8 @@ unsafe fn fuzz(
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
@ -130,7 +132,7 @@ unsafe fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// Feedbacks to recognize an input as solution
@ -139,7 +141,10 @@ unsafe fn fuzz(
CrashFeedback::new(),
TimeoutFeedback::new(),
// true enables the AsanErrorFeedback
feedback_and_fast!(ConstFeedback::from(true), AsanErrorsFeedback::new())
feedback_and_fast!(
ConstFeedback::from(true),
AsanErrorsFeedback::new(&asan_observer)
)
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -185,9 +190,7 @@ unsafe fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe {
AsanErrorsObserver::from_static_asan_errors()
});
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer);
@ -240,6 +243,8 @@ unsafe fn fuzz(
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
@ -247,14 +252,17 @@ unsafe fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
#[cfg(unix)]
let mut objective = feedback_or_fast!(
CrashFeedback::new(),
TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new())
feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -300,11 +308,9 @@ unsafe fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe {
AsanErrorsObserver::from_static_asan_errors()
});
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,);
let observers = tuple_list!(edges_observer, time_observer);
// Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new(
@ -370,6 +376,8 @@ unsafe fn fuzz(
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
@ -377,14 +385,17 @@ unsafe fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
#[cfg(unix)]
let mut objective = feedback_or_fast!(
CrashFeedback::new(),
TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new())
feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -430,11 +441,9 @@ unsafe fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe {
AsanErrorsObserver::from_static_asan_errors()
});
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,);
let observers = tuple_list!(edges_observer, time_observer);
// Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new(

View File

@ -99,7 +99,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let coverage = CoverageRuntime::new();
#[cfg(unix)]
let asan = AsanRuntime::new(&options);
let asan = AsanRuntime::new(options);
#[cfg(unix)]
let mut frida_helper =
@ -119,13 +119,16 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// Feedbacks to recognize an input as solution
@ -134,7 +137,10 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
CrashFeedback::new(),
TimeoutFeedback::new(),
// true enables the AsanErrorFeedback
feedback_and_fast!(ConstFeedback::from(true), AsanErrorsFeedback::new())
feedback_and_fast!(
ConstFeedback::from(true),
AsanErrorsFeedback::new(&asan_observer)
)
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -179,9 +185,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe {
AsanErrorsObserver::from_static_asan_errors()
});
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer);
@ -234,6 +238,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
@ -241,14 +247,17 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
#[cfg(unix)]
let mut objective = feedback_or_fast!(
CrashFeedback::new(),
TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new())
feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -294,9 +303,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe {
AsanErrorsObserver::from_static_asan_errors()
});
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,);
@ -366,20 +373,26 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
#[cfg(unix)]
let mut objective = feedback_or_fast!(
CrashFeedback::new(),
TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new())
feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -425,11 +438,9 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe {
AsanErrorsObserver::from_static_asan_errors()
});
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,);
let observers = tuple_list!(edges_observer, time_observer);
// Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new(

View File

@ -35,7 +35,7 @@ use libafl_bolts::{
#[cfg(unix)]
use libafl_frida::asan::{
asan_rt::AsanRuntime,
errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS},
errors::{AsanErrorsFeedback, AsanErrorsObserver},
};
use libafl_frida::{
cmplog_rt::CmpLogRuntime,
@ -113,6 +113,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
@ -120,7 +122,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// Feedbacks to recognize an input as solution
@ -129,7 +131,10 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
CrashFeedback::new(),
TimeoutFeedback::new(),
// true enables the AsanErrorFeedback
feedback_and_fast!(ConstFeedback::from(true), AsanErrorsFeedback::new())
feedback_and_fast!(
ConstFeedback::from(true),
AsanErrorsFeedback::new(&asan_observer)
)
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -175,9 +180,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe {
AsanErrorsObserver::from_static_asan_errors()
});
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer);
@ -231,6 +234,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
@ -238,14 +243,17 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
#[cfg(unix)]
let mut objective = feedback_or_fast!(
CrashFeedback::new(),
TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new())
feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -291,11 +299,9 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, unsafe {
AsanErrorsObserver::from_static_asan_errors()
});
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,);
let observers = tuple_list!(edges_observer, time_observer);
// Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new(
@ -361,6 +367,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
@ -368,14 +376,17 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
#[cfg(unix)]
let mut objective = feedback_or_fast!(
CrashFeedback::new(),
TimeoutFeedback::new(),
feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new())
feedback_and_fast!(
ConstFeedback::from(false),
AsanErrorsFeedback::new(&asan_observer)
)
);
#[cfg(windows)]
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
@ -421,13 +432,9 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(unix)]
let observers = tuple_list!(
edges_observer,
time_observer,
AsanErrorsObserver::from_static_asan_errors()
);
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer,);
let observers = tuple_list!(edges_observer, time_observer);
// Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new(

View File

@ -260,7 +260,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -270,7 +270,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -258,7 +258,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -267,7 +267,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -37,7 +37,7 @@ use libafl_bolts::{
ownedref::OwnedRefMut,
rands::StdRand,
shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::{tuple_list, Merge},
tuples::{tuple_list, Merge, Referenceable},
AsSliceMut,
};
use libafl_targets::{
@ -268,7 +268,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not
@ -355,6 +355,7 @@ fn fuzz(
let cmpmap = unsafe { OwnedRefMut::from_shmem(&mut cmplog_shmem) };
let cmplog_observer = AFLppCmpLogObserver::new("cmplog", cmpmap, true);
let cmplog_ref = cmplog_observer.reference();
let cmplog_executor = ForkserverExecutor::builder()
.program(exec)
@ -367,7 +368,7 @@ fn fuzz(
.build(tuple_list!(cmplog_observer))
.unwrap();
let tracing = AFLppCmplogTracingStage::with_cmplog_observer_name(cmplog_executor, "cmplog");
let tracing = AFLppCmplogTracingStage::with_cmplog_observer(cmplog_executor, cmplog_ref);
// Setup a randomic Input2State stage
let rq = MultiMutationalStage::new(AFLppRedQueen::with_cmplog_options(true, true));

View File

@ -279,7 +279,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -328,7 +328,7 @@ fn fuzz_binary(
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not
let mut objective = CrashFeedback::new();
@ -539,7 +539,7 @@ fn fuzz_text(
let mut feedback = feedback_or!(
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -151,7 +151,7 @@ pub extern "C" fn LLVMFuzzerRunDriver(
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -101,7 +101,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -152,7 +152,7 @@ pub extern "C" fn libafl_main() {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -115,7 +115,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -150,7 +150,7 @@ pub extern "C" fn libafl_main() {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -100,7 +100,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -151,7 +151,7 @@ pub extern "C" fn libafl_main() {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -176,7 +176,7 @@ pub extern "C" fn libafl_main() {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -99,7 +99,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -81,7 +81,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -42,8 +42,8 @@ use libafl_bolts::{
current_nanos,
rands::StdRand,
shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::tuple_list,
AsSliceMut, AsSlice, Named,
tuples::{tuple_list, Referenceable},
AsSliceMut, AsSlice
};
use libafl_targets::{
libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer, CmpLogObserver,
@ -119,7 +119,7 @@ fn fuzz(
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not
@ -207,8 +207,7 @@ fn fuzz(
// The concolic observer observers the concolic shared memory map.
let concolic_observer = ConcolicObserver::new("concolic", concolic_shmem.as_slice_mut());
let concolic_observer_name = concolic_observer.name().to_string();
let concolic_ref = concolic_observer.reference();
// The order of the stages matter!
let mut stages = tuple_list!(
@ -217,7 +216,7 @@ fn fuzz(
TracingStage::new(
MyCommandConfigurator.into_executor(tuple_list!(concolic_observer))
),
concolic_observer_name,
concolic_ref,
),
// Use the concolic trace for z3-based solving
SimpleConcolicMutationalStage::default(),

View File

@ -77,7 +77,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -97,7 +97,7 @@ impl<'a, M: Monitor> Instance<'a, M> {
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -169,7 +169,7 @@ pub fn fuzz() {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -176,7 +176,7 @@ pub fn fuzz() {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -110,7 +110,7 @@ pub fn fuzz() {
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not

View File

@ -97,7 +97,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer),
TimeFeedback::new(&time_observer),
PacketLenFeedback::new()
);

View File

@ -1,15 +1,15 @@
//! Whole corpus minimizers, for reducing the number of samples/the total size/the average runtime
//! of your corpus.
use alloc::{
borrow::Cow,
string::{String, ToString},
vec::Vec,
};
use alloc::{borrow::Cow, string::ToString, vec::Vec};
use core::{hash::Hash, marker::PhantomData};
use hashbrown::{HashMap, HashSet};
use libafl_bolts::{current_time, tuples::MatchName, AsIter, Named};
use libafl_bolts::{
current_time,
tuples::{Reference, Referenceable},
AsIter, Named,
};
use num_traits::ToPrimitive;
use z3::{ast::Bool, Config, Context, Optimize};
@ -51,8 +51,8 @@ where
/// Algorithm based on WMOPT: <https://hexhive.epfl.ch/publications/files/21ISSTA2.pdf>
#[derive(Debug)]
pub struct MapCorpusMinimizer<C, E, O, T, TS> {
obs_name: String,
phantom: PhantomData<(C, E, O, T, TS)>,
obs_ref: Reference<C>,
phantom: PhantomData<(E, O, T, TS)>,
}
/// Standard corpus minimizer, which weights inputs by length and time.
@ -70,7 +70,7 @@ where
/// in the future to get observed maps from an executed input.
pub fn new(obs: &C) -> Self {
Self {
obs_name: obs.name().to_string(),
obs_ref: obs.reference(),
phantom: PhantomData,
}
}
@ -160,11 +160,8 @@ where
)?;
let seed_expr = Bool::fresh_const(&ctx, "seed");
let obs = executor
.observers()
.match_name::<C>(&self.obs_name)
.expect("Observer must be present.")
.as_ref();
let observers = executor.observers();
let obs = observers[&self.obs_ref].as_ref();
// Store coverage, mapping coverage map indices to hit counts (if present) and the
// associated seeds for the map indices with those hit counts.

View File

@ -10,6 +10,8 @@
use alloc::{boxed::Box, string::String, vec::Vec};
use core::{marker::PhantomData, num::NonZeroUsize, time::Duration};
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::tuples::{Reference, Referenceable};
#[cfg(feature = "llmp_compression")]
use libafl_bolts::{
compress::GzipCompressor,
@ -24,6 +26,8 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "llmp_compression")]
use crate::events::llmp::COMPRESS_THRESHOLD;
#[cfg(feature = "adaptive_serialization")]
use crate::observers::TimeObserver;
#[cfg(feature = "scalability_introspection")]
use crate::state::HasScalabilityMonitor;
use crate::{
@ -221,6 +225,8 @@ where
client: LlmpClient<SP>,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor,
#[cfg(feature = "adaptive_serialization")]
time_ref: Reference<TimeObserver>,
is_main: bool,
}
@ -263,6 +269,10 @@ where
fn should_serialize_cnt_mut(&mut self) -> &mut usize {
self.inner.should_serialize_cnt_mut()
}
fn time_ref(&self) -> &Reference<TimeObserver> {
&self.time_ref
}
}
#[cfg(not(feature = "adaptive_serialization"))]
@ -275,7 +285,7 @@ where
impl<EM, SP> EventFirer for CentralizedEventManager<EM, SP>
where
EM: AdaptiveSerializer + EventFirer + HasEventManagerId + AdaptiveSerializer,
EM: AdaptiveSerializer + EventFirer + HasEventManagerId,
SP: ShMemProvider + 'static,
{
fn fire(
@ -459,6 +469,7 @@ where
SP: ShMemProvider + 'static,
{
/// Creates a new [`CentralizedEventManager`].
#[cfg(not(feature = "adaptive_serialization"))]
pub fn new(inner: EM, client: LlmpClient<SP>, is_main: bool) -> Result<Self, Error> {
Ok(Self {
inner,
@ -469,25 +480,66 @@ where
})
}
/// Creates a new [`CentralizedEventManager`].
#[cfg(feature = "adaptive_serialization")]
pub fn new(
inner: EM,
client: LlmpClient<SP>,
is_main: bool,
time_obs: &TimeObserver,
) -> Result<Self, Error> {
Ok(Self {
inner,
client,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
time_ref: time_obs.reference(),
is_main,
})
}
/// Create a centralized event manager on a port
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn on_port(inner: EM, shmem_provider: SP, port: u16, is_main: bool) -> Result<Self, Error> {
let client = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Ok(Self {
inner,
client,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
is_main,
})
}
/// Create a centralized event manager on a port
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
#[cfg(feature = "std")]
pub fn on_port(inner: EM, shmem_provider: SP, port: u16, is_main: bool) -> Result<Self, Error> {
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn on_port(
inner: EM,
shmem_provider: SP,
port: u16,
is_main: bool,
time_obs: &TimeObserver,
) -> Result<Self, Error> {
let client = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Ok(Self {
inner,
client,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
time_ref: time_obs.reference(),
is_main,
})
}
/// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`].
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn existing_client_from_env(
inner: EM,
shmem_provider: SP,
@ -503,12 +555,28 @@ where
})
}
/// Describe the client event manager's LLMP parts in a restorable fashion
pub fn describe(&self) -> Result<LlmpClientDescription, Error> {
self.client.describe()
/// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`].
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn existing_client_from_env(
inner: EM,
shmem_provider: SP,
env_name: &str,
is_main: bool,
time_obs: &TimeObserver,
) -> Result<Self, Error> {
Ok(Self {
inner,
client: LlmpClient::on_existing_from_env(shmem_provider, env_name)?,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
time_ref: time_obs.reference(),
is_main,
})
}
/// Create an existing client from description
#[cfg(not(feature = "adaptive_serialization"))]
pub fn existing_client_from_description(
inner: EM,
shmem_provider: SP,
@ -524,6 +592,30 @@ where
})
}
/// Create an existing client from description
#[cfg(feature = "adaptive_serialization")]
pub fn existing_client_from_description(
inner: EM,
shmem_provider: SP,
description: &LlmpClientDescription,
is_main: bool,
time_obs: &TimeObserver,
) -> Result<Self, Error> {
Ok(Self {
inner,
client: LlmpClient::existing_client_from_description(shmem_provider, description)?,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
time_ref: time_obs.reference(),
is_main,
})
}
/// Describe the client event manager's LLMP parts in a restorable fashion
pub fn describe(&self) -> Result<LlmpClientDescription, Error> {
self.client.describe()
}
/// Write the config for a client [`EventManager`] to env vars, a new
/// client can reattach using [`CentralizedEventManager::existing_client_from_env()`].
#[cfg(feature = "std")]

View File

@ -30,6 +30,8 @@ use std::{fs::File, os::unix::io::AsRawFd};
#[cfg(all(feature = "std", any(windows, not(feature = "fork"))))]
use libafl_bolts::os::startable_self;
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::tuples::{Reference, Referenceable};
#[cfg(all(unix, feature = "std", feature = "fork"))]
use libafl_bolts::{
core_affinity::get_core_ids,
@ -46,6 +48,8 @@ use typed_builder::TypedBuilder;
use super::hooks::EventManagerHooksTuple;
#[cfg(all(unix, feature = "std", feature = "fork"))]
use crate::events::{CentralizedEventManager, CentralizedLlmpEventBroker};
#[cfg(feature = "adaptive_serialization")]
use crate::observers::TimeObserver;
#[cfg(feature = "std")]
use crate::{
events::{
@ -116,6 +120,8 @@ where
/// clusters.
#[builder(default = None)]
remote_broker_addr: Option<SocketAddr>,
#[cfg(feature = "adaptive_serialization")]
time_ref: Reference<TimeObserver>,
/// If this launcher should spawn a new `broker` on `[Self::broker_port]` (default).
/// The reason you may not want this is, if you already have a [`Launcher`]
/// with a different configuration (for the same target) running on this machine.
@ -250,7 +256,7 @@ where
}
// Fuzzer client. keeps retrying the connection to broker till the broker starts
let (state, mgr) = RestartingMgr::<EMH, MT, S, SP>::builder()
let builder = RestartingMgr::<EMH, MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone())
.broker_port(self.broker_port)
.kind(ManagerKind::Client {
@ -258,9 +264,10 @@ where
})
.configuration(self.configuration)
.serialize_state(self.serialize_state)
.hooks(hooks)
.build()
.launch()?;
.hooks(hooks);
#[cfg(feature = "adaptive_serialization")]
let builder = builder.time_ref(self.time_ref.clone());
let (state, mgr) = builder.build().launch()?;
return (self.run_client.take().unwrap())(state, mgr, *bind_to);
}
@ -273,7 +280,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
RestartingMgr::<EMH, MT, S, SP>::builder()
let builder = RestartingMgr::<EMH, MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone())
.monitor(Some(self.monitor.clone()))
.broker_port(self.broker_port)
@ -282,9 +289,12 @@ where
.exit_cleanly_after(Some(NonZeroUsize::try_from(self.cores.ids.len()).unwrap()))
.configuration(self.configuration)
.serialize_state(self.serialize_state)
.hooks(hooks)
.build()
.launch()?;
.hooks(hooks);
#[cfg(feature = "adaptive_serialization")]
let builder = builder.time_ref(self.time_ref.clone());
builder.build().launch()?;
// Broker exited. kill all clients.
for handle in &handles {
@ -457,6 +467,9 @@ where
/// The centralized broker port to use (or to attach to, in case [`Self::spawn_broker`] is `false`)
#[builder(default = 1338_u16)]
centralized_broker_port: u16,
/// The time observer by which to adaptively serialize
#[cfg(feature = "adaptive_serialization")]
time_obs: &'a TimeObserver,
/// The list of cores to run on
cores: &'a Cores,
/// A file name to write all client output to
@ -617,7 +630,7 @@ where
}
// Fuzzer client. keeps retrying the connection to broker till the broker starts
let (state, mgr) = RestartingMgr::<(), MT, S, SP>::builder()
let builder = RestartingMgr::<(), MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone())
.broker_port(self.broker_port)
.kind(ManagerKind::Client {
@ -625,16 +638,26 @@ where
})
.configuration(self.configuration)
.serialize_state(self.serialize_state)
.hooks(tuple_list!())
.build()
.launch()?;
.hooks(tuple_list!());
#[cfg(feature = "adaptive_serialization")]
let builder = builder.time_ref(self.time_obs.reference());
let (state, mgr) = builder.build().launch()?;
#[cfg(not(feature = "adaptive_serialization"))]
let c_mgr = CentralizedEventManager::on_port(
mgr,
self.shmem_provider.clone(),
self.centralized_broker_port,
index == 1,
)?;
#[cfg(feature = "adaptive_serialization")]
let c_mgr = CentralizedEventManager::on_port(
mgr,
self.shmem_provider.clone(),
self.centralized_broker_port,
index == 1,
self.time_obs,
)?;
return (self.run_client.take().unwrap())(state, c_mgr, *bind_to);
}
@ -646,7 +669,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
RestartingMgr::<(), MT, S, SP>::builder()
let builder = RestartingMgr::<(), MT, S, SP>::builder()
.shmem_provider(self.shmem_provider.clone())
.monitor(Some(self.monitor.clone()))
.broker_port(self.broker_port)
@ -655,9 +678,12 @@ where
.exit_cleanly_after(Some(NonZeroUsize::try_from(self.cores.ids.len()).unwrap()))
.configuration(self.configuration)
.serialize_state(self.serialize_state)
.hooks(tuple_list!())
.build()
.launch()?;
.hooks(tuple_list!());
#[cfg(feature = "adaptive_serialization")]
let builder = builder.time_ref(self.time_obs.reference());
builder.build().launch()?;
// Broker exited. kill all clients.
for handle in &handles {

View File

@ -13,8 +13,6 @@ use std::net::TcpStream;
#[cfg(feature = "std")]
use std::net::{SocketAddr, ToSocketAddrs};
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::current_time;
#[cfg(all(feature = "std", any(windows, not(feature = "fork"))))]
use libafl_bolts::os::startable_self;
#[cfg(all(unix, feature = "std", not(miri)))]
@ -32,6 +30,11 @@ use libafl_bolts::{
llmp::{recv_tcp_msg, send_tcp_msg, TcpRequest, TcpResponse},
IP_LOCALHOST,
};
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::{
current_time,
tuples::{Reference, Referenceable},
};
#[cfg(feature = "std")]
use libafl_bolts::{llmp::LlmpConnection, shmem::StdShMemProvider, staterestore::StateRestorer};
use libafl_bolts::{
@ -49,6 +52,8 @@ use super::{hooks::EventManagerHooksTuple, CustomBufEventResult, CustomBufHandle
use crate::events::AdaptiveSerializer;
#[cfg(all(unix, feature = "std"))]
use crate::events::EVENTMGR_SIGHANDLER_STATE;
#[cfg(feature = "adaptive_serialization")]
use crate::observers::TimeObserver;
use crate::{
events::{
BrokerEventResult, Event, EventConfig, EventFirer, EventManager, EventManagerId,
@ -336,7 +341,7 @@ where
}
/// An [`EventManager`] that forwards all events to other attached fuzzers on shared maps or via tcp,
/// using low-level message passing, [`libafl_bolts::llmp`].
/// using low-level message passing, [`llmp`].
pub struct LlmpEventManager<EMH, S, SP>
where
S: State,
@ -361,6 +366,8 @@ where
serializations_cnt: usize,
#[cfg(feature = "adaptive_serialization")]
should_serialize_cnt: usize,
#[cfg(feature = "adaptive_serialization")]
time_ref: Reference<TimeObserver>,
phantom: PhantomData<S>,
}
@ -395,6 +402,10 @@ where
fn should_serialize_cnt_mut(&mut self) -> &mut usize {
&mut self.should_serialize_cnt
}
fn time_ref(&self) -> &Reference<TimeObserver> {
&self.time_ref
}
}
impl<EMH, S, SP> core::fmt::Debug for LlmpEventManager<EMH, S, SP>
@ -432,6 +443,7 @@ where
SP: ShMemProvider + 'static,
{
/// Create a manager from a raw LLMP client
#[cfg(not(feature = "adaptive_serialization"))]
pub fn new(llmp: LlmpClient<SP>, configuration: EventConfig) -> Result<Self, Error> {
Ok(LlmpEventManager {
hooks: tuple_list!(),
@ -439,14 +451,6 @@ where
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration,
#[cfg(feature = "adaptive_serialization")]
serialization_time: Duration::ZERO,
#[cfg(feature = "adaptive_serialization")]
deserialization_time: Duration::ZERO,
#[cfg(feature = "adaptive_serialization")]
serializations_cnt: 0,
#[cfg(feature = "adaptive_serialization")]
should_serialize_cnt: 0,
phantom: PhantomData,
custom_buf_handlers: vec![],
})
@ -456,7 +460,7 @@ where
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn on_port(
shmem_provider: SP,
port: u16,
@ -468,7 +472,7 @@ where
/// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`].
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn existing_client_from_env(
shmem_provider: SP,
env_name: &str,
@ -479,6 +483,7 @@ where
}
/// Create an existing client from description
#[cfg(not(feature = "adaptive_serialization"))]
pub fn existing_client_from_description(
shmem_provider: SP,
description: &LlmpClientDescription,
@ -487,6 +492,69 @@ where
let llmp = LlmpClient::existing_client_from_description(shmem_provider, description)?;
Self::new(llmp, configuration)
}
/// Create a manager from a raw LLMP client
#[cfg(feature = "adaptive_serialization")]
pub fn new(
llmp: LlmpClient<SP>,
configuration: EventConfig,
time_ref: Reference<TimeObserver>,
) -> Result<Self, Error> {
Ok(LlmpEventManager {
hooks: tuple_list!(),
llmp,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration,
serialization_time: Duration::ZERO,
deserialization_time: Duration::ZERO,
serializations_cnt: 0,
should_serialize_cnt: 0,
time_ref,
phantom: PhantomData,
custom_buf_handlers: vec![],
})
}
/// Create an LLMP event manager on a port
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn on_port(
shmem_provider: SP,
port: u16,
configuration: EventConfig,
time_ref: Reference<TimeObserver>,
) -> Result<LlmpEventManager<(), S, SP>, Error> {
let llmp = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Self::new(llmp, configuration, time_ref)
}
/// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`].
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn existing_client_from_env(
shmem_provider: SP,
env_name: &str,
configuration: EventConfig,
time_ref: Reference<TimeObserver>,
) -> Result<LlmpEventManager<(), S, SP>, Error> {
let llmp = LlmpClient::on_existing_from_env(shmem_provider, env_name)?;
Self::new(llmp, configuration, time_ref)
}
/// Create an existing client from description
#[cfg(feature = "adaptive_serialization")]
pub fn existing_client_from_description(
shmem_provider: SP,
description: &LlmpClientDescription,
configuration: EventConfig,
time_ref: Reference<TimeObserver>,
) -> Result<LlmpEventManager<(), S, SP>, Error> {
let llmp = LlmpClient::existing_client_from_description(shmem_provider, description)?;
Self::new(llmp, configuration, time_ref)
}
}
impl<EMH, S, SP> LlmpEventManager<EMH, S, SP>
@ -494,6 +562,135 @@ where
S: State,
SP: ShMemProvider + 'static,
{
/// Create a manager from a raw LLMP client with hooks
#[cfg(not(feature = "adaptive_serialization"))]
pub fn with_hooks(
llmp: LlmpClient<SP>,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
Ok(Self {
hooks,
llmp,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration,
phantom: PhantomData,
custom_buf_handlers: vec![],
})
}
/// Create an LLMP event manager on a port with hook
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
/// This will make a new connection to the broker so will return its new [`ClientId`], too
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn on_port_with_hooks(
shmem_provider: SP,
port: u16,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`].
/// create a event manager from env with hooks
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
pub fn existing_client_from_env_with_hooks(
shmem_provider: SP,
env_name: &str,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::on_existing_from_env(shmem_provider, env_name)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// Create an existing client from description
#[cfg(not(feature = "adaptive_serialization"))]
pub fn existing_client_from_description_with_hooks(
shmem_provider: SP,
description: &LlmpClientDescription,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::existing_client_from_description(shmem_provider, description)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// Create a manager from a raw LLMP client with hooks
#[cfg(feature = "adaptive_serialization")]
pub fn with_hooks(
llmp: LlmpClient<SP>,
configuration: EventConfig,
hooks: EMH,
time_ref: Reference<TimeObserver>,
) -> Result<Self, Error> {
Ok(Self {
hooks,
llmp,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration,
serialization_time: Duration::ZERO,
deserialization_time: Duration::ZERO,
serializations_cnt: 0,
should_serialize_cnt: 0,
time_ref,
phantom: PhantomData,
custom_buf_handlers: vec![],
})
}
/// Create an LLMP event manager on a port with hook
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
/// This will make a new connection to the broker so will return its new [`ClientId`], too
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn on_port_with_hooks(
shmem_provider: SP,
port: u16,
configuration: EventConfig,
hooks: EMH,
time_ref: Reference<TimeObserver>,
) -> Result<Self, Error> {
let llmp = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Self::with_hooks(llmp, configuration, hooks, time_ref)
}
/// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`].
/// create a event manager from env with hooks
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
pub fn existing_client_from_env_with_hooks(
shmem_provider: SP,
env_name: &str,
configuration: EventConfig,
hooks: EMH,
time_ref: Reference<TimeObserver>,
) -> Result<Self, Error> {
let llmp = LlmpClient::on_existing_from_env(shmem_provider, env_name)?;
Self::with_hooks(llmp, configuration, hooks, time_ref)
}
/// Create an existing client from description
#[cfg(feature = "adaptive_serialization")]
pub fn existing_client_from_description_with_hooks(
shmem_provider: SP,
description: &LlmpClientDescription,
configuration: EventConfig,
hooks: EMH,
time_ref: Reference<TimeObserver>,
) -> Result<Self, Error> {
let llmp = LlmpClient::existing_client_from_description(shmem_provider, description)?;
Self::with_hooks(llmp, configuration, hooks, time_ref)
}
/// Calling this function will tell the llmp broker that this client is exiting
/// This should be called from the restarter not from the actual fuzzer client
/// This function serves the same roll as the `LlmpClient.send_exiting()`
@ -526,77 +723,12 @@ where
log::info!("Asking he broker to be disconnected");
Ok(())
}
/// Create a manager from a raw LLMP client with hooks
pub fn with_hooks(
llmp: LlmpClient<SP>,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
Ok(Self {
hooks,
llmp,
#[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration,
#[cfg(feature = "adaptive_serialization")]
serialization_time: Duration::ZERO,
#[cfg(feature = "adaptive_serialization")]
deserialization_time: Duration::ZERO,
#[cfg(feature = "adaptive_serialization")]
serializations_cnt: 0,
#[cfg(feature = "adaptive_serialization")]
should_serialize_cnt: 0,
phantom: PhantomData,
custom_buf_handlers: vec![],
})
}
/// Create an LLMP event manager on a port with hook
///
/// If the port is not yet bound, it will act as a broker; otherwise, it
/// will act as a client.
/// This will make a new connection to the broker so will return its new [`ClientId`], too
#[cfg(feature = "std")]
pub fn on_port_with_hooks(
shmem_provider: SP,
port: u16,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::create_attach_to_tcp(shmem_provider, port)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// If a client respawns, it may reuse the existing connection, previously
/// stored by [`LlmpClient::to_env()`].
/// create a event manager from env with hooks
#[cfg(feature = "std")]
pub fn existing_client_from_env_with_hooks(
shmem_provider: SP,
env_name: &str,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::on_existing_from_env(shmem_provider, env_name)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// Describe the client event manager's LLMP parts in a restorable fashion
pub fn describe(&self) -> Result<LlmpClientDescription, Error> {
self.llmp.describe()
}
/// Create an existing client from description
pub fn existing_client_from_description_with_hooks(
shmem_provider: SP,
description: &LlmpClientDescription,
configuration: EventConfig,
hooks: EMH,
) -> Result<Self, Error> {
let llmp = LlmpClient::existing_client_from_description(shmem_provider, description)?;
Self::with_hooks(llmp, configuration, hooks)
}
/// Write the config for a client [`EventManager`] to env vars, a new
/// client can reattach using [`LlmpEventManager::existing_client_from_env()`].
#[cfg(feature = "std")]
@ -958,6 +1090,10 @@ where
fn should_serialize_cnt_mut(&mut self) -> &mut usize {
self.llmp_mgr.should_serialize_cnt_mut()
}
fn time_ref(&self) -> &Reference<TimeObserver> {
&self.llmp_mgr.time_ref
}
}
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
@ -1172,7 +1308,7 @@ pub enum ManagerKind {
/// Sets up a restarting fuzzer, using the [`StdShMemProvider`], and standard features.
/// 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.
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(feature = "adaptive_serialization")))]
#[allow(clippy::type_complexity)]
pub fn setup_restarting_mgr_std<MT, S>(
monitor: MT,
@ -1199,6 +1335,38 @@ where
.launch()
}
/// Sets up a restarting fuzzer, using the [`StdShMemProvider`], and standard features.
/// 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.
#[cfg(all(feature = "std", feature = "adaptive_serialization"))]
#[allow(clippy::type_complexity)]
pub fn setup_restarting_mgr_std<MT, S>(
monitor: MT,
broker_port: u16,
configuration: EventConfig,
time_obs: &TimeObserver,
) -> Result<
(
Option<S>,
LlmpRestartingEventManager<(), S, StdShMemProvider>,
),
Error,
>
where
MT: Monitor + Clone,
S: State + HasExecutions,
{
RestartingMgr::builder()
.shmem_provider(StdShMemProvider::new()?)
.monitor(Some(monitor))
.broker_port(broker_port)
.configuration(configuration)
.hooks(tuple_list!())
.time_ref(time_obs.reference())
.build()
.launch()
}
/// Provides a `builder` which can be used to build a [`RestartingMgr`], which is a combination of a
/// `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.
@ -1243,6 +1411,8 @@ where
serialize_state: LlmpShouldSaveState,
/// The hooks passed to event manager:
hooks: EMH,
#[cfg(feature = "adaptive_serialization")]
time_ref: Reference<TimeObserver>,
#[builder(setter(skip), default = PhantomData)]
phantom_data: PhantomData<(EMH, S)>,
}
@ -1310,11 +1480,19 @@ where
return Err(Error::shutting_down());
}
LlmpConnection::IsClient { client } => {
#[cfg(not(feature = "adaptive_serialization"))]
let mgr = LlmpEventManager::<EMH, S, SP>::with_hooks(
client,
self.configuration,
self.hooks,
)?;
#[cfg(feature = "adaptive_serialization")]
let mgr = LlmpEventManager::<EMH, S, SP>::with_hooks(
client,
self.configuration,
self.hooks,
self.time_ref.clone(),
)?;
(mgr, None)
}
}
@ -1331,12 +1509,21 @@ where
}
ManagerKind::Client { cpu_core } => {
// We are a client
#[cfg(not(feature = "adaptive_serialization"))]
let mgr = LlmpEventManager::<EMH, S, SP>::on_port_with_hooks(
self.shmem_provider.clone(),
self.broker_port,
self.configuration,
self.hooks,
)?;
#[cfg(feature = "adaptive_serialization")]
let mgr = LlmpEventManager::<EMH, S, SP>::on_port_with_hooks(
self.shmem_provider.clone(),
self.broker_port,
self.configuration,
self.hooks,
self.time_ref.clone(),
)?;
(mgr, cpu_core)
}
@ -1449,15 +1636,25 @@ where
// If we're restarting, deserialize the old state.
let (state, mut mgr) =
if let Some((state_opt, mgr_description)) = staterestorer.restore()? {
#[cfg(not(feature = "adaptive_serialization"))]
let llmp_mgr = LlmpEventManager::existing_client_from_description_with_hooks(
new_shmem_provider,
&mgr_description,
self.configuration,
self.hooks,
)?;
#[cfg(feature = "adaptive_serialization")]
let llmp_mgr = LlmpEventManager::existing_client_from_description_with_hooks(
new_shmem_provider,
&mgr_description,
self.configuration,
self.hooks,
self.time_ref.clone(),
)?;
(
state_opt,
LlmpRestartingEventManager::with_save_state(
LlmpEventManager::existing_client_from_description_with_hooks(
new_shmem_provider,
&mgr_description,
self.configuration,
self.hooks,
)?,
llmp_mgr,
staterestorer,
self.serialize_state,
),
@ -1465,12 +1662,21 @@ where
} else {
log::info!("First run. Let's set it all up");
// Mgr to send and receive msgs from/to all other fuzzer instances
#[cfg(not(feature = "adaptive_serialization"))]
let mgr = LlmpEventManager::<EMH, S, SP>::existing_client_from_env_with_hooks(
new_shmem_provider,
_ENV_FUZZER_BROKER_CLIENT_INITIAL,
self.configuration,
self.hooks,
)?;
#[cfg(feature = "adaptive_serialization")]
let mgr = LlmpEventManager::<EMH, S, SP>::existing_client_from_env_with_hooks(
new_shmem_provider,
_ENV_FUZZER_BROKER_CLIENT_INITIAL,
self.configuration,
self.hooks,
self.time_ref.clone(),
)?;
(
None,
@ -1854,6 +2060,8 @@ where
mod tests {
use core::sync::atomic::{compiler_fence, Ordering};
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::tuples::Referenceable;
use libafl_bolts::{
llmp::{LlmpClient, LlmpSharedMap},
rands::StdRand,
@ -1872,6 +2080,7 @@ mod tests {
fuzzer::Fuzzer,
inputs::BytesInput,
mutators::BitFlipMutator,
observers::TimeObserver,
schedulers::RandScheduler,
stages::StdMutationalStage,
state::StdState,
@ -1884,6 +2093,10 @@ mod tests {
fn test_mgr_state_restore() {
let rand = StdRand::with_seed(0);
let time = TimeObserver::new("time");
#[cfg(feature = "adaptive_serialization")]
let time_ref = time.reference();
let mut corpus = InMemoryCorpus::<BytesInput>::new();
let testcase = Testcase::new(vec![0; 4].into());
corpus.add(testcase).unwrap();
@ -1910,7 +2123,11 @@ mod tests {
llmp_client.mark_safe_to_unmap();
}
#[cfg(not(feature = "adaptive_serialization"))]
let mut llmp_mgr = LlmpEventManager::new(llmp_client, "fuzzer".into()).unwrap();
#[cfg(feature = "adaptive_serialization")]
let mut llmp_mgr =
LlmpEventManager::new(llmp_client, "fuzzer".into(), time_ref.clone()).unwrap();
let scheduler = RandScheduler::new();
@ -1922,7 +2139,7 @@ mod tests {
let mut harness = |_buf: &BytesInput| ExitKind::Ok;
let mut executor = InProcessExecutor::new(
&mut harness,
tuple_list!(),
tuple_list!(time),
&mut fuzzer,
&mut state,
&mut llmp_mgr,
@ -1952,22 +2169,29 @@ mod tests {
assert!(sc_cpy.has_content());
let (mut state_clone, mgr_description) = staterestorer.restore().unwrap().unwrap();
#[cfg(not(feature = "adaptive_serialization"))]
let mut llmp_clone = LlmpEventManager::existing_client_from_description(
shmem_provider,
&mgr_description,
"fuzzer".into(),
)
.unwrap();
#[cfg(feature = "adaptive_serialization")]
let mut llmp_clone = LlmpEventManager::existing_client_from_description(
shmem_provider,
&mgr_description,
"fuzzer".into(),
time_ref,
)
.unwrap();
if false {
fuzzer
.fuzz_one(
&mut stages,
&mut executor,
&mut state_clone,
&mut llmp_clone,
)
.unwrap();
}
fuzzer
.fuzz_one(
&mut stages,
&mut executor,
&mut state_clone,
&mut llmp_clone,
)
.unwrap();
}
}

View File

@ -32,6 +32,8 @@ use ahash::RandomState;
pub use launcher::*;
#[cfg(all(unix, feature = "std"))]
use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Handler, Signal};
#[cfg(feature = "adaptive_serialization")]
use libafl_bolts::tuples::{MatchNameRef, Reference};
use libafl_bolts::{current_time, ClientId};
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
@ -119,7 +121,7 @@ impl Handler for ShutdownSignalData {
}
/// A per-fuzzer unique `ID`, usually starting with `0` and increasing
/// by `1` in multiprocessed [`EventManager`]s, such as [`self::llmp::LlmpEventManager`].
/// by `1` in multiprocessed [`EventManager`]s, such as [`LlmpEventManager`].
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct EventManagerId(
@ -129,6 +131,8 @@ pub struct EventManagerId(
#[cfg(feature = "introspection")]
use crate::monitors::ClientPerfMonitor;
#[cfg(feature = "adaptive_serialization")]
use crate::observers::TimeObserver;
use crate::{inputs::UsesInput, stages::HasCurrentStage, state::UsesState};
/// The log event severity
@ -415,7 +419,7 @@ where
pub trait EventFirer: UsesState {
/// Send off an [`Event`] to the broker
///
/// For multi-processed managers, such as [`llmp::LlmpEventManager`],
/// For multi-processed managers, such as [`LlmpEventManager`],
/// this serializes the [`Event`] and commits it to the [`llmp`] page.
/// In this case, if you `fire` faster than the broker can consume
/// (for example for each [`Input`], on multiple cores)
@ -466,7 +470,7 @@ where
{
/// Given the last time, if `monitor_timeout` seconds passed, send off an info/monitor/heartbeat message to the broker.
/// Returns the new `last` time (so the old one, unless `monitor_timeout` time has passed and monitor have been sent)
/// Will return an [`crate::Error`], if the stats could not be sent.
/// Will return an [`Error`], if the stats could not be sent.
fn maybe_report_progress(
&mut self,
state: &mut Self::State,
@ -487,7 +491,7 @@ where
}
/// Send off an info/monitor/heartbeat message to the broker.
/// Will return an [`crate::Error`], if the stats could not be sent.
/// Will return an [`Error`], if the stats could not be sent.
fn report_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
let executions = *state.executions();
let cur = current_time();
@ -875,6 +879,9 @@ pub trait AdaptiveSerializer {
/// How many times shoukd have been serialized an observer (mut)
fn should_serialize_cnt_mut(&mut self) -> &mut usize;
/// A [`Reference`] to the time observer to determine the `time_factor`
fn time_ref(&self) -> &Reference<TimeObserver>;
/// Serialize the observer using the `time_factor` and `percentage_threshold`.
/// These parameters are unique to each of the different types of `EventManager`
fn serialize_observers_adaptive<S, OT>(
@ -888,7 +895,7 @@ pub trait AdaptiveSerializer {
S: UsesInput,
{
let exec_time = observers
.match_name::<crate::observers::TimeObserver>("time")
.get(self.time_ref())
.map(|o| o.last_runtime().unwrap_or(Duration::ZERO))
.unwrap();

View File

@ -3,6 +3,8 @@
use core::fmt::Debug;
use libafl_bolts::tuples::RefIndexable;
use crate::{
executors::{Executor, ExitKind, HasObservers},
observers::UsesObservers,
@ -80,12 +82,12 @@ where
A: HasObservers,
{
#[inline]
fn observers(&self) -> &Self::Observers {
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.primary.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut Self::Observers {
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.primary.observers_mut()
}
}

View File

@ -18,7 +18,7 @@ use std::{
use libafl_bolts::{
fs::{get_unique_std_input_file, InputFile},
tuples::MatchName,
tuples::{MatchName, RefIndexable},
AsSlice,
};
@ -397,12 +397,12 @@ where
T: Debug,
OT: ObserversTuple<S>,
{
fn observers(&self) -> &OT {
&self.observers
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
RefIndexable::from(&self.observers)
}
fn observers_mut(&mut self) -> &mut OT {
&mut self.observers
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
RefIndexable::from(&mut self.observers)
}
}

View File

@ -4,7 +4,10 @@
//!
use core::{cell::UnsafeCell, fmt::Debug, ptr};
use libafl_bolts::{ownedref::OwnedMutPtr, tuples::MatchName};
use libafl_bolts::{
ownedref::OwnedMutPtr,
tuples::{MatchName, RefIndexable},
};
use serde::{Deserialize, Serialize};
use crate::{
@ -183,6 +186,7 @@ where
B: MatchName,
DOT: MatchName,
{
#[allow(deprecated)]
fn match_name<T>(&self, name: &str) -> Option<&T> {
if let Some(t) = self.primary.as_ref().match_name::<T>(name) {
Some(t)
@ -192,6 +196,8 @@ where
self.differential.match_name::<T>(name)
}
}
#[allow(deprecated)]
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T> {
if let Some(t) = self.primary.as_mut().match_name_mut::<T>(name) {
Some(t)
@ -238,26 +244,25 @@ where
DOT: DifferentialObserversTuple<OTA, OTB, A::State>,
{
#[inline]
fn observers(&self) -> &ProxyObserversTuple<OTA, OTB, DOT> {
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
unsafe {
self.observers
.get()
.as_mut()
.unwrap()
.set(self.primary.observers(), self.secondary.observers());
self.observers.get().as_ref().unwrap()
.set(&*self.primary.observers(), &*self.secondary.observers());
RefIndexable::from(self.observers.get().as_ref().unwrap())
}
}
#[inline]
fn observers_mut(&mut self) -> &mut ProxyObserversTuple<OTA, OTB, DOT> {
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
unsafe {
self.observers
.get()
.as_mut()
.unwrap()
.set(self.primary.observers(), self.secondary.observers());
self.observers.get().as_mut().unwrap()
self.observers.get().as_mut().unwrap().set(
&*self.primary.observers_mut(),
&*self.secondary.observers_mut(),
);
RefIndexable::from(self.observers.get().as_mut().unwrap())
}
}
}

View File

@ -22,7 +22,7 @@ use libafl_bolts::{
fs::{get_unique_std_input_file, InputFile},
os::{dup2, pipes::Pipe},
shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::Prepend,
tuples::{MatchNameRef, Prepend, RefIndexable, Reference, Referenceable},
AsSlice, AsSliceMut, Truncate,
};
use nix::{
@ -497,6 +497,8 @@ where
map: Option<SP::ShMem>,
phantom: PhantomData<S>,
map_size: Option<usize>,
#[cfg(feature = "regex")]
asan_obs: Reference<AsanBacktraceObserver>,
timeout: TimeSpec,
crash_exitcode: Option<i8>,
}
@ -584,6 +586,8 @@ pub struct ForkserverExecutorBuilder<'a, SP> {
real_map_size: i32,
kill_signal: Option<Signal>,
timeout: Option<Duration>,
#[cfg(feature = "regex")]
asan_obs: Option<Reference<AsanBacktraceObserver>>,
crash_exitcode: Option<i8>,
}
@ -633,6 +637,10 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
phantom: PhantomData,
map_size: self.map_size,
timeout,
asan_obs: self
.asan_obs
.clone()
.unwrap_or(AsanBacktraceObserver::default().reference()),
crash_exitcode: self.crash_exitcode,
})
}
@ -691,6 +699,10 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
phantom: PhantomData,
map_size: self.map_size,
timeout,
asan_obs: self
.asan_obs
.clone()
.unwrap_or(AsanBacktraceObserver::default().reference()),
crash_exitcode: self.crash_exitcode,
})
}
@ -1058,6 +1070,7 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
max_input_size: MAX_INPUT_SIZE_DEFAULT,
kill_signal: None,
timeout: None,
asan_obs: None,
crash_exitcode: None,
}
}
@ -1084,6 +1097,7 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
max_input_size: MAX_INPUT_SIZE_DEFAULT,
kill_signal: None,
timeout: None,
asan_obs: None,
crash_exitcode: None,
}
}
@ -1178,10 +1192,7 @@ where
if libc::WIFSIGNALED(self.forkserver().status()) || exitcode_is_crash {
exit_kind = ExitKind::Crash;
#[cfg(feature = "regex")]
if let Some(asan_observer) = self
.observers_mut()
.match_name_mut::<AsanBacktraceObserver>("AsanBacktraceObserver")
{
if let Some(asan_observer) = self.observers.get_mut(&self.asan_obs) {
asan_observer.parse_asan_output_from_asan_log_file(pid)?;
}
}
@ -1229,13 +1240,13 @@ where
SP: ShMemProvider,
{
#[inline]
fn observers(&self) -> &OT {
&self.observers
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
RefIndexable::from(&self.observers)
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
&mut self.observers
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
RefIndexable::from(&mut self.observers)
}
}

View File

@ -7,7 +7,7 @@ use core::{
time::Duration,
};
use libafl_bolts::tuples::{tuple_list, Merge};
use libafl_bolts::tuples::{tuple_list, Merge, RefIndexable};
#[cfg(windows)]
use windows::Win32::System::Threading::SetThreadStackGuarantee;
@ -85,13 +85,13 @@ where
S: State,
{
#[inline]
fn observers(&self) -> &OT {
&self.observers
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
RefIndexable::from(&self.observers)
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
&mut self.observers
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
RefIndexable::from(&mut self.observers)
}
}

View File

@ -16,7 +16,7 @@ use core::{
time::Duration,
};
use libafl_bolts::tuples::tuple_list;
use libafl_bolts::tuples::{tuple_list, RefIndexable};
#[cfg(any(unix, feature = "std"))]
use crate::executors::hooks::inprocess::GLOBAL_STATE;
@ -151,12 +151,12 @@ where
S: State,
{
#[inline]
fn observers(&self) -> &OT {
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut()
}
}
@ -438,7 +438,7 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
E::State: HasExecutions + HasSolutions + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>,
{
let observers = executor.observers_mut();
let mut observers = executor.observers_mut();
observers
.post_exec_all(state, input, &exitkind)
@ -446,7 +446,7 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
let interesting = fuzzer
.objective_mut()
.is_interesting(state, event_mgr, input, observers, &exitkind)
.is_interesting(state, event_mgr, input, &*observers, &exitkind)
.expect("In run_observers_and_save_state objective failure.");
if interesting {
@ -456,7 +456,7 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
new_testcase.set_parent_id_optional(*state.corpus().current());
fuzzer
.objective_mut()
.append_metadata(state, event_mgr, observers, &mut new_testcase)
.append_metadata(state, event_mgr, &*observers, &mut new_testcase)
.expect("Failed adding metadata");
state
.solutions_mut()

View File

@ -8,7 +8,7 @@ use core::{
time::Duration,
};
use libafl_bolts::tuples::tuple_list;
use libafl_bolts::tuples::{tuple_list, RefIndexable};
use crate::{
events::{EventFirer, EventRestarter},
@ -142,12 +142,12 @@ where
S: State,
{
#[inline]
fn observers(&self) -> &OT {
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut()
}
}

View File

@ -10,7 +10,7 @@ use core::{
use libafl_bolts::{
os::unix_signals::Signal,
shmem::ShMemProvider,
tuples::{tuple_list, Merge},
tuples::{tuple_list, Merge, RefIndexable},
};
use nix::{
sys::wait::{waitpid, WaitStatus},
@ -339,12 +339,12 @@ where
Z: UsesState<State = S>,
{
#[inline]
fn observers(&self) -> &OT {
&self.observers
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
RefIndexable::from(&self.observers)
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
&mut self.observers
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
RefIndexable::from(&mut self.observers)
}
}

View File

@ -7,7 +7,7 @@ use core::{
use libafl_bolts::{
os::unix_signals::{ucontext_t, Signal},
shmem::ShMemProvider,
tuples::tuple_list,
tuples::{tuple_list, RefIndexable},
};
use libc::siginfo_t;
use nix::unistd::{fork, ForkResult};
@ -255,12 +255,12 @@ where
Z: UsesState<State = S>,
{
#[inline]
fn observers(&self) -> &OT {
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut()
}
}
@ -295,7 +295,7 @@ pub mod child_signal_handlers {
let data = addr_of_mut!(FORK_EXECUTOR_GLOBAL_DATA);
if !data.is_null() && (*data).is_valid() {
let executor = (*data).executor_mut::<E>();
let observers = executor.observers_mut();
let mut observers = executor.observers_mut();
let state = (*data).state_mut::<E::State>();
// Invalidate data to not execute again the observer hooks in the crash handler
let input = (*data).take_current_input::<<E::State as UsesInput>::Input>();
@ -326,7 +326,7 @@ pub mod child_signal_handlers {
{
if data.is_valid() {
let executor = data.executor_mut::<E>();
let observers = executor.observers_mut();
let mut observers = executor.observers_mut();
let state = data.state_mut::<E::State>();
let input = data.take_current_input::<<E::State as UsesInput>::Input>();
observers
@ -349,7 +349,7 @@ pub mod child_signal_handlers {
{
if data.is_valid() {
let executor = data.executor_mut::<E>();
let observers = executor.observers_mut();
let mut observers = executor.observers_mut();
let state = data.state_mut::<E::State>();
let input = data.take_current_input::<<E::State as UsesInput>::Input>();
observers

View File

@ -5,7 +5,10 @@ use core::{
time::Duration,
};
use libafl_bolts::{shmem::ShMemProvider, tuples::tuple_list};
use libafl_bolts::{
shmem::ShMemProvider,
tuples::{tuple_list, RefIndexable},
};
use nix::unistd::{fork, ForkResult};
use super::super::hooks::ExecutorHooksTuple;
@ -245,12 +248,12 @@ where
Z: UsesState<State = S>,
{
#[inline]
fn observers(&self) -> &OT {
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut()
}
}

View File

@ -15,6 +15,7 @@ pub use inprocess::InProcessExecutor;
pub use inprocess_fork::InProcessForkExecutor;
#[cfg(unix)]
use libafl_bolts::os::unix_signals::Signal;
use libafl_bolts::tuples::RefIndexable;
use serde::{Deserialize, Serialize};
pub use shadow::ShadowExecutor;
pub use with_observers::WithObservers;
@ -110,10 +111,10 @@ libafl_bolts::impl_serdeany!(DiffExitKind);
/// Holds a tuple of Observers
pub trait HasObservers: UsesObservers {
/// Get the linked observers
fn observers(&self) -> &Self::Observers;
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers>;
/// Get the linked observers (mutable)
fn observers_mut(&mut self) -> &mut Self::Observers;
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers>;
}
/// An executor takes the given inputs, and runs the harness/target.

View File

@ -2,6 +2,8 @@
use core::fmt::{self, Debug, Formatter};
use libafl_bolts::tuples::RefIndexable;
use crate::{
executors::{Executor, ExitKind, HasObservers},
observers::{ObserversTuple, UsesObservers},
@ -45,14 +47,14 @@ where
/// The shadow observers are not considered by the feedbacks and the manager, mutable
#[inline]
pub fn shadow_observers(&self) -> &SOT {
&self.shadow_observers
pub fn shadow_observers(&self) -> RefIndexable<&SOT, SOT> {
RefIndexable::from(&self.shadow_observers)
}
/// The shadow observers are not considered by the feedbacks and the manager, mutable
#[inline]
pub fn shadow_observers_mut(&mut self) -> &mut SOT {
&mut self.shadow_observers
pub fn shadow_observers_mut(&mut self) -> RefIndexable<&mut SOT, SOT> {
RefIndexable::from(&mut self.shadow_observers)
}
}
@ -94,12 +96,12 @@ where
SOT: ObserversTuple<E::State>,
{
#[inline]
fn observers(&self) -> &Self::Observers {
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.executor.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut Self::Observers {
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.executor.observers_mut()
}
}

View File

@ -2,6 +2,8 @@
use core::fmt::Debug;
use libafl_bolts::tuples::RefIndexable;
use crate::{
executors::{Executor, ExitKind, HasObservers},
observers::{ObserversTuple, UsesObservers},
@ -53,12 +55,12 @@ where
E: UsesState,
OT: ObserversTuple<E::State>,
{
fn observers(&self) -> &OT {
&self.observers
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
RefIndexable::from(&self.observers)
}
fn observers_mut(&mut self) -> &mut OT {
&mut self.observers
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
RefIndexable::from(&mut self.observers)
}
}

View File

@ -6,7 +6,10 @@
use alloc::borrow::Cow;
use core::{fmt::Debug, marker::PhantomData};
use libafl_bolts::Named;
use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
Named,
};
use crate::{
corpus::Testcase,
@ -24,30 +27,30 @@ use crate::{
/// to be not interesting.
/// Requires a [`ConcolicObserver`] to observe the concolic trace.
#[derive(Debug)]
pub struct ConcolicFeedback<S> {
name: Cow<'static, str>,
pub struct ConcolicFeedback<'map, S> {
obs_ref: Reference<ConcolicObserver<'map>>,
phantom: PhantomData<S>,
}
impl<S> ConcolicFeedback<S> {
impl<'map, S> ConcolicFeedback<'map, S> {
/// Creates a concolic feedback from an observer
#[allow(unused)]
#[must_use]
pub fn from_observer(observer: &ConcolicObserver) -> Self {
pub fn from_observer(observer: &ConcolicObserver<'map>) -> Self {
Self {
name: observer.name().clone(),
obs_ref: observer.reference(),
phantom: PhantomData,
}
}
}
impl<S> Named for ConcolicFeedback<S> {
impl<S> Named for ConcolicFeedback<'_, S> {
fn name(&self) -> &Cow<'static, str> {
&self.name
self.obs_ref.name()
}
}
impl<S> Feedback<S> for ConcolicFeedback<S>
impl<S> Feedback<S> for ConcolicFeedback<'_, S>
where
S: State,
{
@ -79,7 +82,7 @@ where
EM: EventFirer<State = S>,
{
if let Some(metadata) = observers
.match_name::<ConcolicObserver>(&self.name)
.get(&self.obs_ref)
.map(ConcolicObserver::create_metadata_from_current_map)
{
testcase.metadata_map_mut().insert(metadata);

View File

@ -7,7 +7,10 @@ use core::{
marker::PhantomData,
};
use libafl_bolts::{tuples::MatchName, Named};
use libafl_bolts::{
tuples::{MatchName, MatchNameRef, Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize};
use crate::{
@ -55,12 +58,12 @@ where
/// This feedback's name
name: Cow<'static, str>,
/// The first observer to compare against
o1_name: Cow<'static, str>,
o1_ref: Reference<O1>,
/// The second observer to compare against
o2_name: Cow<'static, str>,
o2_ref: Reference<O2>,
/// The function used to compare the two observers
compare_fn: F,
phantomm: PhantomData<(O1, O2, I, S)>,
phantomm: PhantomData<(I, S)>,
}
impl<F, I, O1, O2, S> DiffFeedback<F, I, O1, O2, S>
@ -71,16 +74,17 @@ where
{
/// Create a new [`DiffFeedback`] using two observers and a test function.
pub fn new(name: &'static str, o1: &O1, o2: &O2, compare_fn: F) -> Result<Self, Error> {
let o1_name = o1.name().clone();
let o2_name = o2.name().clone();
if o1_name == o2_name {
let o1_ref = o1.reference();
let o2_ref = o2.reference();
if o1_ref.name() == o2_ref.name() {
Err(Error::illegal_argument(format!(
"DiffFeedback: observer names must be different (both were {o1_name})"
"DiffFeedback: observer names must be different (both were {})",
o1_ref.name()
)))
} else {
Ok(Self {
o1_name,
o2_name,
o1_ref,
o2_ref,
name: Cow::from(name),
compare_fn,
phantomm: PhantomData,
@ -101,8 +105,8 @@ where
fn create_feedback(&self, _ctx: &T) -> DiffFeedback<F, I, O1, O2, S> {
Self {
name: self.name.clone(),
o1_name: self.o1_name.clone(),
o2_name: self.o2_name.clone(),
o1_ref: self.o1_ref.clone(),
o2_ref: self.o2_ref.clone(),
compare_fn: self.compare_fn.clone(),
phantomm: self.phantomm,
}
@ -127,11 +131,11 @@ where
O2: Named,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"DiffFeedback {{ name: {}, o1: {}, o2: {} }}",
self.name, self.o1_name, self.o2_name
)
f.debug_struct("DiffFeedback")
.field("name", self.name())
.field("o1", &self.o1_ref)
.field("o2", &self.o2_ref)
.finish_non_exhaustive()
}
}
@ -160,11 +164,11 @@ where
Error::illegal_argument(format!("DiffFeedback: observer {name} not found"))
}
let o1: &O1 = observers
.match_name(&self.o1_name)
.ok_or_else(|| err(&self.o1_name))?;
.get(&self.o1_ref)
.ok_or_else(|| err(self.o1_ref.name()))?;
let o2: &O2 = observers
.match_name(&self.o2_name)
.ok_or_else(|| err(&self.o2_name))?;
.get(&self.o2_ref)
.ok_or_else(|| err(self.o2_ref.name()))?;
Ok((self.compare_fn)(o1, o2) == DiffResult::Diff)
}

View File

@ -1,8 +1,11 @@
use alloc::borrow::Cow;
use core::{fmt::Debug, hash::Hash, marker::PhantomData};
use core::{fmt::Debug, hash::Hash};
use hashbrown::HashSet;
use libafl_bolts::{Error, HasRefCnt, Named};
use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
Error, HasRefCnt, Named,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{
@ -70,10 +73,8 @@ pub struct ListFeedback<T>
where
T: Hash + Eq,
{
name: Cow<'static, str>,
observer_name: Cow<'static, str>,
obs_ref: Reference<ListObserver<T>>,
novelty: HashSet<T>,
phantom: PhantomData<T>,
}
libafl_bolts::impl_serdeany!(
@ -88,7 +89,7 @@ where
{
fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
// eprintln!("self.name {:#?}", &self.name);
state.add_named_metadata(&self.name, ListFeedbackMetadata::<T>::default());
state.add_named_metadata(self.name(), ListFeedbackMetadata::<T>::default());
Ok(())
}
#[allow(clippy::wrong_self_convention)]
@ -105,15 +106,13 @@ where
OT: ObserversTuple<S>,
{
// TODO Replace with match_name_type when stable
let observer = observers
.match_name::<ListObserver<T>>(&self.observer_name)
.unwrap();
let observer = observers.get(&self.obs_ref).unwrap();
// TODO register the list content in a testcase metadata
self.novelty.clear();
// can't fail
let history_set = state
.named_metadata_map_mut()
.get_mut::<ListFeedbackMetadata<T>>(&self.name)
.get_mut::<ListFeedbackMetadata<T>>(self.name())
.unwrap();
for v in observer.list() {
if !history_set.set.contains(v) {
@ -136,7 +135,7 @@ where
{
let history_set = state
.named_metadata_map_mut()
.get_mut::<ListFeedbackMetadata<T>>(&self.name)
.get_mut::<ListFeedbackMetadata<T>>(self.name())
.unwrap();
for v in &self.novelty {
@ -152,7 +151,7 @@ where
{
#[inline]
fn name(&self) -> &Cow<'static, str> {
&self.name
self.obs_ref.name()
}
}
@ -164,10 +163,8 @@ where
#[must_use]
pub fn new(observer: &ListObserver<T>) -> Self {
Self {
name: observer.name().clone(),
observer_name: observer.name().clone(),
obs_ref: observer.reference(),
novelty: HashSet::<T>::new(),
phantom: PhantomData,
}
}
}

View File

@ -9,7 +9,10 @@ use core::{
ops::{BitAnd, BitOr},
};
use libafl_bolts::{AsIter, AsSlice, AsSliceMut, HasRefCnt, Named};
use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
AsIter, AsSlice, AsSliceMut, HasRefCnt, Named,
};
use num_traits::PrimInt;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
@ -17,32 +20,31 @@ use crate::{
corpus::Testcase,
events::{Event, EventFirer},
executors::ExitKind,
feedbacks::{Feedback, HasObserverName},
feedbacks::{Feedback, HasObserverReference},
inputs::UsesInput,
monitors::{AggregatorOps, UserStats, UserStatsValue},
observers::{CanTrack, MapObserver, Observer, ObserversTuple, UsesObserver},
observers::{CanTrack, MapObserver, Observer, ObserversTuple},
state::State,
Error, HasMetadata, HasNamedMetadata,
};
/// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from (`HitcountsMapObserver`)[`crate::observers::HitcountsMapObserver`].
pub type AflMapFeedback<C, O, S, T> = MapFeedback<C, DifferentIsNovel, O, OrReducer, S, T>;
pub type AflMapFeedback<C, O, T> = MapFeedback<C, DifferentIsNovel, O, OrReducer, T>;
/// A [`MapFeedback`] that strives to maximize the map contents.
pub type MaxMapFeedback<C, O, S, T> = MapFeedback<C, DifferentIsNovel, O, MaxReducer, S, T>;
pub type MaxMapFeedback<C, O, T> = MapFeedback<C, DifferentIsNovel, O, MaxReducer, T>;
/// A [`MapFeedback`] that strives to minimize the map contents.
pub type MinMapFeedback<C, O, S, T> = MapFeedback<C, DifferentIsNovel, O, MinReducer, S, T>;
pub type MinMapFeedback<C, O, T> = MapFeedback<C, DifferentIsNovel, O, MinReducer, T>;
/// A [`MapFeedback`] that always returns `true` for `is_interesting`. Useful for tracing all executions.
pub type AlwaysInterestingMapFeedback<C, O, S, T> = MapFeedback<C, AllIsNovel, O, NopReducer, S, T>;
pub type AlwaysInterestingMapFeedback<C, O, T> = MapFeedback<C, AllIsNovel, O, NopReducer, T>;
/// A [`MapFeedback`] that strives to maximize the map contents,
/// but only, if a value is larger than `pow2` of the previous.
pub type MaxMapPow2Feedback<C, O, S, T> = MapFeedback<C, NextPow2IsNovel, O, MaxReducer, S, T>;
pub type MaxMapPow2Feedback<C, O, T> = MapFeedback<C, NextPow2IsNovel, O, MaxReducer, T>;
/// A [`MapFeedback`] that strives to maximize the map contents,
/// but only, if a value is larger than `pow2` of the previous.
pub type MaxMapOneOrFilledFeedback<C, O, S, T> =
MapFeedback<C, OneOrFilledIsNovel, O, MaxReducer, S, T>;
pub type MaxMapOneOrFilledFeedback<C, O, T> = MapFeedback<C, OneOrFilledIsNovel, O, MaxReducer, T>;
/// A `Reducer` function is used to aggregate values for the novelty search
pub trait Reducer<T>: 'static
@ -380,35 +382,27 @@ where
/// The most common AFL-like feedback type
#[derive(Clone, Debug)]
pub struct MapFeedback<C, N, O, R, S, T> {
pub struct MapFeedback<C, N, O, R, T> {
/// New indexes observed in the last observation
novelties: Option<Vec<usize>>,
/// Name identifier of this instance
name: Cow<'static, str>,
/// Name identifier of the observer
observer_name: Cow<'static, str>,
map_ref: Reference<C>,
/// Name of the feedback as shown in the `UserStats`
stats_name: Cow<'static, str>,
/// Phantom Data of Reducer
phantom: PhantomData<(C, N, O, R, S, T)>,
phantom: PhantomData<(C, N, O, R, T)>,
}
impl<C, N, O, R, S, T> UsesObserver<S> for MapFeedback<C, N, O, R, S, T>
where
S: UsesInput,
C: AsRef<O> + Observer<S>,
{
type Observer = C;
}
impl<C, N, O, R, S, T> Feedback<S> for MapFeedback<C, N, O, R, S, T>
impl<C, N, O, R, S, T> Feedback<S> for MapFeedback<C, N, O, R, T>
where
N: IsNovel<T>,
O: MapObserver<Entry = T> + for<'it> AsIter<'it, Item = T>,
R: Reducer<T>,
S: State + HasNamedMetadata,
T: Default + Copy + Serialize + for<'de> Deserialize<'de> + PartialEq + Debug + 'static,
C: CanTrack + AsRef<O>,
C: CanTrack + AsRef<O> + Observer<S>,
{
fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
// Initialize `MapFeedbackMetadata` with an empty vector and add it to the state.
@ -464,10 +458,7 @@ where
let meta = MapNoveltiesMetadata::new(novelties);
testcase.add_metadata(meta);
}
let observer = observers
.match_name::<C>(&self.observer_name)
.unwrap()
.as_ref();
let observer = observers.get(&self.map_ref).unwrap().as_ref();
let initial = observer.initial();
let map_state = state
.named_metadata_map_mut()
@ -546,12 +537,12 @@ where
/// Specialize for the common coverage map size, maximization of u8s
#[rustversion::nightly]
impl<C, O, S> Feedback<S> for MapFeedback<C, DifferentIsNovel, O, MaxReducer, S, u8>
impl<C, O, S> Feedback<S> for MapFeedback<C, DifferentIsNovel, O, MaxReducer, u8>
where
O: MapObserver<Entry = u8> + AsSlice<Entry = u8>,
for<'it> O: AsIter<'it, Item = u8>,
S: State + HasNamedMetadata,
C: CanTrack + AsRef<O>,
C: CanTrack + AsRef<O> + Observer<S>,
{
#[allow(clippy::wrong_self_convention)]
#[allow(clippy::needless_range_loop)]
@ -572,10 +563,7 @@ where
let mut interesting = false;
// TODO Replace with match_name_type when stable
let observer = observers
.match_name::<C>(&self.observer_name)
.unwrap()
.as_ref();
let observer = observers.get(&self.map_ref).unwrap().as_ref();
let map_state = state
.named_metadata_map_mut()
@ -666,21 +654,23 @@ where
}
}
impl<C, N, O, R, S, T> Named for MapFeedback<C, N, O, R, S, T> {
impl<C, N, O, R, T> Named for MapFeedback<C, N, O, R, T> {
#[inline]
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
impl<C, N, O, R, S, T> HasObserverName for MapFeedback<C, N, O, R, S, T>
impl<C, N, O, R, T> HasObserverReference for MapFeedback<C, N, O, R, T>
where
O: Named,
C: AsRef<O>,
{
type Observer = C;
#[inline]
fn observer_name(&self) -> &Cow<'static, str> {
&self.observer_name
fn observer_ref(&self) -> &Reference<C> {
&self.map_ref
}
}
@ -693,24 +683,22 @@ fn create_stats_name(name: &Cow<'static, str>) -> Cow<'static, str> {
}
}
impl<C, N, O, R, S, T> MapFeedback<C, N, O, R, S, T>
impl<C, N, O, R, T> MapFeedback<C, N, O, R, T>
where
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
R: Reducer<T>,
O: MapObserver<Entry = T>,
for<'it> O: AsIter<'it, Item = T>,
N: IsNovel<T>,
S: UsesInput + HasNamedMetadata,
C: CanTrack + AsRef<O>,
C: CanTrack + AsRef<O> + Named,
{
/// Create new `MapFeedback`
#[must_use]
pub fn new(map_observer: &C) -> Self {
let map_observer = map_observer.as_ref();
Self {
novelties: if C::NOVELTIES { Some(vec![]) } else { None },
name: map_observer.name().clone(),
observer_name: map_observer.name().clone(),
map_ref: map_observer.reference(),
stats_name: create_stats_name(map_observer.name()),
phantom: PhantomData,
}
@ -722,10 +710,9 @@ where
#[must_use]
pub fn with_name(name: &'static str, map_observer: &C) -> Self {
let name = Cow::from(name);
let map_observer = map_observer.as_ref();
Self {
novelties: if C::NOVELTIES { Some(vec![]) } else { None },
observer_name: map_observer.name().clone(),
map_ref: map_observer.reference(),
stats_name: create_stats_name(&name),
name,
phantom: PhantomData,
@ -735,7 +722,7 @@ where
#[allow(clippy::wrong_self_convention)]
#[allow(clippy::needless_range_loop)]
#[allow(clippy::trivially_copy_pass_by_ref)]
fn is_interesting_default<EM, OT>(
fn is_interesting_default<EM, S, OT>(
&mut self,
state: &mut S,
_manager: &mut EM,
@ -746,13 +733,11 @@ where
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
S: UsesInput + HasNamedMetadata,
{
let mut interesting = false;
// TODO Replace with match_name_type when stable
let observer = observers
.match_name::<C>(&self.observer_name)
.unwrap()
.as_ref();
let observer = observers.get(&self.map_ref).unwrap().as_ref();
let map_state = state
.named_metadata_map_mut()

View File

@ -4,43 +4,27 @@
// TODO: make S of Feedback<S> an associated type when specialisation + AT is stable
pub mod map;
use alloc::borrow::Cow;
pub use map::*;
pub mod differential;
pub use differential::DiffFeedback;
#[cfg(feature = "std")]
pub mod concolic;
#[cfg(feature = "std")]
pub use concolic::ConcolicFeedback;
#[cfg(feature = "std")]
pub mod new_hash_feedback;
#[cfg(feature = "std")]
pub use new_hash_feedback::NewHashFeedback;
#[cfg(feature = "std")]
pub use new_hash_feedback::NewHashFeedbackMetadata;
#[cfg(feature = "nautilus")]
pub mod nautilus;
#[cfg(feature = "std")]
pub mod stdio;
pub mod transferred;
/// The module for list feedback
pub mod list;
use core::{
fmt::{self, Debug, Formatter},
marker::PhantomData,
};
use libafl_bolts::Named;
#[cfg(feature = "std")]
pub use concolic::ConcolicFeedback;
pub use differential::DiffFeedback;
use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
Named,
};
pub use list::*;
pub use map::*;
#[cfg(feature = "nautilus")]
pub use nautilus::*;
#[cfg(feature = "std")]
pub use new_hash_feedback::NewHashFeedback;
#[cfg(feature = "std")]
pub use new_hash_feedback::NewHashFeedbackMetadata;
use serde::{Deserialize, Serialize};
use crate::{
@ -52,6 +36,22 @@ use crate::{
Error,
};
pub mod map;
#[cfg(feature = "std")]
pub mod concolic;
pub mod differential;
#[cfg(feature = "nautilus")]
pub mod nautilus;
#[cfg(feature = "std")]
pub mod new_hash_feedback;
#[cfg(feature = "std")]
pub mod stdio;
pub mod transferred;
/// The module for list feedback
pub mod list;
/// Feedbacks evaluate the observers.
/// Basically, they reduce the information provided by an observer to a value,
/// indicating the "interestingness" of the last run.
@ -138,9 +138,12 @@ where
}
/// Has an associated observer name (mostly used to retrieve the observer with `MatchName` from an `ObserverTuple`)
pub trait HasObserverName {
pub trait HasObserverReference {
/// The observer for which we hold a reference
type Observer: ?Sized;
/// The name associated with the observer
fn observer_name(&self) -> &Cow<'static, str>;
fn observer_ref(&self) -> &Reference<Self::Observer>;
}
/// A combined feedback consisting of multiple [`Feedback`]s
@ -931,7 +934,7 @@ pub type TimeoutFeedbackFactory = DefaultFeedbackFactory<TimeoutFeedback>;
/// It decides, if the given [`TimeObserver`] value of a run is interesting.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TimeFeedback {
name: Cow<'static, str>,
obs_ref: Reference<TimeObserver>,
}
impl<S> Feedback<S> for TimeFeedback
@ -968,7 +971,7 @@ where
OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{
let observer = observers.match_name::<TimeObserver>(self.name()).unwrap();
let observer = observers.get(&self.obs_ref).unwrap();
*testcase.exec_time_mut() = *observer.last_runtime();
Ok(())
}
@ -983,24 +986,16 @@ where
impl Named for TimeFeedback {
#[inline]
fn name(&self) -> &Cow<'static, str> {
&self.name
self.obs_ref.name()
}
}
impl TimeFeedback {
/// Creates a new [`TimeFeedback`], deciding if the value of a [`TimeObserver`] with the given `name` of a run is interesting.
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
name: Cow::from(name),
}
}
/// Creates a new [`TimeFeedback`], deciding if the given [`TimeObserver`] value of a run is interesting.
#[must_use]
pub fn with_observer(observer: &TimeObserver) -> Self {
pub fn new(observer: &TimeObserver) -> Self {
Self {
name: observer.name().clone(),
obs_ref: observer.reference(),
}
}
}

View File

@ -4,13 +4,16 @@ use alloc::{borrow::Cow, string::ToString};
use std::{fmt::Debug, marker::PhantomData};
use hashbrown::HashSet;
use libafl_bolts::Named;
use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize};
use crate::{
events::EventFirer,
executors::ExitKind,
feedbacks::{Feedback, HasObserverName},
feedbacks::{Feedback, HasObserverReference},
inputs::UsesInput,
observers::{ObserverWithHashField, ObserversTuple},
state::State,
@ -79,10 +82,10 @@ impl HashSetState<u64> for NewHashFeedbackMetadata {
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct NewHashFeedback<O, S> {
name: Cow<'static, str>,
observer_name: Cow<'static, str>,
o_ref: Reference<O>,
/// Initial capacity of hash set
capacity: usize,
o_type: PhantomData<(O, S)>,
phantom: PhantomData<S>,
}
impl<O, S> Feedback<S> for NewHashFeedback<O, S>
@ -112,7 +115,7 @@ where
OT: ObserversTuple<S>,
{
let observer = observers
.match_name::<O>(&self.observer_name)
.get(&self.o_ref)
.expect("A NewHashFeedback needs a BacktraceObserver");
let backtrace_state = state
@ -142,10 +145,12 @@ impl<O, S> Named for NewHashFeedback<O, S> {
}
}
impl<O, S> HasObserverName for NewHashFeedback<O, S> {
impl<O, S> HasObserverReference for NewHashFeedback<O, S> {
type Observer = O;
#[inline]
fn observer_name(&self) -> &Cow<'static, str> {
&self.observer_name
fn observer_ref(&self) -> &Reference<O> {
&self.o_ref
}
}
@ -171,9 +176,9 @@ where
pub fn with_capacity(observer: &O, capacity: usize) -> Self {
Self {
name: Cow::from(NEWHASHFEEDBACK_PREFIX.to_string() + observer.name()),
observer_name: observer.name().clone(),
o_ref: observer.reference(),
capacity,
o_type: PhantomData,
phantom: PhantomData,
}
}
}

View File

@ -2,7 +2,11 @@
use alloc::{borrow::Cow, string::String};
use libafl_bolts::{impl_serdeany, Named};
use libafl_bolts::{
impl_serdeany,
tuples::{MatchNameRef, Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize};
use crate::{
@ -28,7 +32,7 @@ impl_serdeany!(StdOutMetadata);
/// is never interesting (use with an OR).
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct StdOutToMetadataFeedback {
name: Cow<'static, str>,
o_ref: Reference<StdOutObserver>,
}
impl<S> Feedback<S> for StdOutToMetadataFeedback
@ -66,7 +70,7 @@ where
EM: EventFirer<State = S>,
{
let observer = observers
.match_name::<StdOutObserver>(self.name())
.get(&self.o_ref)
.ok_or(Error::illegal_state("StdOutObserver is missing"))?;
let buffer = observer
.stdout
@ -91,25 +95,16 @@ where
impl Named for StdOutToMetadataFeedback {
#[inline]
fn name(&self) -> &Cow<'static, str> {
&self.name
self.o_ref.name()
}
}
impl StdOutToMetadataFeedback {
/// Creates a new [`StdOutToMetadataFeedback`]. The provided `name` is
/// used to look up the observer.
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
name: Cow::from(name),
}
}
/// Creates a new [`StdOutToMetadataFeedback`].
#[must_use]
pub fn with_observer(observer: &StdOutObserver) -> Self {
pub fn new(observer: &StdOutObserver) -> Self {
Self {
name: observer.name().clone(),
o_ref: observer.reference(),
}
}
}
@ -127,7 +122,7 @@ impl_serdeany!(StdErrMetadata);
/// is never interesting (use with an OR).
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct StdErrToMetadataFeedback {
name: Cow<'static, str>,
o_ref: Reference<StdErrObserver>,
}
impl<S> Feedback<S> for StdErrToMetadataFeedback
@ -165,7 +160,7 @@ where
EM: EventFirer<State = S>,
{
let observer = observers
.match_name::<StdErrObserver>(self.name())
.get(&self.o_ref)
.ok_or(Error::illegal_state("StdErrObserver is missing"))?;
let buffer = observer
.stderr
@ -190,25 +185,16 @@ where
impl Named for StdErrToMetadataFeedback {
#[inline]
fn name(&self) -> &Cow<'static, str> {
&self.name
self.o_ref.name()
}
}
impl StdErrToMetadataFeedback {
/// Creates a new [`StdErrToMetadataFeedback`]. The provided `name` is
/// used to look up the observer.
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
name: Cow::from(name),
}
}
/// Creates a new [`StdErrToMetadataFeedback`].
#[must_use]
pub fn with_observer(observer: &StdErrObserver) -> Self {
pub fn new(observer: &StdErrObserver) -> Self {
Self {
name: observer.name().clone(),
o_ref: observer.reference(),
}
}
}

View File

@ -541,9 +541,9 @@ where
let exit_kind = self.execute_input(state, executor, manager, &input)?;
let observers = executor.observers();
self.scheduler.on_evaluation(state, &input, observers)?;
self.scheduler.on_evaluation(state, &input, &*observers)?;
self.execute_and_process(state, manager, input, observers, &exit_kind, send_events)
self.execute_and_process(state, manager, input, &*observers, &exit_kind, send_events)
}
}
@ -595,18 +595,22 @@ where
// Maybe a solution
#[cfg(not(feature = "introspection"))]
let is_solution = self
.objective_mut()
.is_interesting(state, manager, &input, observers, &exit_kind)?;
let is_solution =
self.objective_mut()
.is_interesting(state, manager, &input, &*observers, &exit_kind)?;
#[cfg(feature = "introspection")]
let is_solution = self
.objective_mut()
.is_interesting_introspection(state, manager, &input, observers, &exit_kind)?;
let is_solution = self.objective_mut().is_interesting_introspection(
state,
manager,
&input,
&*observers,
&exit_kind,
)?;
if is_solution {
self.objective_mut()
.append_metadata(state, manager, observers, &mut testcase)?;
.append_metadata(state, manager, &*observers, &mut testcase)?;
let idx = state.solutions_mut().add(testcase)?;
let executions = *state.executions();
@ -627,25 +631,29 @@ where
// several is_interesting implementations collect some data about the run, later used in
// append_metadata; we *must* invoke is_interesting here to collect it
#[cfg(not(feature = "introspection"))]
let _corpus_worthy = self
.feedback_mut()
.is_interesting(state, manager, &input, observers, &exit_kind)?;
let _corpus_worthy =
self.feedback_mut()
.is_interesting(state, manager, &input, &*observers, &exit_kind)?;
#[cfg(feature = "introspection")]
let _corpus_worthy = self
.feedback_mut()
.is_interesting_introspection(state, manager, &input, observers, &exit_kind)?;
let _corpus_worthy = self.feedback_mut().is_interesting_introspection(
state,
manager,
&input,
&*observers,
&exit_kind,
)?;
// Add the input to the main corpus
self.feedback_mut()
.append_metadata(state, manager, observers, &mut testcase)?;
.append_metadata(state, manager, &*observers, &mut testcase)?;
let idx = state.corpus_mut().add(testcase)?;
self.scheduler_mut().on_add(state, idx)?;
let observers_buf = if manager.configuration() == EventConfig::AlwaysUnique {
None
} else {
manager.serialize_observers::<OT>(observers)?
manager.serialize_observers::<OT>(&*observers)?
};
manager.fire(
state,

View File

@ -8,12 +8,9 @@ use crate::{inputs::UsesInput, observers::Observer};
/// A simple observer with a list of things.
#[derive(Serialize, Deserialize, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")]
#[serde(bound = "T: serde::de::DeserializeOwned + serde::Serialize")]
#[allow(clippy::unsafe_derive_deserialize)]
pub struct ListObserver<T>
where
T: Debug + Serialize,
{
pub struct ListObserver<T> {
name: Cow<'static, str>,
/// The list
list: OwnedMutPtr<Vec<T>>,

View File

@ -38,15 +38,6 @@ pub use value::*;
use crate::{executors::ExitKind, inputs::UsesInput, state::UsesState, Error};
/// Something that uses observer like mapfeedbacks
pub trait UsesObserver<S>
where
S: UsesInput,
{
/// The observer type used
type Observer: Observer<S>;
}
/// Observers observe different information about the target.
/// They can then be used by various sorts of feedback.
pub trait Observer<S>: Named

View File

@ -27,7 +27,10 @@ pub mod weighted;
pub use weighted::{StdWeightedScheduler, WeightedScheduler};
pub mod tuneable;
use libafl_bolts::rands::Rand;
use libafl_bolts::{
rands::Rand,
tuples::{MatchNameRef, Reference},
};
pub use tuneable::*;
use crate::{
@ -79,7 +82,7 @@ where
fn set_last_hash(&mut self, value: usize);
/// Get the observer map observer name
fn map_observer_name(&self) -> &str;
fn map_observer_ref(&self) -> &Reference<C>;
/// Called when a [`Testcase`] is added to the corpus
fn on_add_metadata(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
@ -118,7 +121,7 @@ where
OT: ObserversTuple<Self::State>,
{
let observer = observers
.match_name::<C>(self.map_observer_name())
.get(self.map_observer_ref())
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref();

View File

@ -1,12 +1,12 @@
//! The queue corpus scheduler for power schedules.
use alloc::{
string::{String, ToString},
vec::Vec,
};
use alloc::vec::Vec;
use core::{marker::PhantomData, time::Duration};
use libafl_bolts::Named;
use libafl_bolts::{
tuples::{Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize};
use crate::{
@ -173,9 +173,9 @@ pub enum PowerSchedule {
#[derive(Clone, Debug)]
pub struct PowerQueueScheduler<C, O, S> {
strat: PowerSchedule,
map_observer_name: String,
map_observer_ref: Reference<C>,
last_hash: usize,
phantom: PhantomData<(C, O, S)>,
phantom: PhantomData<(O, S)>,
}
impl<C, O, S> UsesState for PowerQueueScheduler<C, O, S>
@ -226,8 +226,8 @@ where
self.last_hash = hash;
}
fn map_observer_name(&self) -> &str {
&self.map_observer_name
fn map_observer_ref(&self) -> &Reference<C> {
&self.map_observer_ref
}
}
@ -256,9 +256,9 @@ where
fn next(&mut self, state: &mut Self::State) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 {
Err(Error::empty(String::from(
Err(Error::empty(
"No entries in corpus. This often implies the target is not properly instrumented.",
)))
))
} else {
let id = match state.corpus().current() {
Some(cur) => {
@ -305,7 +305,7 @@ where
}
PowerQueueScheduler {
strat,
map_observer_name: map_observer.name().to_string(),
map_observer_ref: map_observer.reference(),
last_hash: 0,
phantom: PhantomData,
}

View File

@ -1,11 +1,14 @@
//! The queue corpus scheduler with weighted queue item selection [from AFL++](https://github.com/AFLplusplus/AFLplusplus/blob/1d4f1e48797c064ee71441ba555b29fc3f467983/src/afl-fuzz-queue.c#L32).
//! This queue corpus scheduler needs calibration stage.
use alloc::string::{String, ToString};
use core::marker::PhantomData;
use hashbrown::HashMap;
use libafl_bolts::{rands::Rand, Named};
use libafl_bolts::{
rands::Rand,
tuples::{Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize};
use crate::{
@ -95,9 +98,9 @@ libafl_bolts::impl_serdeany!(WeightedScheduleMetadata);
pub struct WeightedScheduler<C, F, O, S> {
table_invalidated: bool,
strat: Option<PowerSchedule>,
map_observer_name: String,
map_observer_ref: Reference<C>,
last_hash: usize,
phantom: PhantomData<(C, F, O, S)>,
phantom: PhantomData<(F, O, S)>,
}
impl<C, F, O, S> WeightedScheduler<C, F, O, S>
@ -121,7 +124,7 @@ where
Self {
strat,
map_observer_name: map_observer.name().to_string(),
map_observer_ref: map_observer.reference(),
last_hash: 0,
table_invalidated: true,
phantom: PhantomData,
@ -271,8 +274,8 @@ where
self.last_hash = hash;
}
fn map_observer_name(&self) -> &str {
&self.map_observer_name
fn map_observer_ref(&self) -> &Reference<C> {
&self.map_observer_ref
}
}
@ -310,9 +313,9 @@ where
}
let corpus_counts = state.corpus().count();
if corpus_counts == 0 {
Err(Error::empty(String::from(
Err(Error::empty(
"No entries in corpus. This often implies the target is not properly instrumented.",
)))
))
} else {
let s = random_corpus_id!(state.corpus(), state.rand_mut());

View File

@ -1,14 +1,10 @@
//! The calibration stage. The fuzzer measures the average exec time and the bitmap size.
use alloc::{
borrow::Cow,
string::{String, ToString},
vec::Vec,
};
use alloc::{borrow::Cow, vec::Vec};
use core::{fmt::Debug, marker::PhantomData, time::Duration};
use hashbrown::HashSet;
use libafl_bolts::{current_time, impl_serdeany, AsIter, Named};
use libafl_bolts::{current_time, impl_serdeany, tuples::Reference, AsIter, Named};
use num_traits::Bounded;
use serde::{Deserialize, Serialize};
@ -16,10 +12,11 @@ use crate::{
corpus::{Corpus, SchedulerTestcaseMetadata},
events::{Event, EventFirer, LogSeverity},
executors::{Executor, ExitKind, HasObservers},
feedbacks::{map::MapFeedbackMetadata, HasObserverName},
feedbacks::{map::MapFeedbackMetadata, HasObserverReference},
fuzzer::Evaluator,
inputs::UsesInput,
monitors::{AggregatorOps, UserStats, UserStatsValue},
observers::{MapObserver, ObserversTuple, UsesObserver},
observers::{MapObserver, ObserversTuple},
schedulers::powersched::SchedulerMetadata,
stages::{ExecutionCountRestartHelper, Stage},
state::{HasCorpus, HasCurrentTestcase, HasExecutions, State, UsesState},
@ -66,13 +63,13 @@ impl 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, O, OT, S> {
map_observer_name: String,
map_name: String,
map_observer_ref: Reference<C>,
map_name: Cow<'static, str>,
stage_max: usize,
/// If we should track stability
track_stability: bool,
restart_helper: ExecutionCountRestartHelper,
phantom: PhantomData<(C, O, OT, S)>,
phantom: PhantomData<(O, OT, S)>,
}
const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1
@ -147,10 +144,7 @@ where
.observers_mut()
.post_exec_all(state, &input, &exit_kind)?;
let map_first = &executor
.observers()
.match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
let map_first = &executor.observers()[&self.map_observer_ref]
.as_ref()
.to_vec();
@ -191,10 +185,7 @@ where
.post_exec_all(state, &input, &exit_kind)?;
if self.track_stability {
let map = &executor
.observers()
.match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
let map = &executor.observers()[&self.map_observer_ref]
.as_ref()
.to_vec();
@ -248,11 +239,8 @@ where
// If weighted scheduler or powerscheduler is used, update it
if state.has_metadata::<SchedulerMetadata>() {
let map = executor
.observers()
.match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref();
let observers = executor.observers();
let map = observers[&self.map_observer_ref].as_ref();
let mut bitmap_size = map.count_bytes();
assert!(bitmap_size != 0);
@ -343,21 +331,20 @@ where
impl<C, O, OT, S> CalibrationStage<C, O, OT, S>
where
O: MapObserver,
for<'it> O: AsIter<'it, Item = O::Entry>,
C: AsRef<O>,
OT: ObserversTuple<S>,
S: HasCorpus + HasMetadata + HasNamedMetadata,
S: UsesInput + HasNamedMetadata,
{
/// Create a new [`CalibrationStage`].
#[must_use]
pub fn new<F>(map_feedback: &F) -> Self
where
F: HasObserverName + Named + UsesObserver<S, Observer = C>,
for<'it> O: AsIter<'it, Item = O::Entry>,
C: AsRef<O>,
F: HasObserverReference<Observer = C> + Named,
{
Self {
map_observer_name: map_feedback.observer_name().to_string(),
map_name: map_feedback.name().to_string(),
map_observer_ref: map_feedback.observer_ref().clone(),
map_name: map_feedback.name().clone(),
stage_max: CAL_STAGE_START,
track_stability: true,
restart_helper: ExecutionCountRestartHelper::default(),
@ -369,13 +356,11 @@ where
#[must_use]
pub fn ignore_stability<F>(map_feedback: &F) -> Self
where
F: HasObserverName + Named + UsesObserver<S, Observer = C>,
for<'it> O: AsIter<'it, Item = O::Entry>,
C: AsRef<O>,
F: HasObserverReference<Observer = C> + Named,
{
Self {
map_observer_name: map_feedback.observer_name().to_string(),
map_name: map_feedback.name().to_string(),
map_observer_ref: map_feedback.observer_ref().clone(),
map_name: map_feedback.name().clone(),
stage_max: CAL_STAGE_START,
track_stability: false,
restart_helper: ExecutionCountRestartHelper::default(),

View File

@ -1,8 +1,12 @@
//! The colorization stage from `colorization()` in afl++
use alloc::{borrow::Cow, collections::binary_heap::BinaryHeap, string::ToString, vec::Vec};
use alloc::{borrow::Cow, collections::binary_heap::BinaryHeap, vec::Vec};
use core::{cmp::Ordering, fmt::Debug, marker::PhantomData, ops::Range};
use libafl_bolts::{rands::Rand, tuples::MatchName, Named};
use libafl_bolts::{
rands::Rand,
tuples::{Reference, Referenceable},
Named,
};
use serde::{Deserialize, Serialize};
use crate::{
@ -51,9 +55,9 @@ impl Ord for Earlier {
/// The mutational stage using power schedules
#[derive(Clone, Debug)]
pub struct ColorizationStage<C, E, EM, O, Z> {
map_observer_name: Cow<'static, str>,
map_observer_ref: Reference<C>,
#[allow(clippy::type_complexity)]
phantom: PhantomData<(C, E, EM, O, E, Z)>,
phantom: PhantomData<(E, EM, O, E, Z)>,
}
impl<C, E, EM, O, Z> UsesState for ColorizationStage<C, E, EM, O, Z>
@ -68,7 +72,7 @@ where
E: UsesState,
{
fn name(&self) -> &Cow<'static, str> {
&self.map_observer_name
self.map_observer_ref.name()
}
}
@ -92,7 +96,7 @@ where
manager: &mut EM,
) -> Result<(), Error> {
// Run with the mutated input
Self::colorize(fuzzer, executor, state, manager, &self.map_observer_name)?;
Self::colorize(fuzzer, executor, state, manager, &self.map_observer_ref)?;
Ok(())
}
@ -164,7 +168,7 @@ where
executor: &mut E,
state: &mut E::State,
manager: &mut EM,
name: &str,
obs_ref: &Reference<C>,
) -> Result<E::Input, Error> {
let mut input = state.current_input_cloned()?;
// The backup of the input
@ -179,7 +183,7 @@ where
// Idea: No need to do this every time
let orig_hash =
Self::get_raw_map_hash_run(fuzzer, executor, state, manager, consumed_input, name)?;
Self::get_raw_map_hash_run(fuzzer, executor, state, manager, consumed_input, obs_ref)?;
let changed_bytes = changed.bytes_mut();
let input_len = changed_bytes.len();
@ -224,7 +228,7 @@ where
state,
manager,
consumed_input,
name,
obs_ref,
)?;
if orig_hash == changed_hash {
@ -297,7 +301,7 @@ where
/// Creates a new [`ColorizationStage`]
pub fn new(map_observer: &C) -> Self {
Self {
map_observer_name: map_observer.name().clone(),
map_observer_ref: map_observer.reference(),
phantom: PhantomData,
}
}
@ -309,17 +313,14 @@ where
state: &mut E::State,
manager: &mut EM,
input: E::Input,
name: &str,
obs_ref: &Reference<C>,
) -> Result<usize, Error> {
executor.observers_mut().pre_exec_all(state, &input)?;
let exit_kind = executor.run_target(fuzzer, state, manager, &input)?;
let observer = executor
.observers()
.match_name::<C>(name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref();
let observers = executor.observers();
let observer = observers[obs_ref].as_ref();
let hash = observer.hash_simple() as usize;

View File

@ -2,13 +2,16 @@
//! and use the results for fuzzer input and mutations.
//!
use alloc::{borrow::Cow, string::String};
use alloc::borrow::Cow;
#[cfg(feature = "concolic_mutation")]
use alloc::{string::ToString, vec::Vec};
#[cfg(feature = "concolic_mutation")]
use core::marker::PhantomData;
use libafl_bolts::{tuples::MatchName, Named};
use libafl_bolts::{
tuples::{MatchNameRef, Reference},
Named,
};
#[cfg(all(feature = "concolic_mutation", feature = "introspection"))]
use crate::monitors::PerfFeature;
@ -34,26 +37,26 @@ use crate::{
/// Wraps a [`TracingStage`] to add concolic observing.
#[derive(Clone, Debug)]
pub struct ConcolicTracingStage<EM, TE, Z> {
pub struct ConcolicTracingStage<'a, EM, TE, Z> {
inner: TracingStage<EM, TE, Z>,
observer_name: String,
obs_ref: Reference<ConcolicObserver<'a>>,
}
impl<EM, TE, Z> UsesState for ConcolicTracingStage<EM, TE, Z>
impl<EM, TE, Z> UsesState for ConcolicTracingStage<'_, EM, TE, Z>
where
TE: UsesState,
{
type State = TE::State;
}
impl<EM, TE, Z> Named for ConcolicTracingStage<EM, TE, Z> {
impl<EM, TE, Z> Named for ConcolicTracingStage<'_, EM, TE, Z> {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("ConcolicTracingStage");
&NAME
}
}
impl<E, EM, TE, Z> Stage<E, EM, Z> for ConcolicTracingStage<EM, TE, Z>
impl<E, EM, TE, Z> Stage<E, EM, Z> for ConcolicTracingStage<'_, EM, TE, Z>
where
E: UsesState<State = TE::State>,
EM: UsesState<State = TE::State>,
@ -70,12 +73,7 @@ where
manager: &mut EM,
) -> Result<(), Error> {
self.inner.trace(fuzzer, state, manager)?;
if let Some(observer) = self
.inner
.executor()
.observers()
.match_name::<ConcolicObserver>(&self.observer_name)
{
if let Some(observer) = self.inner.executor().observers().get(&self.obs_ref) {
let metadata = observer.create_metadata_from_current_map();
state
.current_testcase_mut()?
@ -94,14 +92,11 @@ where
}
}
impl<EM, TE, Z> ConcolicTracingStage<EM, TE, Z> {
impl<'a, EM, TE, Z> ConcolicTracingStage<'a, EM, TE, 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, Z>, observer_name: String) -> Self {
Self {
inner,
observer_name,
}
pub fn new(inner: TracingStage<EM, TE, Z>, obs_ref: Reference<ConcolicObserver<'a>>) -> Self {
Self { inner, obs_ref }
}
}

View File

@ -1,13 +1,12 @@
//! The tracing stage can trace the target and enrich a [`crate::corpus::Testcase`] with metadata, for example for `CmpLog`.
use alloc::{
borrow::Cow,
string::{String, ToString},
vec::Vec,
};
use alloc::{borrow::Cow, vec::Vec};
use core::{fmt::Debug, marker::PhantomData};
use libafl_bolts::{AsSlice, Named};
use libafl_bolts::{
tuples::{Reference, Referenceable},
AsSlice, Named,
};
use crate::{
corpus::{Corpus, HasCurrentCorpusIdx},
@ -44,9 +43,9 @@ fn find_next_char(list: &[Option<u8>], mut idx: usize, ch: u8) -> usize {
/// A stage that runs a tracer executor
#[derive(Clone, Debug)]
pub struct GeneralizationStage<C, EM, O, OT, Z> {
map_observer_name: String,
map_observer_ref: Reference<C>,
#[allow(clippy::type_complexity)]
phantom: PhantomData<(C, EM, O, OT, Z)>,
phantom: PhantomData<(EM, O, OT, Z)>,
}
impl<C, EM, O, OT, Z> Named for GeneralizationStage<C, EM, O, OT, Z> {
@ -67,7 +66,7 @@ where
impl<C, E, EM, O, Z> Stage<E, EM, Z> for GeneralizationStage<C, EM, O, E::Observers, Z>
where
O: MapObserver,
C: CanTrack + AsRef<O>,
C: CanTrack + AsRef<O> + Named,
E: Executor<EM, Z> + HasObservers,
E::Observers: ObserversTuple<E::State>,
E::State:
@ -339,7 +338,7 @@ impl<C, EM, O, OT, Z> GeneralizationStage<C, EM, O, OT, Z>
where
EM: UsesState,
O: MapObserver,
C: CanTrack + AsRef<O>,
C: CanTrack + AsRef<O> + Named,
OT: ObserversTuple<EM::State>,
EM::State: UsesInput<Input = BytesInput> + HasExecutions + HasMetadata + HasCorpus,
{
@ -348,16 +347,7 @@ where
pub fn new(map_observer: &C) -> Self {
require_novelties_tracking!("GeneralizationStage", C);
Self {
map_observer_name: map_observer.as_ref().name().to_string(),
phantom: PhantomData,
}
}
/// Create a new [`GeneralizationStage`] from name
#[must_use]
pub fn from_name(map_observer_name: &str) -> Self {
Self {
map_observer_name: map_observer_name.to_string(),
map_observer_ref: map_observer.reference(),
phantom: PhantomData,
}
}
@ -391,10 +381,7 @@ where
.post_exec_all(state, input, &exit_kind)?;
mark_feature_time!(state, PerfFeature::PostExecObservers);
let cnt = executor
.observers()
.match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
let cnt = executor.observers()[&self.map_observer_ref]
.as_ref()
.how_many_set(novelties);

View File

@ -429,11 +429,12 @@ where
push_stage.set_current_corpus_idx(corpus_idx);
push_stage.init(fuzzer, state, event_mgr, executor.observers_mut())?;
push_stage.init(fuzzer, state, event_mgr, &mut *executor.observers_mut())?;
loop {
let input =
match push_stage.pre_exec(fuzzer, state, event_mgr, executor.observers_mut()) {
match push_stage.pre_exec(fuzzer, state, event_mgr, &mut *executor.observers_mut())
{
Some(Ok(next_input)) => next_input,
Some(Err(err)) => return Err(err),
None => break,
@ -445,14 +446,14 @@ where
fuzzer,
state,
event_mgr,
executor.observers_mut(),
&mut *executor.observers_mut(),
input,
exit_kind,
)?;
}
self.push_stage
.deinit(fuzzer, state, event_mgr, executor.observers_mut())
.deinit(fuzzer, state, event_mgr, &mut *executor.observers_mut())
}
#[inline]

View File

@ -4,13 +4,16 @@ use alloc::borrow::Cow;
use core::{borrow::BorrowMut, fmt::Debug, hash::Hash, marker::PhantomData};
use ahash::RandomState;
use libafl_bolts::{HasLen, Named};
use libafl_bolts::{
tuples::{MatchNameRef, Reference, Referenceable},
HasLen, Named,
};
use crate::{
corpus::{Corpus, HasCurrentCorpusIdx, Testcase},
events::EventFirer,
executors::{Executor, ExitKind, HasObservers},
feedbacks::{Feedback, FeedbackFactory, HasObserverName},
feedbacks::{Feedback, FeedbackFactory, HasObserverReference},
inputs::UsesInput,
mark_feature_time,
mutators::{MutationResult, Mutator},
@ -91,7 +94,7 @@ where
fuzzer.execute_input(state, executor, manager, &base)?;
let observers = executor.observers();
let mut feedback = self.create_feedback(observers);
let mut feedback = self.create_feedback(&*observers);
let mut i = 0;
loop {
@ -130,7 +133,7 @@ where
state,
manager,
input.clone(),
observers,
&*observers,
&exit_kind,
false,
)?;
@ -139,7 +142,7 @@ where
&& state.solutions().count() == solution_count
{
// we do not care about interesting inputs!
if feedback.is_interesting(state, manager, &input, observers, &exit_kind)? {
if feedback.is_interesting(state, manager, &input, &*observers, &exit_kind)? {
// we found a reduced corpus entry! use the smaller base
base = input;
base_post = Some(post.clone());
@ -172,11 +175,11 @@ where
// marked as interesting above; similarly, it should not trigger objectives
fuzzer
.feedback_mut()
.is_interesting(state, manager, &base, observers, &exit_kind)?;
.is_interesting(state, manager, &base, &*observers, &exit_kind)?;
let mut testcase = Testcase::with_executions(base, *state.executions());
fuzzer
.feedback_mut()
.append_metadata(state, manager, observers, &mut testcase)?;
.append_metadata(state, manager, &*observers, &mut testcase)?;
let prev = state.corpus_mut().replace(base_corpus_idx, testcase)?;
fuzzer
.scheduler_mut()
@ -245,6 +248,14 @@ where
IP: MutatedTransformPost<CS::State> + Clone,
I: MutatedTransform<CS::Input, CS::State, Post = IP> + Clone,
{
fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result<bool, Error> {
self.restart_helper.restart_progress_should_run(state)
}
fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
self.restart_helper.clear_restart_progress(state)
}
fn perform(
&mut self,
fuzzer: &mut Z,
@ -259,14 +270,6 @@ where
Ok(())
}
fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result<bool, Error> {
self.restart_helper.restart_progress_should_run(state)
}
fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
self.restart_helper.clear_restart_progress(state)
}
}
impl<CS, E, EM, F1, F2, FF, I, IP, M, OT, Z> FeedbackFactory<F2, Z::State, OT>
@ -348,28 +351,31 @@ where
/// A feedback which checks if the hash of the currently observed map is equal to the original hash
/// provided
#[derive(Clone, Debug)]
pub struct MapEqualityFeedback<M, S> {
pub struct MapEqualityFeedback<C, M, S> {
name: Cow<'static, str>,
obs_name: Cow<'static, str>,
map_ref: Reference<C>,
orig_hash: u64,
phantom: PhantomData<(M, S)>,
}
impl<M, S> Named for MapEqualityFeedback<M, S> {
impl<C, M, S> Named for MapEqualityFeedback<C, M, S> {
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
impl<M, S> HasObserverName for MapEqualityFeedback<M, S> {
fn observer_name(&self) -> &Cow<'static, str> {
&self.obs_name
impl<C, M, S> HasObserverReference for MapEqualityFeedback<C, M, S> {
type Observer = C;
fn observer_ref(&self) -> &Reference<Self::Observer> {
&self.map_ref
}
}
impl<M, S> Feedback<S> for MapEqualityFeedback<M, S>
impl<C, M, S> Feedback<S> for MapEqualityFeedback<C, M, S>
where
M: MapObserver,
C: AsRef<M>,
S: State,
{
fn is_interesting<EM, OT>(
@ -385,52 +391,57 @@ where
OT: ObserversTuple<S>,
{
let obs = observers
.match_name::<M>(self.observer_name())
.get(self.observer_ref())
.expect("Should have been provided valid observer name.");
Ok(obs.hash_simple() == self.orig_hash)
Ok(obs.as_ref().hash_simple() == self.orig_hash)
}
}
/// A feedback factory for ensuring that the maps for minimized inputs are the same
#[derive(Debug, Clone)]
pub struct MapEqualityFactory<M, S> {
obs_name: Cow<'static, str>,
phantom: PhantomData<(M, S)>,
pub struct MapEqualityFactory<C, M, S> {
map_ref: Reference<C>,
phantom: PhantomData<(C, M, S)>,
}
impl<M, S> MapEqualityFactory<M, S>
impl<C, M, S> MapEqualityFactory<C, M, S>
where
M: MapObserver,
C: AsRef<M> + Referenceable,
{
/// Creates a new map equality feedback for the given observer
pub fn with_observer(obs: &M) -> Self {
pub fn new(obs: &C) -> Self {
Self {
obs_name: obs.name().clone(),
map_ref: obs.reference(),
phantom: PhantomData,
}
}
}
impl<M, S> HasObserverName for MapEqualityFactory<M, S> {
fn observer_name(&self) -> &Cow<'static, str> {
&self.obs_name
impl<C, M, S> HasObserverReference for MapEqualityFactory<C, M, S> {
type Observer = C;
fn observer_ref(&self) -> &Reference<C> {
&self.map_ref
}
}
impl<M, OT, S> FeedbackFactory<MapEqualityFeedback<M, S>, S, OT> for MapEqualityFactory<M, S>
impl<C, M, OT, S> FeedbackFactory<MapEqualityFeedback<C, M, S>, S, OT>
for MapEqualityFactory<C, M, S>
where
M: MapObserver,
C: AsRef<M> + Referenceable,
OT: ObserversTuple<S>,
S: State + Debug,
{
fn create_feedback(&self, observers: &OT) -> MapEqualityFeedback<M, S> {
fn create_feedback(&self, observers: &OT) -> MapEqualityFeedback<C, M, S> {
let obs = observers
.match_name::<M>(self.observer_name())
.get(self.observer_ref())
.expect("Should have been provided valid observer name.");
MapEqualityFeedback {
name: Cow::from("MapEq"),
obs_name: self.obs_name.clone(),
orig_hash: obs.hash_simple(),
map_ref: obs.reference(),
orig_hash: obs.as_ref().hash_simple(),
phantom: PhantomData,
}
}

View File

@ -51,6 +51,7 @@ pub fn read_time_counter() -> u64 {
v
}
/// Read a timestamp for measurements
#[cfg(target_arch = "arm")]
#[must_use]
pub fn read_time_counter() -> u64 {

View File

@ -2,15 +2,19 @@
#[cfg(feature = "alloc")]
use alloc::{borrow::Cow, vec::Vec};
#[rustversion::not(nightly)]
use core::any::type_name;
#[cfg(feature = "alloc")]
use core::ops::{Deref, DerefMut};
use core::{
any::TypeId,
any::{type_name, TypeId},
fmt::{Debug, Formatter},
marker::PhantomData,
mem::transmute,
ops::{Index, IndexMut},
ptr::{addr_of, addr_of_mut},
};
#[cfg(feature = "alloc")]
use serde::{Deserialize, Serialize};
pub use tuple_list::{tuple_list, tuple_list_type, TupleList};
#[cfg(any(feature = "xxh3", feature = "alloc"))]
@ -219,9 +223,9 @@ where
/// Returns the first element with the given type
pub trait MatchFirstType {
/// Returns the first element with the given type as borrow, or [`Option::None`]
/// Returns the first element with the given type as borrow, or [`None`]
fn match_first_type<T: 'static>(&self) -> Option<&T>;
/// Returns the first element with the given type as mutable borrow, or [`Option::None`]
/// Returns the first element with the given type as mutable borrow, or [`None`]
fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T>;
}
@ -258,7 +262,7 @@ where
/// Returns the first element with the given type (dereference mut version)
pub trait ExtractFirstRefType {
/// Returns the first element with the given type as borrow, or [`Option::None`]
/// Returns the first element with the given type as borrow, or [`None`]
fn take<'a, T: 'static>(self) -> (Option<&'a T>, Self);
}
@ -305,7 +309,7 @@ where
/// Returns the first element with the given type (dereference mut version)
pub trait ExtractFirstRefMutType {
/// Returns the first element with the given type as borrow, or [`Option::None`]
/// Returns the first element with the given type as borrow, or [`None`]
fn take<'a, T: 'static>(self) -> (Option<&'a mut T>, Self);
}
@ -456,8 +460,10 @@ where
#[cfg(feature = "alloc")]
pub trait MatchName {
/// Match for a name and return the borrowed value
#[deprecated = "Use `.reference` and either `.get` (fallible access) or `[]` (infallible access) instead"]
fn match_name<T>(&self, name: &str) -> Option<&T>;
/// Match for a name and return the mut borrowed value
#[deprecated = "Use `.reference` and either `.get` (fallible access) or `[]` (infallible access) instead"]
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T>;
}
@ -472,6 +478,7 @@ impl MatchName for () {
}
#[cfg(feature = "alloc")]
#[allow(deprecated)]
impl<Head, Tail> MatchName for (Head, Tail)
where
Head: Named,
@ -494,56 +501,12 @@ where
}
}
/// Finds an element of a `type` by the given `name`.
#[cfg(feature = "alloc")]
pub trait MatchNameAndType {
/// Finds an element of a `type` by the given `name`, and returns a borrow, or [`Option::None`].
fn match_name_type<T: 'static>(&self, name: &str) -> Option<&T>;
/// Finds an element of a `type` by the given `name`, and returns a mut borrow, or [`Option::None`].
fn match_name_type_mut<T: 'static>(&mut self, name: &str) -> Option<&mut T>;
}
#[cfg(feature = "alloc")]
impl MatchNameAndType for () {
fn match_name_type<T: 'static>(&self, _name: &str) -> Option<&T> {
None
}
fn match_name_type_mut<T: 'static>(&mut self, _name: &str) -> Option<&mut T> {
None
}
}
#[cfg(feature = "alloc")]
impl<Head, Tail> MatchNameAndType for (Head, Tail)
where
Head: 'static + Named,
Tail: MatchNameAndType,
{
fn match_name_type<T: 'static>(&self, name: &str) -> Option<&T> {
// Switch this check to https://stackoverflow.com/a/60138532/7658998 when in stable and remove 'static
if TypeId::of::<T>() == TypeId::of::<Head>() && name == self.0.name() {
unsafe { (addr_of!(self.0) as *const T).as_ref() }
} else {
self.1.match_name_type::<T>(name)
}
}
fn match_name_type_mut<T: 'static>(&mut self, name: &str) -> Option<&mut T> {
// Switch this check to https://stackoverflow.com/a/60138532/7658998 when in stable and remove 'static
if TypeId::of::<T>() == TypeId::of::<Head>() && name == self.0.name() {
unsafe { (addr_of_mut!(self.0) as *mut T).as_mut() }
} else {
self.1.match_name_type_mut::<T>(name)
}
}
}
/// Structs that has `Reference `
/// You should use this when you want to avoid specifying types using `match_name_type_mut`
#[cfg(feature = "alloc")]
pub trait Referenceable: Named {
/// Return the `Reference `
fn type_ref(&self) -> Reference<Self> {
fn reference(&self) -> Reference<Self> {
Reference {
name: Named::name(self).clone(),
phantom: PhantomData,
@ -554,38 +517,141 @@ pub trait Referenceable: Named {
#[cfg(feature = "alloc")]
impl<N> Referenceable for N where N: Named {}
/// Empty object with the type T
#[derive(Debug)]
/// Object with the type T and the name associated with its concrete value
#[derive(Serialize, Deserialize)]
#[cfg(feature = "alloc")]
pub struct Reference<T: ?Sized> {
name: Cow<'static, str>,
#[serde(skip)]
phantom: PhantomData<T>,
}
#[cfg(feature = "alloc")]
impl<T: ?Sized> Reference<T> {
/// Fetch the name of the referenced instance.
///
/// We explicitly do *not* implement [`Named`], as this could potentially lead to confusion
/// where we make a [`Reference`] of a [`Reference`] as [`Named`] is blanket implemented.
#[must_use]
pub fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
#[cfg(feature = "alloc")]
impl<T> Clone for Reference<T> {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
phantom: PhantomData,
}
}
}
#[cfg(feature = "alloc")]
impl<T> Debug for Reference<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Reference")
.field("name", self.name())
.field("type", &type_name::<T>())
.finish()
}
}
/// Search using `Reference `
#[cfg(feature = "alloc")]
pub trait MatchNameRef {
/// Search using name and `Reference `
fn match_by_ref<T>(&self, rf: Reference<T>) -> Option<&T>;
fn get<T>(&self, rf: &Reference<T>) -> Option<&T>;
/// Search using name and `Reference `
fn match_by_ref_mut<T>(&mut self, rf: Reference<T>) -> Option<&mut T>;
fn get_mut<T>(&mut self, rf: &Reference<T>) -> Option<&mut T>;
}
#[cfg(feature = "alloc")]
#[allow(deprecated)]
impl<M> MatchNameRef for M
where
M: MatchName,
{
fn match_by_ref<T>(&self, rf: Reference<T>) -> Option<&T> {
fn get<T>(&self, rf: &Reference<T>) -> Option<&T> {
self.match_name::<T>(&rf.name)
}
fn match_by_ref_mut<T>(&mut self, rf: Reference<T>) -> Option<&mut T> {
fn get_mut<T>(&mut self, rf: &Reference<T>) -> Option<&mut T> {
self.match_name_mut::<T>(&rf.name)
}
}
/// A wrapper type to enable the indexing of [`MatchName`] implementors with `[]`.
#[cfg(feature = "alloc")]
#[derive(Copy, Clone, Debug)]
#[repr(transparent)]
pub struct RefIndexable<RM, M>(RM, PhantomData<M>);
#[cfg(feature = "alloc")]
impl<RM, M> From<RM> for RefIndexable<RM, M>
where
RM: Deref<Target = M>,
M: MatchName,
{
fn from(value: RM) -> Self {
RefIndexable(value, PhantomData)
}
}
#[cfg(feature = "alloc")]
impl<RM, M> Deref for RefIndexable<RM, M>
where
RM: Deref<Target = M>,
{
type Target = RM::Target;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "alloc")]
impl<RM, M> DerefMut for RefIndexable<RM, M>
where
RM: DerefMut<Target = M>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(feature = "alloc")]
impl<T, RM, M> Index<&Reference<T>> for RefIndexable<RM, M>
where
RM: Deref<Target = M>,
M: MatchName,
{
type Output = T;
fn index(&self, index: &Reference<T>) -> &Self::Output {
let Some(e) = self.get(index) else {
panic!("Could not find entry matching {index:?}")
};
e
}
}
#[cfg(feature = "alloc")]
impl<T, RM, M> IndexMut<&Reference<T>> for RefIndexable<RM, M>
where
RM: DerefMut<Target = M>,
M: MatchName,
{
fn index_mut(&mut self, index: &Reference<T>) -> &mut Self::Output {
let Some(e) = self.get_mut(index) else {
panic!("Could not find entry matching {index:?}")
};
e
}
}
/// Allows prepending of values to a tuple
pub trait Prepend<T> {
/// The Resulting [`TupleList`], of an [`Prepend::prepend()`] call,

View File

@ -22,7 +22,11 @@ use libafl::{
state::State,
Error, HasMetadata,
};
use libafl_bolts::{ownedref::OwnedPtr, Named, SerdeAny};
use libafl_bolts::{
ownedref::OwnedPtr,
tuples::{MatchNameRef, Reference, Referenceable},
Named, SerdeAny,
};
use serde::{Deserialize, Serialize};
use termcolor::{Color, ColorSpec, WriteColor};
#[cfg(target_arch = "aarch64")]
@ -39,8 +43,6 @@ use crate::{
alloc::AllocationMetadata, asan::asan_rt::ASAN_SAVE_REGISTER_COUNT, utils::disas_count,
};
static ASAN_ERRORS_NAME: Cow<'static, str> = Cow::Borrowed("AsanErrors");
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct AsanReadWriteError {
pub registers: [usize; ASAN_SAVE_REGISTER_COUNT],
@ -591,6 +593,7 @@ where
impl Named for AsanErrorsObserver {
#[inline]
fn name(&self) -> &Cow<'static, str> {
static ASAN_ERRORS_NAME: Cow<'static, str> = Cow::Borrowed("AsanErrors");
&ASAN_ERRORS_NAME
}
}
@ -643,6 +646,7 @@ impl AsanErrorsObserver {
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct AsanErrorsFeedback<S> {
errors: Option<AsanErrors>,
obs_ref: Reference<AsanErrorsObserver>,
phantom: PhantomData<S>,
}
@ -665,7 +669,7 @@ where
OT: ObserversTuple<S>,
{
let observer = observers
.match_name::<AsanErrorsObserver>(&ASAN_ERRORS_NAME)
.get(&self.obs_ref)
.expect("An AsanErrorsFeedback needs an AsanErrorsObserver");
let errors = observer.errors();
if errors.is_empty() {
@ -702,23 +706,18 @@ where
impl<S> Named for AsanErrorsFeedback<S> {
#[inline]
fn name(&self) -> &Cow<'static, str> {
&ASAN_ERRORS_NAME
self.obs_ref.name()
}
}
impl<S> AsanErrorsFeedback<S> {
/// Create a new `AsanErrorsFeedback`
#[must_use]
pub fn new() -> Self {
pub fn new(obs: &AsanErrorsObserver) -> Self {
Self {
errors: None,
obs_ref: obs.reference(),
phantom: PhantomData,
}
}
}
impl<S> Default for AsanErrorsFeedback<S> {
fn default() -> Self {
Self::new()
}
}

View File

@ -19,6 +19,7 @@ use libafl::{
state::{HasExecutions, State, UsesState},
Error,
};
use libafl_bolts::tuples::RefIndexable;
#[cfg(all(unix, not(test)))]
use crate::asan::errors::AsanErrors;
@ -145,12 +146,12 @@ where
OT: ObserversTuple<S>,
{
#[inline]
fn observers(&self) -> &OT {
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.base.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.base.observers_mut()
}
}

View File

@ -416,10 +416,15 @@ mod tests {
let mut feedback = ConstFeedback::new(false);
let asan_obs = AsanErrorsObserver::from_static_asan_errors();
// Feedbacks to recognize an input as solution
let mut objective = feedback_or_fast!(
// true enables the AsanErrorFeedback
feedback_and_fast!(ConstFeedback::from(true), AsanErrorsFeedback::new())
feedback_and_fast!(
ConstFeedback::from(true),
AsanErrorsFeedback::new(&asan_obs)
)
);
let mut state = StdState::new(
@ -436,7 +441,7 @@ mod tests {
let mut fuzzer = StdFuzzer::new(StdScheduler::new(), feedback, objective);
let observers = tuple_list!(
AsanErrorsObserver::from_static_asan_errors() //,
asan_obs //,
);
{

View File

@ -174,4 +174,4 @@ where
}
}
pub type ShrinkMapFeedback<C, O, S, T> = MinMapFeedback<C, MappedEdgeMapObserver<O, T>, S, usize>;
pub type ShrinkMapFeedback<C, O, T> = MinMapFeedback<C, MappedEdgeMapObserver<O, T>, usize>;

View File

@ -244,7 +244,7 @@ macro_rules! fuzz_with {
map_feedback,
feedback_and_fast!(ConstFeedback::new($options.shrink()), shrinking_map_feedback),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
)
);

View File

@ -11,7 +11,7 @@ use libafl::{
state::{HasExecutions, State, UsesState},
Error,
};
use libafl_bolts::AsSlice;
use libafl_bolts::{tuples::RefIndexable, AsSlice};
use libnyx::NyxReturnValue;
use crate::helper::NyxHelper;
@ -146,11 +146,11 @@ where
S: State,
OT: ObserversTuple<S>,
{
fn observers(&self) -> &OT {
&self.observers
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
RefIndexable::from(&self.observers)
}
fn observers_mut(&mut self) -> &mut OT {
&mut self.observers
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
RefIndexable::from(&mut self.observers)
}
}

View File

@ -22,9 +22,12 @@ use libafl::{
state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState},
Error, HasMetadata,
};
use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Signal};
#[cfg(feature = "fork")]
use libafl_bolts::shmem::ShMemProvider;
use libafl_bolts::{
os::unix_signals::{siginfo_t, ucontext_t, Signal},
tuples::RefIndexable,
};
use crate::{helpers::QemuHelperTuple, hooks::QemuHooks, Qemu};
@ -308,7 +311,7 @@ where
self.state.post_exec::<Self, EM, OT, OF, Z>(
input,
qemu,
self.inner.observers_mut(),
&mut *self.inner.observers_mut(),
&mut exit_kind,
);
Ok(exit_kind)
@ -343,12 +346,12 @@ where
QT: QemuHelperTuple<S>,
{
#[inline]
fn observers(&self) -> &OT {
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut()
}
}
@ -480,7 +483,7 @@ where
self.state.hooks.helpers_mut().post_exec_all(
qemu,
input,
self.inner.observers_mut(),
&mut *self.inner.observers_mut(),
&mut exit_kind,
);
Ok(exit_kind)
@ -527,12 +530,12 @@ where
Z: UsesState<State = S>,
{
#[inline]
fn observers(&self) -> &OT {
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut()
}
}

View File

@ -17,6 +17,7 @@ use libafl::{
state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState},
Error,
};
use libafl_bolts::tuples::RefIndexable;
#[cfg(emulation_mode = "usermode")]
use crate::executor::inproc_qemu_crash_handler;
@ -164,7 +165,7 @@ where
.post_exec::<Self, EM, OT, OF, Z>(
input,
qemu,
self.inner.inner.observers_mut(),
&mut *self.inner.inner.observers_mut(),
&mut exit_kind,
);
Ok(exit_kind)
@ -199,12 +200,12 @@ where
QT: QemuHelperTuple<S>,
{
#[inline]
fn observers(&self) -> &OT {
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut()
}
}

View File

@ -6,7 +6,7 @@ use libafl::{
inputs::{Input, UsesInput},
observers::{stacktrace::BacktraceObserver, ObserversTuple},
};
use libafl_bolts::{tuples::MatchFirstType, Named};
use libafl_bolts::tuples::{MatchFirstType, MatchNameRef, Reference, Referenceable};
use libafl_qemu_sys::GuestAddr;
use thread_local::ThreadLocal;
@ -21,7 +21,7 @@ use crate::{
Qemu,
};
pub trait CallTraceCollector: 'static + Debug {
pub trait CallTraceCollector: 'static {
fn on_call<QT, S>(
&mut self,
hooks: &mut QemuHooks<QT, S>,
@ -62,7 +62,7 @@ pub trait CallTraceCollector: 'static + Debug {
}
}
pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug {
pub trait CallTraceCollectorTuple: 'static + MatchFirstType {
fn on_call_all<QT, S>(
&mut self,
hooks: &mut QemuHooks<QT, S>,
@ -402,7 +402,7 @@ where
impl<S, T> QemuHelper<S> for QemuCallTracerHelper<T>
where
S: UsesInput,
T: CallTraceCollectorTuple,
T: CallTraceCollectorTuple + Debug,
{
fn init_hooks<QT>(&self, hooks: &QemuHooks<QT, S>)
where
@ -437,25 +437,17 @@ where
// TODO support multiple threads with thread local callstack
#[derive(Debug)]
pub struct OnCrashBacktraceCollector {
pub struct OnCrashBacktraceCollector<'a> {
callstack_hash: u64,
observer_name: String,
obs_ref: Reference<BacktraceObserver<'a>>,
}
impl OnCrashBacktraceCollector {
impl<'a> OnCrashBacktraceCollector<'a> {
#[must_use]
pub fn new(observer: &BacktraceObserver<'_>) -> Self {
pub fn new(observer: &BacktraceObserver<'a>) -> Self {
Self {
callstack_hash: 0,
observer_name: observer.name().to_string(),
}
}
#[must_use]
pub fn with_name(observer_name: String) -> Self {
Self {
callstack_hash: 0,
observer_name,
obs_ref: observer.reference(),
}
}
@ -469,7 +461,10 @@ impl OnCrashBacktraceCollector {
}
}
impl CallTraceCollector for OnCrashBacktraceCollector {
impl<'a> CallTraceCollector for OnCrashBacktraceCollector<'a>
where
'a: 'static,
{
#[allow(clippy::unnecessary_cast)]
fn on_call<QT, S>(
&mut self,
@ -516,7 +511,7 @@ impl CallTraceCollector for OnCrashBacktraceCollector {
S: UsesInput,
{
let observer = observers
.match_name_mut::<BacktraceObserver<'_>>(&self.observer_name)
.get_mut(&self.obs_ref)
.expect("A OnCrashBacktraceCollector needs a BacktraceObserver");
observer.fill_external(self.callstack_hash, exit_kind);
}

View File

@ -33,7 +33,7 @@ hexagon = ["libafl_qemu/hexagon"] # build qemu for hexagon
pyo3-build-config = { version = "0.18", optional = true }
[dependencies]
libafl = { path = "../libafl", version = "0.12.0" }
libafl = { path = "../libafl", version = "0.12.0", features = ["adaptive_serialization"] }
libafl_bolts = { path = "../libafl_bolts", version = "0.12.0" }
libafl_targets = { path = "../libafl_targets", version = "0.12.0" }

View File

@ -26,7 +26,7 @@ use libafl_bolts::{
current_nanos,
rands::StdRand,
shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::{tuple_list, Merge},
tuples::{tuple_list, Merge, Referenceable},
AsSliceMut,
};
use typed_builder::TypedBuilder;
@ -114,9 +114,15 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
let monitor = MultiMonitor::new(|s| log::info!("{s}"));
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
let time_ref = time_observer.reference();
let mut run_client = |state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>,
_core_id| {
let time_observer = time_observer.clone();
// Coverage map shared between target and fuzzer
let mut shmem = shmem_provider_client.new_shmem(MAP_SIZE).unwrap();
shmem.write_to_env("__AFL_SHM_ID").unwrap();
@ -131,16 +137,13 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
.track_indices()
};
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not
@ -292,7 +295,8 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
.run_client(&mut run_client)
.cores(self.cores)
.broker_port(self.broker_port)
.remote_broker_addr(self.remote_broker_addr);
.remote_broker_addr(self.remote_broker_addr)
.time_ref(time_ref);
#[cfg(unix)]
let launcher = launcher.stdout_file(Some("/dev/null"));
match launcher.build().launch() {

View File

@ -29,7 +29,7 @@ use libafl_bolts::{
current_nanos,
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
tuples::{tuple_list, Merge, Referenceable},
AsSlice,
};
use libafl_targets::{std_edges_map_observer, CmpLogObserver};
@ -138,17 +138,20 @@ where
let monitor = MultiMonitor::new(|s| println!("{s}"));
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
let time_ref = time_observer.reference();
let mut run_client = |state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>,
_core_id| {
let time_observer = time_observer.clone();
// Create an observation channel using the coverage map
let edges_observer =
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") })
.track_indices();
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
let cmplog_observer = CmpLogObserver::new("cmplog", true);
// Feedback to rate the interestingness of an input
@ -157,7 +160,7 @@ where
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not
@ -340,7 +343,8 @@ where
.run_client(&mut run_client)
.cores(self.cores)
.broker_port(self.broker_port)
.remote_broker_addr(self.remote_broker_addr);
.remote_broker_addr(self.remote_broker_addr)
.time_ref(time_ref);
#[cfg(unix)]
let launcher = launcher.stdout_file(Some("/dev/null"));
match launcher.build().launch() {

View File

@ -32,7 +32,7 @@ use libafl_bolts::{
current_nanos,
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
tuples::{tuple_list, Merge, Referenceable},
AsSlice,
};
pub use libafl_qemu::emu::Qemu;
@ -146,9 +146,15 @@ where
let monitor = MultiMonitor::new(|s| log::info!("{s}"));
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
let time_ref = time_observer.reference();
let mut run_client = |state: Option<_>,
mut mgr: LlmpRestartingEventManager<_, _, _>,
_core_id| {
let time_observer = time_observer.clone();
// Create an observation channel using the coverage map
let edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
@ -159,9 +165,6 @@ where
.track_indices()
};
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
// Keep tracks of CMPs
let cmplog_observer = CmpLogObserver::new("cmplog", true);
@ -171,7 +174,7 @@ where
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer)
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not
@ -433,9 +436,11 @@ where
.run_client(&mut run_client)
.cores(self.cores)
.broker_port(self.broker_port)
.remote_broker_addr(self.remote_broker_addr);
.remote_broker_addr(self.remote_broker_addr)
.time_ref(time_ref);
#[cfg(unix)]
let launcher = launcher.stdout_file(Some("/dev/null"));
launcher.build().launch().expect("Launcher failed");
}
}

View File

@ -65,10 +65,7 @@ struct cmp_map {
/// A [`CmpObserver`] observer for AFL++ redqueen
#[derive(Serialize, Deserialize, Debug)]
pub struct AFLppCmpLogObserver<'a, S>
where
S: UsesInput + HasMetadata,
{
pub struct AFLppCmpLogObserver<'a, S> {
cmp_map: OwnedRefMut<'a, AFLppCmpLogMap>,
size: Option<OwnedRefMut<'a, usize>>,
name: Cow<'static, str>,
@ -80,7 +77,7 @@ where
impl<'a, S> CmpObserver<'a, AFLppCmpLogMap, S, AFLppCmpValuesMetadata>
for AFLppCmpLogObserver<'a, S>
where
S: UsesInput + Debug + HasMetadata,
S: UsesInput + HasMetadata,
{
/// Get the number of usable cmps (all by default)
fn usable_count(&self) -> usize {
@ -142,7 +139,7 @@ where
impl<'a, S> Observer<S> for AFLppCmpLogObserver<'a, S>
where
S: UsesInput + Debug + HasMetadata,
S: UsesInput + HasMetadata,
{
fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
#[cfg(feature = "cmplog_extended_instrumentation")]
@ -176,19 +173,13 @@ where
}
}
impl<'a, S> Named for AFLppCmpLogObserver<'a, S>
where
S: UsesInput + HasMetadata,
{
impl<'a, S> Named for AFLppCmpLogObserver<'a, S> {
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
impl<'a, S> AFLppCmpLogObserver<'a, S>
where
S: UsesInput + HasMetadata,
{
impl<'a, S> AFLppCmpLogObserver<'a, S> {
/// Creates a new [`AFLppCmpLogObserver`] with the given name and map.
#[must_use]
pub fn new(

View File

@ -1,7 +1,4 @@
use alloc::{
borrow::Cow,
string::{String, ToString},
};
use alloc::borrow::Cow;
use core::marker::PhantomData;
#[cfg(feature = "introspection")]
@ -14,34 +11,43 @@ use libafl::{
state::{HasCorpus, HasCurrentTestcase, HasExecutions, UsesState},
Error, HasMetadata, HasNamedMetadata,
};
use libafl_bolts::{tuples::MatchName, Named};
use libafl_bolts::{
tuples::{MatchNameRef, Reference},
Named,
};
use crate::cmps::observers::AFLppCmpLogObserver;
/// Trace with tainted input
#[derive(Clone, Debug)]
pub struct AFLppCmplogTracingStage<EM, TE, Z> {
pub struct AFLppCmplogTracingStage<'a, EM, TE, Z>
where
TE: UsesState,
{
tracer_executor: TE,
cmplog_observer_name: Option<String>,
cmplog_observer_ref: Option<Reference<AFLppCmpLogObserver<'a, TE::State>>>,
#[allow(clippy::type_complexity)]
phantom: PhantomData<(EM, TE, Z)>,
}
impl<EM, TE, Z> UsesState for AFLppCmplogTracingStage<EM, TE, Z>
impl<EM, TE, Z> UsesState for AFLppCmplogTracingStage<'_, EM, TE, Z>
where
TE: UsesState,
{
type State = TE::State;
}
impl<EM, TE, Z> Named for AFLppCmplogTracingStage<EM, TE, Z> {
impl<EM, TE, Z> Named for AFLppCmplogTracingStage<'_, EM, TE, Z>
where
TE: UsesState,
{
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("AFLppCmplogTracingStage");
&NAME
}
}
impl<E, EM, TE, Z> Stage<E, EM, Z> for AFLppCmplogTracingStage<EM, TE, Z>
impl<E, EM, TE, Z> Stage<E, EM, Z> for AFLppCmplogTracingStage<'_, EM, TE, Z>
where
E: UsesState<State = TE::State>,
TE: Executor<EM, Z> + HasObservers,
@ -61,12 +67,8 @@ where
// First run with the un-mutated input
let unmutated_input = state.current_input_cloned()?;
if let Some(name) = &self.cmplog_observer_name {
if let Some(ob) = self
.tracer_executor
.observers_mut()
.match_name_mut::<AFLppCmpLogObserver<TE::State>>(name)
{
if let Some(obs_ref) = &self.cmplog_observer_ref {
if let Some(ob) = self.tracer_executor.observers_mut().get_mut(obs_ref) {
// This is not the original input,
// Set it to false
ob.set_original(true);
@ -95,12 +97,8 @@ where
None => return Err(Error::unknown("No metadata found")),
};
if let Some(name) = &self.cmplog_observer_name {
if let Some(ob) = self
.tracer_executor
.observers_mut()
.match_name_mut::<AFLppCmpLogObserver<TE::State>>(name)
{
if let Some(obs_ref) = &self.cmplog_observer_ref {
if let Some(ob) = self.tracer_executor.observers_mut().get_mut(obs_ref) {
// This is not the original input,
// Set it to false
ob.set_original(false);
@ -137,20 +135,26 @@ where
}
}
impl<EM, TE, Z> AFLppCmplogTracingStage<EM, TE, Z> {
impl<'a, EM, TE, Z> AFLppCmplogTracingStage<'a, EM, TE, Z>
where
TE: UsesState,
{
/// Creates a new default stage
pub fn new(tracer_executor: TE) -> Self {
Self {
cmplog_observer_name: None,
cmplog_observer_ref: None,
tracer_executor,
phantom: PhantomData,
}
}
/// With cmplog observer
pub fn with_cmplog_observer_name(tracer_executor: TE, name: &'static str) -> Self {
pub fn with_cmplog_observer(
tracer_executor: TE,
obs_ref: Reference<AFLppCmpLogObserver<'a, TE::State>>,
) -> Self {
Self {
cmplog_observer_name: Some(name.to_string()),
cmplog_observer_ref: Some(obs_ref),
tracer_executor,
phantom: PhantomData,
}

View File

@ -11,6 +11,7 @@ use libafl::{
use libafl_bolts::{
fs::{InputFile, INPUTFILE_STD},
shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::RefIndexable,
AsSlice, AsSliceMut,
};
use tinyinst::tinyinst::{litecov::RunResult, TinyInst};
@ -300,12 +301,12 @@ where
SP: ShMemProvider,
OT: ObserversTuple<S>,
{
fn observers(&self) -> &OT {
&self.observers
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
RefIndexable::from(&self.observers)
}
fn observers_mut(&mut self) -> &mut OT {
&mut self.observers
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
RefIndexable::from(&mut self.observers)
}
}
impl<'a, S, SP, OT> UsesState for TinyInstExecutor<'a, S, SP, OT>