Observers lifetime (#89)
* introduce MatchName and alow lifetimes in observers * adapt fuzzers to observers with lifetime * introduce type_eq when on nightly * fix no_std * fmt
This commit is contained in:
parent
08a32c3856
commit
bfa3fffc18
@ -46,9 +46,8 @@ pub fn main() {
|
|||||||
// such as the notification of the addition of a new item to the corpus
|
// such as the notification of the addition of a new item to the corpus
|
||||||
let mut mgr = SimpleEventManager::new(stats);
|
let mut mgr = SimpleEventManager::new(stats);
|
||||||
|
|
||||||
// Create an observation channel using the siganls map
|
// Create an observation channel using the signals map
|
||||||
let observer =
|
let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS });
|
||||||
StdMapObserver::new("signals", unsafe { &mut SIGNALS }, unsafe { SIGNALS.len() });
|
|
||||||
|
|
||||||
// create a State from scratch
|
// create a State from scratch
|
||||||
let mut state = State::new(
|
let mut state = State::new(
|
||||||
@ -76,13 +75,9 @@ pub fn main() {
|
|||||||
let scheduler = QueueCorpusScheduler::new();
|
let scheduler = QueueCorpusScheduler::new();
|
||||||
|
|
||||||
// Create the executor for an in-process function with just one observer
|
// Create the executor for an in-process function with just one observer
|
||||||
let mut executor = InProcessExecutor::new(
|
let mut executor =
|
||||||
&mut harness,
|
InProcessExecutor::new(&mut harness, tuple_list!(observer), &mut state, &mut mgr)
|
||||||
tuple_list!(observer),
|
.expect("Failed to create the Executor".into());
|
||||||
&mut state,
|
|
||||||
&mut mgr,
|
|
||||||
)
|
|
||||||
.expect("Failed to create the Executor".into());
|
|
||||||
|
|
||||||
// Generator of printable bytearrays of max size 32
|
// Generator of printable bytearrays of max size 32
|
||||||
let mut generator = RandPrintablesGenerator::new(32);
|
let mut generator = RandPrintablesGenerator::new(32);
|
||||||
|
@ -258,12 +258,8 @@ unsafe fn fuzz(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let frida_options = FridaOptions::parse_env_options();
|
let frida_options = FridaOptions::parse_env_options();
|
||||||
let mut frida_helper = FridaInstrumentationHelper::new(
|
let mut frida_helper =
|
||||||
&gum,
|
FridaInstrumentationHelper::new(&gum, &frida_options, module_name, &modules_to_instrument);
|
||||||
&frida_options,
|
|
||||||
module_name,
|
|
||||||
&modules_to_instrument,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new_from_ptr(
|
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new_from_ptr(
|
||||||
|
@ -22,7 +22,7 @@ use libafl::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use libafl_targets::{
|
use libafl_targets::{
|
||||||
libfuzzer_initialize, libfuzzer_test_one_input, CMP_MAP, CMP_MAP_SIZE, EDGES_MAP, MAX_EDGES_NUM,
|
libfuzzer_initialize, libfuzzer_test_one_input, CMP_MAP, EDGES_MAP, MAX_EDGES_NUM,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ALLOC_MAP_SIZE: usize = 16 * 1024;
|
const ALLOC_MAP_SIZE: usize = 16 * 1024;
|
||||||
@ -59,15 +59,14 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
setup_restarting_mgr_std(stats, broker_port).expect("Failed to setup the restarter".into());
|
setup_restarting_mgr_std(stats, broker_port).expect("Failed to setup the restarter".into());
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
let edges_observer =
|
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };
|
||||||
StdMapObserver::new("edges", unsafe { &mut EDGES_MAP }, unsafe { MAX_EDGES_NUM });
|
let edges_observer = StdMapObserver::new("edges", edges);
|
||||||
|
|
||||||
// Create an observation channel using the cmp map
|
// Create an observation channel using the cmp map
|
||||||
let cmps_observer = StdMapObserver::new("cmps", unsafe { &mut CMP_MAP }, CMP_MAP_SIZE);
|
let cmps_observer = StdMapObserver::new("cmps", unsafe { &mut CMP_MAP });
|
||||||
|
|
||||||
// Create an observation channel using the allocations map
|
// Create an observation channel using the allocations map
|
||||||
let allocs_observer =
|
let allocs_observer = StdMapObserver::new("allocs", unsafe { &mut libafl_alloc_map });
|
||||||
StdMapObserver::new("allocs", unsafe { &mut libafl_alloc_map }, ALLOC_MAP_SIZE);
|
|
||||||
|
|
||||||
// If not restarting, create a State from scratch
|
// If not restarting, create a State from scratch
|
||||||
let mut state = state.unwrap_or_else(|| {
|
let mut state = state.unwrap_or_else(|| {
|
||||||
|
@ -63,11 +63,13 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
let edges_observer = HitcountsMapObserver::new(unsafe {
|
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };
|
||||||
StdMapObserver::new("edges", &mut EDGES_MAP, MAX_EDGES_NUM)
|
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges));
|
||||||
});
|
|
||||||
|
// Create an observation channel to keep track of the execution time
|
||||||
|
let time_observer = TimeObserver::new("time");
|
||||||
|
|
||||||
// If not restarting, create a State from scratch
|
// If not restarting, create a State from scratch
|
||||||
let mut state = state.unwrap_or_else(|| {
|
let mut state = state.unwrap_or_else(|| {
|
||||||
@ -79,7 +81,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
// Feedbacks to rate the interestingness of an input
|
// Feedbacks to rate the interestingness of an input
|
||||||
feedback_or!(
|
feedback_or!(
|
||||||
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
||||||
TimeFeedback::new()
|
TimeFeedback::new_with_observer(&time_observer)
|
||||||
),
|
),
|
||||||
// Corpus in which we store solutions (crashes in this example),
|
// Corpus in which we store solutions (crashes in this example),
|
||||||
// on disk so the user can get them after stopping the fuzzer
|
// on disk so the user can get them after stopping the fuzzer
|
||||||
@ -122,7 +124,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = TimeoutExecutor::new(
|
||||||
InProcessExecutor::new(
|
InProcessExecutor::new(
|
||||||
&mut harness,
|
&mut harness,
|
||||||
tuple_list!(edges_observer, TimeObserver::new("time")),
|
tuple_list!(edges_observer, time_observer),
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut restarting_mgr,
|
&mut restarting_mgr,
|
||||||
)?,
|
)?,
|
||||||
|
@ -1,38 +1,28 @@
|
|||||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||||
//! The example harness is built for libpng.
|
//! The example harness is built for libpng.
|
||||||
|
|
||||||
use core::time::Duration;
|
|
||||||
use std::{env, path::PathBuf};
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
bolts::tuples::tuple_list,
|
bolts::tuples::tuple_list,
|
||||||
corpus::{
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
|
||||||
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
|
|
||||||
QueueCorpusScheduler,
|
|
||||||
},
|
|
||||||
events::{setup_restarting_mgr_std, EventManager},
|
events::{setup_restarting_mgr_std, EventManager},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or,
|
feedbacks::{MaxMapFeedback, ReachabilityFeedback},
|
||||||
feedbacks::{
|
|
||||||
CrashFeedback, MaxMapFeedback, ReachabilityFeedback, TimeFeedback, TimeoutFeedback,
|
|
||||||
},
|
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||||
mutators::token_mutations::Tokens,
|
mutators::token_mutations::Tokens,
|
||||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
observers::{HitcountsMapObserver, StdMapObserver},
|
||||||
stages::mutational::StdMutationalStage,
|
stages::mutational::StdMutationalStage,
|
||||||
state::{HasCorpus, HasMetadata, State},
|
state::{HasCorpus, HasMetadata, State},
|
||||||
stats::SimpleStats,
|
stats::SimpleStats,
|
||||||
utils::{current_nanos, StdRand},
|
utils::{current_nanos, StdRand},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
|
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
const TARGET_SIZE: usize = 4;
|
const TARGET_SIZE: usize = 4;
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static __libafl_target_list: *mut usize;
|
static __libafl_target_list: *mut usize;
|
||||||
}
|
}
|
||||||
@ -75,12 +65,12 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
let edges_observer = HitcountsMapObserver::new(unsafe {
|
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };
|
||||||
StdMapObserver::new("edges", &mut EDGES_MAP, MAX_EDGES_NUM)
|
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges));
|
||||||
});
|
|
||||||
|
|
||||||
let reachability_observer =
|
let reachability_observer =
|
||||||
unsafe { StdMapObserver::new_from_ptr("png.c", __libafl_target_list, TARGET_SIZE) };
|
unsafe { StdMapObserver::new_from_ptr("png.c", __libafl_target_list, TARGET_SIZE) };
|
||||||
|
|
||||||
// If not restarting, create a State from scratch
|
// If not restarting, create a State from scratch
|
||||||
let mut state = state.unwrap_or_else(|| {
|
let mut state = state.unwrap_or_else(|| {
|
||||||
State::new(
|
State::new(
|
||||||
@ -89,19 +79,12 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
// Corpus that will be evolved, we keep it in memory for performance
|
// Corpus that will be evolved, we keep it in memory for performance
|
||||||
InMemoryCorpus::new(),
|
InMemoryCorpus::new(),
|
||||||
// Feedbacks to rate the interestingness of an input
|
// Feedbacks to rate the interestingness of an input
|
||||||
feedback_or!(
|
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
||||||
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
|
||||||
TimeFeedback::new()
|
|
||||||
),
|
|
||||||
// Corpus in which we store solutions (crashes in this example),
|
// Corpus in which we store solutions (crashes in this example),
|
||||||
// on disk so the user can get them after stopping the fuzzer
|
// on disk so the user can get them after stopping the fuzzer
|
||||||
OnDiskCorpus::new(objective_dir).unwrap(),
|
OnDiskCorpus::new(objective_dir).unwrap(),
|
||||||
// Feedbacks to recognize an input as solution
|
// Feedbacks to recognize an input as solution
|
||||||
feedback_or!(
|
ReachabilityFeedback::new_with_observer(&reachability_observer),
|
||||||
CrashFeedback::new(),
|
|
||||||
TimeoutFeedback::new(),
|
|
||||||
ReachabilityFeedback::new_with_observer(&reachability_observer)
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -125,8 +108,8 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
// A fuzzer with just one stage
|
// A fuzzer with just one stage
|
||||||
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
|
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
|
||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A random policy to get testcasess from the corpus
|
||||||
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
let scheduler = RandCorpusScheduler::new();
|
||||||
|
|
||||||
// The wrapped harness function, calling out to the LLVM-style harness
|
// The wrapped harness function, calling out to the LLVM-style harness
|
||||||
let mut harness = |buf: &[u8]| {
|
let mut harness = |buf: &[u8]| {
|
||||||
@ -135,20 +118,12 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::new(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, reachability_observer,),
|
||||||
tuple_list!(
|
&mut state,
|
||||||
edges_observer,
|
&mut restarting_mgr,
|
||||||
reachability_observer,
|
)?;
|
||||||
TimeObserver::new("time")
|
|
||||||
),
|
|
||||||
&mut state,
|
|
||||||
&mut restarting_mgr,
|
|
||||||
)?,
|
|
||||||
// 10 seconds timeout
|
|
||||||
Duration::new(10, 0),
|
|
||||||
);
|
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
// Call LLVMFUzzerInitialize() if present.
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
@ -63,8 +63,11 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
|
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
|
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
|
||||||
let edges_observer =
|
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };
|
||||||
StdMapObserver::new("edges", unsafe { &mut EDGES_MAP }, unsafe { MAX_EDGES_NUM });
|
let edges_observer = StdMapObserver::new("edges", edges);
|
||||||
|
|
||||||
|
// Create an observation channel to keep track of the execution time
|
||||||
|
let time_observer = TimeObserver::new("time");
|
||||||
|
|
||||||
// If not restarting, create a State from scratch
|
// If not restarting, create a State from scratch
|
||||||
let mut state = state.unwrap_or_else(|| {
|
let mut state = state.unwrap_or_else(|| {
|
||||||
@ -76,7 +79,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
// Feedbacks to rate the interestingness of an input
|
// Feedbacks to rate the interestingness of an input
|
||||||
feedback_or!(
|
feedback_or!(
|
||||||
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
||||||
TimeFeedback::new()
|
TimeFeedback::new_with_observer(&time_observer)
|
||||||
),
|
),
|
||||||
// Corpus in which we store solutions (crashes in this example),
|
// Corpus in which we store solutions (crashes in this example),
|
||||||
// on disk so the user can get them after stopping the fuzzer
|
// on disk so the user can get them after stopping the fuzzer
|
||||||
@ -118,7 +121,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
|||||||
// Create the executor for an in-process function with just one observer for edge coverage
|
// Create the executor for an in-process function with just one observer for edge coverage
|
||||||
let mut executor = InProcessExecutor::new(
|
let mut executor = InProcessExecutor::new(
|
||||||
&mut harness,
|
&mut harness,
|
||||||
tuple_list!(edges_observer, TimeObserver::new("time")),
|
tuple_list!(edges_observer, time_observer),
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut restarting_mgr,
|
&mut restarting_mgr,
|
||||||
)?;
|
)?;
|
||||||
|
@ -10,7 +10,8 @@ keywords = ["fuzzing", "testing", "security"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
[build-dependencies]
|
||||||
|
rustc_version = "0.3.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = "0.3" # Benchmarking
|
criterion = "0.3" # Benchmarking
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
//! special handling to build and link libafl
|
//! special handling to build and link libafl
|
||||||
|
|
||||||
|
use rustc_version::{version_meta, Channel};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
windows::build!(
|
windows::build!(
|
||||||
@ -9,4 +11,20 @@ fn main() {
|
|||||||
windows::win32::system_services::{CreateFileMappingA, OpenFileMappingA, MapViewOfFile, UnmapViewOfFile},
|
windows::win32::system_services::{CreateFileMappingA, OpenFileMappingA, MapViewOfFile, UnmapViewOfFile},
|
||||||
windows::win32::debug::{SetUnhandledExceptionFilter, EXCEPTION_POINTERS, EXCEPTION_RECORD, LPTOP_LEVEL_EXCEPTION_FILTER}
|
windows::win32::debug::{SetUnhandledExceptionFilter, EXCEPTION_POINTERS, EXCEPTION_RECORD, LPTOP_LEVEL_EXCEPTION_FILTER}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Set cfg flags depending on release channel
|
||||||
|
match version_meta().unwrap().channel {
|
||||||
|
Channel::Stable => {
|
||||||
|
println!("cargo:rustc-cfg=RUSTC_IS_STABLE");
|
||||||
|
}
|
||||||
|
Channel::Beta => {
|
||||||
|
println!("cargo:rustc-cfg=RUSTC_IS_BETA");
|
||||||
|
}
|
||||||
|
Channel::Nightly => {
|
||||||
|
println!("cargo:rustc-cfg=RUSTC_IS_NIGHTLY");
|
||||||
|
}
|
||||||
|
Channel::Dev => {
|
||||||
|
println!("cargo:rustc-cfg=RUSTC_IS_DEV");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,34 @@ use core::any::TypeId;
|
|||||||
|
|
||||||
use xxhash_rust::const_xxh3::xxh3_64;
|
use xxhash_rust::const_xxh3::xxh3_64;
|
||||||
|
|
||||||
|
#[cfg(feature = "RUSTC_IS_NIGHTLY")]
|
||||||
|
/// From https://stackoverflow.com/a/60138532/7658998
|
||||||
|
const fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
|
||||||
|
// Helper trait. `VALUE` is false, except for the specialization of the
|
||||||
|
// case where `T == U`.
|
||||||
|
trait TypeEq<U: ?Sized> {
|
||||||
|
const VALUE: bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default implementation.
|
||||||
|
impl<T: ?Sized, U: ?Sized> TypeEq<U> for T {
|
||||||
|
default const VALUE: bool = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specialization for `T == U`.
|
||||||
|
impl<T: ?Sized> TypeEq<T> for T {
|
||||||
|
const VALUE: bool = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
<T as TypeEq<U>>::VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "RUSTC_IS_NIGHTLY"))]
|
||||||
|
const fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
|
||||||
|
// BEWARE! This is not unsafe, it is SUPER UNSAFE
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
pub trait HasLen {
|
pub trait HasLen {
|
||||||
const LEN: usize;
|
const LEN: usize;
|
||||||
|
|
||||||
@ -60,7 +88,7 @@ impl HasNameIdTuple for () {
|
|||||||
|
|
||||||
impl<Head, Tail> HasNameIdTuple for (Head, Tail)
|
impl<Head, Tail> HasNameIdTuple for (Head, Tail)
|
||||||
where
|
where
|
||||||
Head: 'static + HasNameId,
|
Head: HasNameId,
|
||||||
Tail: HasNameIdTuple,
|
Tail: HasNameIdTuple,
|
||||||
{
|
{
|
||||||
fn get_const_name(&self, index: usize) -> Option<&'static str> {
|
fn get_const_name(&self, index: usize) -> Option<&'static str> {
|
||||||
@ -132,6 +160,7 @@ where
|
|||||||
Tail: MatchType,
|
Tail: MatchType,
|
||||||
{
|
{
|
||||||
fn match_type<T: 'static>(&self, f: fn(t: &T)) {
|
fn match_type<T: 'static>(&self, f: fn(t: &T)) {
|
||||||
|
// Switch this check to https://stackoverflow.com/a/60138532/7658998 when in stable and remove 'static
|
||||||
if TypeId::of::<T>() == TypeId::of::<Head>() {
|
if TypeId::of::<T>() == TypeId::of::<Head>() {
|
||||||
f(unsafe { (&self.0 as *const _ as *const T).as_ref() }.unwrap());
|
f(unsafe { (&self.0 as *const _ as *const T).as_ref() }.unwrap());
|
||||||
}
|
}
|
||||||
@ -139,6 +168,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn match_type_mut<T: 'static>(&mut self, f: fn(t: &mut T)) {
|
fn match_type_mut<T: 'static>(&mut self, f: fn(t: &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>() {
|
if TypeId::of::<T>() == TypeId::of::<Head>() {
|
||||||
f(unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }.unwrap());
|
f(unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }.unwrap());
|
||||||
}
|
}
|
||||||
@ -164,7 +194,7 @@ impl NamedTuple for () {
|
|||||||
|
|
||||||
impl<Head, Tail> NamedTuple for (Head, Tail)
|
impl<Head, Tail> NamedTuple for (Head, Tail)
|
||||||
where
|
where
|
||||||
Head: 'static + Named,
|
Head: Named,
|
||||||
Tail: NamedTuple,
|
Tail: NamedTuple,
|
||||||
{
|
{
|
||||||
fn get_name(&self, index: usize) -> Option<&str> {
|
fn get_name(&self, index: usize) -> Option<&str> {
|
||||||
@ -176,6 +206,43 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This operation is unsafe with Rust stable, wait for https://stackoverflow.com/a/60138532/7658998
|
||||||
|
pub trait MatchName {
|
||||||
|
fn match_name<T>(&self, name: &str) -> Option<&T>;
|
||||||
|
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MatchName for () {
|
||||||
|
fn match_name<T>(&self, _name: &str) -> Option<&T> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn match_name_mut<T>(&mut self, _name: &str) -> Option<&mut T> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Head, Tail> MatchName for (Head, Tail)
|
||||||
|
where
|
||||||
|
Head: Named,
|
||||||
|
Tail: MatchName,
|
||||||
|
{
|
||||||
|
fn match_name<T>(&self, name: &str) -> Option<&T> {
|
||||||
|
if type_eq::<Head, T>() && name == self.0.name() {
|
||||||
|
unsafe { (&self.0 as *const _ as *const T).as_ref() }
|
||||||
|
} else {
|
||||||
|
self.1.match_name::<T>(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T> {
|
||||||
|
if type_eq::<Head, T>() && name == self.0.name() {
|
||||||
|
unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }
|
||||||
|
} else {
|
||||||
|
self.1.match_name_mut::<T>(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait MatchNameAndType {
|
pub trait MatchNameAndType {
|
||||||
fn match_name_type<T: 'static>(&self, name: &str) -> Option<&T>;
|
fn match_name_type<T: 'static>(&self, name: &str) -> Option<&T>;
|
||||||
fn match_name_type_mut<T: 'static>(&mut self, name: &str) -> Option<&mut T>;
|
fn match_name_type_mut<T: 'static>(&mut self, name: &str) -> Option<&mut T>;
|
||||||
@ -196,6 +263,7 @@ where
|
|||||||
Tail: MatchNameAndType,
|
Tail: MatchNameAndType,
|
||||||
{
|
{
|
||||||
fn match_name_type<T: 'static>(&self, name: &str) -> Option<&T> {
|
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() {
|
if TypeId::of::<T>() == TypeId::of::<Head>() && name == self.0.name() {
|
||||||
unsafe { (&self.0 as *const _ as *const T).as_ref() }
|
unsafe { (&self.0 as *const _ as *const T).as_ref() }
|
||||||
} else {
|
} else {
|
||||||
@ -204,6 +272,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn match_name_type_mut<T: 'static>(&mut self, name: &str) -> Option<&mut T> {
|
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() {
|
if TypeId::of::<T>() == TypeId::of::<Head>() && name == self.0.name() {
|
||||||
unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }
|
unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }
|
||||||
} else {
|
} else {
|
||||||
|
@ -247,7 +247,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_event_serde() {
|
fn test_event_serde() {
|
||||||
let obv = StdMapObserver::new("test", unsafe { &mut MAP }, unsafe { MAP.len() });
|
let obv = StdMapObserver::new("test", unsafe { &mut MAP });
|
||||||
let map = tuple_list!(obv);
|
let map = tuple_list!(obv);
|
||||||
let observers_buf = postcard::to_allocvec(&map).unwrap();
|
let observers_buf = postcard::to_allocvec(&map).unwrap();
|
||||||
|
|
||||||
|
@ -144,8 +144,8 @@ where
|
|||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
let mut interesting = false;
|
let mut interesting = false;
|
||||||
// TODO optimize
|
// TODO Replace with match_name_type when stable
|
||||||
let observer = observers.match_name_type::<O>(&self.name).unwrap();
|
let observer = observers.match_name::<O>(&self.name).unwrap();
|
||||||
let size = observer.usable_count();
|
let size = observer.usable_count();
|
||||||
let initial = observer.initial();
|
let initial = observer.initial();
|
||||||
|
|
||||||
@ -359,7 +359,8 @@ where
|
|||||||
observers: &OT,
|
observers: &OT,
|
||||||
_exit_kind: &ExitKind,
|
_exit_kind: &ExitKind,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
let observer = observers.match_name_type::<O>(&self.name).unwrap();
|
// TODO Replace with match_name_type when stable
|
||||||
|
let observer = observers.match_name::<O>(&self.name).unwrap();
|
||||||
let size = observer.usable_count();
|
let size = observer.usable_count();
|
||||||
let mut hit_target: bool = false;
|
let mut hit_target: bool = false;
|
||||||
//check if we've hit any targets.
|
//check if we've hit any targets.
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
pub mod map;
|
pub mod map;
|
||||||
pub use map::*;
|
pub use map::*;
|
||||||
|
|
||||||
|
use alloc::string::{String, ToString};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -409,6 +410,7 @@ impl Default for TimeoutFeedback {
|
|||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct TimeFeedback {
|
pub struct TimeFeedback {
|
||||||
exec_time: Option<Duration>,
|
exec_time: Option<Duration>,
|
||||||
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Feedback<I> for TimeFeedback
|
impl<I> Feedback<I> for TimeFeedback
|
||||||
@ -424,7 +426,8 @@ where
|
|||||||
where
|
where
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
let observer = observers.match_first_type::<TimeObserver>().unwrap();
|
// TODO Replace with match_name_type when stable
|
||||||
|
let observer = observers.match_name::<TimeObserver>(self.name()).unwrap();
|
||||||
self.exec_time = *observer.last_runtime();
|
self.exec_time = *observer.last_runtime();
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
@ -448,18 +451,22 @@ where
|
|||||||
impl Named for TimeFeedback {
|
impl Named for TimeFeedback {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"TimeFeedback"
|
self.name.as_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimeFeedback {
|
impl TimeFeedback {
|
||||||
pub fn new() -> Self {
|
pub fn new(name: &'static str) -> Self {
|
||||||
Self { exec_time: None }
|
Self {
|
||||||
|
exec_time: None,
|
||||||
|
name: name.to_string(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for TimeFeedback {
|
pub fn new_with_observer(observer: &TimeObserver) -> Self {
|
||||||
fn default() -> Self {
|
Self {
|
||||||
Self::new()
|
exec_time: None,
|
||||||
|
name: observer.name().to_string(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ Welcome to libAFL
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
#![cfg_attr(feature = "RUSTC_IS_NIGHTLY", feature(specialization))]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
@ -4,11 +4,12 @@ use alloc::{
|
|||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
use core::slice::from_raw_parts_mut;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{
|
bolts::{
|
||||||
ownedref::{OwnedArrayPtrMut, OwnedPtr},
|
ownedref::{OwnedRefMut, OwnedSliceMut},
|
||||||
tuples::Named,
|
tuples::Named,
|
||||||
},
|
},
|
||||||
executors::HasExecHooks,
|
executors::HasExecHooks,
|
||||||
@ -57,24 +58,24 @@ where
|
|||||||
/// The Map Observer retrieves the state of a map,
|
/// The Map Observer retrieves the state of a map,
|
||||||
/// that will get updated by the target.
|
/// that will get updated by the target.
|
||||||
/// A well-known example is the AFL-Style coverage map.
|
/// A well-known example is the AFL-Style coverage map.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||||
#[allow(clippy::unsafe_derive_deserialize)]
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
pub struct StdMapObserver<T>
|
pub struct StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
map: OwnedArrayPtrMut<T>,
|
map: OwnedSliceMut<'a, T>,
|
||||||
initial: T,
|
initial: T,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Observer for StdMapObserver<T> where
|
impl<'a, T> Observer for StdMapObserver<'a, T> where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EM, I, S, T> HasExecHooks<EM, I, S> for StdMapObserver<T>
|
impl<'a, EM, I, S, T> HasExecHooks<EM, I, S> for StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
Self: MapObserver<T>,
|
Self: MapObserver<T>,
|
||||||
@ -85,7 +86,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Named for StdMapObserver<T>
|
impl<'a, T> Named for StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
@ -95,7 +96,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> MapObserver<T> for StdMapObserver<T>
|
impl<'a, T> MapObserver<T> for StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
@ -125,16 +126,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> StdMapObserver<T>
|
impl<'a, T> StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
/// Creates a new MapObserver
|
/// Creates a new MapObserver
|
||||||
pub fn new(name: &'static str, map: &'static mut [T], len: usize) -> Self {
|
pub fn new(name: &'static str, map: &'a mut [T]) -> Self {
|
||||||
assert!(map.len() >= len);
|
|
||||||
let initial = if map.is_empty() { T::default() } else { map[0] };
|
let initial = if map.is_empty() { T::default() } else { map[0] };
|
||||||
Self {
|
Self {
|
||||||
map: OwnedArrayPtrMut::ArrayPtr((map.as_mut_ptr(), len)),
|
map: OwnedSliceMut::Ref(map),
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
initial,
|
initial,
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ where
|
|||||||
pub fn new_owned(name: &'static str, map: Vec<T>) -> Self {
|
pub fn new_owned(name: &'static str, map: Vec<T>) -> Self {
|
||||||
let initial = if map.is_empty() { T::default() } else { map[0] };
|
let initial = if map.is_empty() { T::default() } else { map[0] };
|
||||||
Self {
|
Self {
|
||||||
map: OwnedArrayPtrMut::Owned(map),
|
map: OwnedSliceMut::Owned(map),
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
initial,
|
initial,
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ where
|
|||||||
pub unsafe fn new_from_ptr(name: &'static str, map_ptr: *mut T, len: usize) -> Self {
|
pub unsafe fn new_from_ptr(name: &'static str, map_ptr: *mut T, len: usize) -> Self {
|
||||||
let initial = if len > 0 { *map_ptr } else { T::default() };
|
let initial = if len > 0 { *map_ptr } else { T::default() };
|
||||||
StdMapObserver {
|
StdMapObserver {
|
||||||
map: OwnedArrayPtrMut::ArrayPtr((map_ptr, len)),
|
map: OwnedSliceMut::Ref(from_raw_parts_mut(map_ptr, len)),
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
initial,
|
initial,
|
||||||
}
|
}
|
||||||
@ -164,25 +164,25 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Overlooking a variable bitmap
|
/// Overlooking a variable bitmap
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||||
#[allow(clippy::unsafe_derive_deserialize)]
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
pub struct VariableMapObserver<T>
|
pub struct VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
map: OwnedArrayPtrMut<T>,
|
map: OwnedSliceMut<'a, T>,
|
||||||
size: OwnedPtr<usize>,
|
size: OwnedRefMut<'a, usize>,
|
||||||
initial: T,
|
initial: T,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Observer for VariableMapObserver<T> where
|
impl<'a, T> Observer for VariableMapObserver<'a, T> where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EM, I, S, T> HasExecHooks<EM, I, S> for VariableMapObserver<T>
|
impl<'a, EM, I, S, T> HasExecHooks<EM, I, S> for VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
@ -192,7 +192,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Named for VariableMapObserver<T>
|
impl<'a, T> Named for VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
@ -202,7 +202,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> MapObserver<T> for VariableMapObserver<T>
|
impl<'a, T> MapObserver<T> for VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
@ -237,16 +237,16 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> VariableMapObserver<T>
|
impl<'a, T> VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
/// Creates a new MapObserver
|
/// Creates a new MapObserver
|
||||||
pub fn new(name: &'static str, map: &'static mut [T], size: *const usize) -> Self {
|
pub fn new(name: &'static str, map: &'a mut [T], size: &'a mut usize) -> Self {
|
||||||
let initial = if map.is_empty() { T::default() } else { map[0] };
|
let initial = if map.is_empty() { T::default() } else { map[0] };
|
||||||
Self {
|
Self {
|
||||||
map: OwnedArrayPtrMut::ArrayPtr((map.as_mut_ptr(), map.len())),
|
map: OwnedSliceMut::Ref(map),
|
||||||
size: OwnedPtr::Ptr(size),
|
size: OwnedRefMut::Ref(size),
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
initial,
|
initial,
|
||||||
}
|
}
|
||||||
@ -254,17 +254,17 @@ where
|
|||||||
|
|
||||||
/// Creates a new MapObserver from a raw pointer
|
/// Creates a new MapObserver from a raw pointer
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// Dereferences map_ptr with up to max_len elements of size_ptr.
|
/// Dereferences map_ptr with up to max_len elements of size.
|
||||||
pub unsafe fn new_from_ptr(
|
pub unsafe fn new_from_ptr(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
map_ptr: *mut T,
|
map_ptr: *mut T,
|
||||||
max_len: usize,
|
max_len: usize,
|
||||||
size_ptr: *const usize,
|
size: &'a mut usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let initial = if max_len > 0 { *map_ptr } else { T::default() };
|
let initial = if max_len > 0 { *map_ptr } else { T::default() };
|
||||||
VariableMapObserver {
|
VariableMapObserver {
|
||||||
map: OwnedArrayPtrMut::ArrayPtr((map_ptr, max_len)),
|
map: OwnedSliceMut::Ref(from_raw_parts_mut(map_ptr, max_len)),
|
||||||
size: OwnedPtr::Ptr(size_ptr),
|
size: OwnedRefMut::Ref(size),
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
initial,
|
initial,
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use core::time::Duration;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::tuples::{MatchFirstType, MatchNameAndType, MatchType, Named},
|
bolts::tuples::{MatchName, Named},
|
||||||
executors::HasExecHooks,
|
executors::HasExecHooks,
|
||||||
utils::current_time,
|
utils::current_time,
|
||||||
Error,
|
Error,
|
||||||
@ -16,7 +16,7 @@ use crate::{
|
|||||||
|
|
||||||
/// Observers observe different information about the target.
|
/// Observers observe different information about the target.
|
||||||
/// They can then be used by various sorts of feedback.
|
/// They can then be used by various sorts of feedback.
|
||||||
pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'static {
|
pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned {
|
||||||
/// The testcase finished execution, calculate any changes.
|
/// The testcase finished execution, calculate any changes.
|
||||||
/// Reserved for future use.
|
/// Reserved for future use.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -26,10 +26,7 @@ pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'st
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A haskell-style tuple of observers
|
/// A haskell-style tuple of observers
|
||||||
pub trait ObserversTuple:
|
pub trait ObserversTuple: MatchName + serde::Serialize + serde::de::DeserializeOwned {}
|
||||||
MatchNameAndType + MatchType + MatchFirstType + serde::Serialize + serde::de::DeserializeOwned
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObserversTuple for () {}
|
impl ObserversTuple for () {}
|
||||||
|
|
||||||
@ -99,7 +96,7 @@ mod tests {
|
|||||||
fn test_observer_serde() {
|
fn test_observer_serde() {
|
||||||
let obv = tuple_list!(
|
let obv = tuple_list!(
|
||||||
TimeObserver::new("time"),
|
TimeObserver::new("time"),
|
||||||
StdMapObserver::new("map", unsafe { &mut MAP }, unsafe { MAP.len() })
|
StdMapObserver::new("map", unsafe { &mut MAP })
|
||||||
);
|
);
|
||||||
let vec = postcard::to_allocvec(&obv).unwrap();
|
let vec = postcard::to_allocvec(&obv).unwrap();
|
||||||
println!("{:?}", vec);
|
println!("{:?}", vec);
|
||||||
|
@ -1663,7 +1663,7 @@ impl<EM, I, S> HasExecHooks<EM, I, S> for AsanErrorsObserver {
|
|||||||
impl Named for AsanErrorsObserver {
|
impl Named for AsanErrorsObserver {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"AsanErrorsObserver"
|
"AsanErrors"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1710,7 +1710,7 @@ where
|
|||||||
_exit_kind: &ExitKind,
|
_exit_kind: &ExitKind,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
let observer = observers
|
let observer = observers
|
||||||
.match_first_type::<AsanErrorsObserver>()
|
.match_name::<AsanErrorsObserver>("AsanErrors")
|
||||||
.expect("An AsanErrorsFeedback needs an AsanErrorsObserver");
|
.expect("An AsanErrorsFeedback needs an AsanErrorsObserver");
|
||||||
match observer.errors() {
|
match observer.errors() {
|
||||||
None => Ok(false),
|
None => Ok(false),
|
||||||
@ -1742,7 +1742,7 @@ where
|
|||||||
impl Named for AsanErrorsFeedback {
|
impl Named for AsanErrorsFeedback {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"AsanErrorsFeedback"
|
"AsanErrors"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user