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:
Andrea Fioraldi 2021-05-05 15:38:24 +02:00
parent 08a32c3856
commit bfa3fffc18
16 changed files with 193 additions and 129 deletions

View File

@ -46,9 +46,8 @@ pub fn main() {
// such as the notification of the addition of a new item to the corpus
let mut mgr = SimpleEventManager::new(stats);
// Create an observation channel using the siganls map
let observer =
StdMapObserver::new("signals", unsafe { &mut SIGNALS }, unsafe { SIGNALS.len() });
// Create an observation channel using the signals map
let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS });
// create a State from scratch
let mut state = State::new(
@ -76,12 +75,8 @@ pub fn main() {
let scheduler = QueueCorpusScheduler::new();
// Create the executor for an in-process function with just one observer
let mut executor = InProcessExecutor::new(
&mut harness,
tuple_list!(observer),
&mut state,
&mut mgr,
)
let mut executor =
InProcessExecutor::new(&mut harness, tuple_list!(observer), &mut state, &mut mgr)
.expect("Failed to create the Executor".into());
// Generator of printable bytearrays of max size 32

View File

@ -258,12 +258,8 @@ unsafe fn fuzz(
};
let frida_options = FridaOptions::parse_env_options();
let mut frida_helper = FridaInstrumentationHelper::new(
&gum,
&frida_options,
module_name,
&modules_to_instrument,
);
let mut frida_helper =
FridaInstrumentationHelper::new(&gum, &frida_options, module_name, &modules_to_instrument);
// Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new_from_ptr(

View File

@ -22,7 +22,7 @@ use libafl::{
};
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;
@ -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());
// Create an observation channel using the coverage map
let edges_observer =
StdMapObserver::new("edges", unsafe { &mut EDGES_MAP }, unsafe { MAX_EDGES_NUM });
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };
let edges_observer = StdMapObserver::new("edges", edges);
// 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
let allocs_observer =
StdMapObserver::new("allocs", unsafe { &mut libafl_alloc_map }, ALLOC_MAP_SIZE);
let allocs_observer = StdMapObserver::new("allocs", unsafe { &mut libafl_alloc_map });
// If not restarting, create a State from scratch
let mut state = state.unwrap_or_else(|| {

View File

@ -65,9 +65,11 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
};
// Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(unsafe {
StdMapObserver::new("edges", &mut EDGES_MAP, MAX_EDGES_NUM)
});
let edges = unsafe { &mut EDGES_MAP[0..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
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
feedback_or!(
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),
// 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(
InProcessExecutor::new(
&mut harness,
tuple_list!(edges_observer, TimeObserver::new("time")),
tuple_list!(edges_observer, time_observer),
&mut state,
&mut restarting_mgr,
)?,

View File

@ -1,38 +1,28 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng.
use core::time::Duration;
use std::{env, path::PathBuf};
use libafl::{
bolts::tuples::tuple_list,
corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
QueueCorpusScheduler,
},
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
events::{setup_restarting_mgr_std, EventManager},
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
feedback_or,
feedbacks::{
CrashFeedback, MaxMapFeedback, ReachabilityFeedback, TimeFeedback, TimeoutFeedback,
},
executors::{inprocess::InProcessExecutor, ExitKind},
feedbacks::{MaxMapFeedback, ReachabilityFeedback},
fuzzer::{Fuzzer, StdFuzzer},
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
mutators::token_mutations::Tokens,
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
observers::{HitcountsMapObserver, StdMapObserver},
stages::mutational::StdMutationalStage,
state::{HasCorpus, HasMetadata, State},
stats::SimpleStats,
utils::{current_nanos, StdRand},
Error,
};
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
#[cfg(unix)]
const TARGET_SIZE: usize = 4;
#[cfg(unix)]
extern "C" {
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
let edges_observer = HitcountsMapObserver::new(unsafe {
StdMapObserver::new("edges", &mut EDGES_MAP, MAX_EDGES_NUM)
});
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges));
let reachability_observer =
unsafe { StdMapObserver::new_from_ptr("png.c", __libafl_target_list, TARGET_SIZE) };
// If not restarting, create a State from scratch
let mut state = state.unwrap_or_else(|| {
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
InMemoryCorpus::new(),
// Feedbacks to rate the interestingness of an input
feedback_or!(
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
TimeFeedback::new()
),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(objective_dir).unwrap(),
// Feedbacks to recognize an input as solution
feedback_or!(
CrashFeedback::new(),
TimeoutFeedback::new(),
ReachabilityFeedback::new_with_observer(&reachability_observer)
),
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
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
// A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
// A random policy to get testcasess from the corpus
let scheduler = RandCorpusScheduler::new();
// The wrapped harness function, calling out to the LLVM-style harness
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
let mut executor = TimeoutExecutor::new(
InProcessExecutor::new(
let mut executor = InProcessExecutor::new(
&mut harness,
tuple_list!(
edges_observer,
reachability_observer,
TimeObserver::new("time")
),
tuple_list!(edges_observer, reachability_observer,),
&mut state,
&mut restarting_mgr,
)?,
// 10 seconds timeout
Duration::new(10, 0),
);
)?;
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.

View File

@ -63,8 +63,11 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// Create an observation channel using the coverage map
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
let edges_observer =
StdMapObserver::new("edges", unsafe { &mut EDGES_MAP }, unsafe { MAX_EDGES_NUM });
let edges = unsafe { &mut EDGES_MAP[0..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
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
feedback_or!(
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),
// 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
let mut executor = InProcessExecutor::new(
&mut harness,
tuple_list!(edges_observer, TimeObserver::new("time")),
tuple_list!(edges_observer, time_observer),
&mut state,
&mut restarting_mgr,
)?;

View File

@ -10,7 +10,8 @@ keywords = ["fuzzing", "testing", "security"]
edition = "2018"
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]
criterion = "0.3" # Benchmarking

View File

@ -1,5 +1,7 @@
//! special handling to build and link libafl
use rustc_version::{version_meta, Channel};
fn main() {
#[cfg(target_os = "windows")]
windows::build!(
@ -9,4 +11,20 @@ fn main() {
windows::win32::system_services::{CreateFileMappingA, OpenFileMappingA, MapViewOfFile, UnmapViewOfFile},
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");
}
}
}

View File

@ -6,6 +6,34 @@ use core::any::TypeId;
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 {
const LEN: usize;
@ -60,7 +88,7 @@ impl HasNameIdTuple for () {
impl<Head, Tail> HasNameIdTuple for (Head, Tail)
where
Head: 'static + HasNameId,
Head: HasNameId,
Tail: HasNameIdTuple,
{
fn get_const_name(&self, index: usize) -> Option<&'static str> {
@ -132,6 +160,7 @@ where
Tail: MatchType,
{
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>() {
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)) {
// Switch this check to https://stackoverflow.com/a/60138532/7658998 when in stable and remove 'static
if TypeId::of::<T>() == TypeId::of::<Head>() {
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)
where
Head: 'static + Named,
Head: Named,
Tail: NamedTuple,
{
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 {
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>;
@ -196,6 +263,7 @@ where
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 { (&self.0 as *const _ as *const T).as_ref() }
} else {
@ -204,6 +272,7 @@ where
}
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 { (&mut self.0 as *mut _ as *mut T).as_mut() }
} else {

View File

@ -247,7 +247,7 @@ mod tests {
#[test]
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 observers_buf = postcard::to_allocvec(&map).unwrap();

View File

@ -144,8 +144,8 @@ where
OT: ObserversTuple,
{
let mut interesting = false;
// TODO optimize
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 initial = observer.initial();
@ -359,7 +359,8 @@ where
observers: &OT,
_exit_kind: &ExitKind,
) -> 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 mut hit_target: bool = false;
//check if we've hit any targets.

View File

@ -4,6 +4,7 @@
pub mod map;
pub use map::*;
use alloc::string::{String, ToString};
use serde::{Deserialize, Serialize};
use crate::{
@ -409,6 +410,7 @@ impl Default for TimeoutFeedback {
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TimeFeedback {
exec_time: Option<Duration>,
name: String,
}
impl<I> Feedback<I> for TimeFeedback
@ -424,7 +426,8 @@ where
where
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();
Ok(false)
}
@ -448,18 +451,22 @@ where
impl Named for TimeFeedback {
#[inline]
fn name(&self) -> &str {
"TimeFeedback"
self.name.as_str()
}
}
impl TimeFeedback {
pub fn new() -> Self {
Self { exec_time: None }
pub fn new(name: &'static str) -> Self {
Self {
exec_time: None,
name: name.to_string(),
}
}
impl Default for TimeFeedback {
fn default() -> Self {
Self::new()
pub fn new_with_observer(observer: &TimeObserver) -> Self {
Self {
exec_time: None,
name: observer.name().to_string(),
}
}
}

View File

@ -3,6 +3,7 @@ Welcome to libAFL
*/
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "RUSTC_IS_NIGHTLY", feature(specialization))]
#[macro_use]
extern crate alloc;

View File

@ -4,11 +4,12 @@ use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::slice::from_raw_parts_mut;
use serde::{Deserialize, Serialize};
use crate::{
bolts::{
ownedref::{OwnedArrayPtrMut, OwnedPtr},
ownedref::{OwnedRefMut, OwnedSliceMut},
tuples::Named,
},
executors::HasExecHooks,
@ -57,24 +58,24 @@ where
/// The Map Observer retrieves the state of a map,
/// that will get updated by the target.
/// 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")]
#[allow(clippy::unsafe_derive_deserialize)]
pub struct StdMapObserver<T>
pub struct StdMapObserver<'a, T>
where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{
map: OwnedArrayPtrMut<T>,
map: OwnedSliceMut<'a, T>,
initial: T,
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
{
}
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
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
Self: MapObserver<T>,
@ -85,7 +86,7 @@ where
}
}
impl<T> Named for StdMapObserver<T>
impl<'a, T> Named for StdMapObserver<'a, T>
where
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
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
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{
/// Creates a new MapObserver
pub fn new(name: &'static str, map: &'static mut [T], len: usize) -> Self {
assert!(map.len() >= len);
pub fn new(name: &'static str, map: &'a mut [T]) -> Self {
let initial = if map.is_empty() { T::default() } else { map[0] };
Self {
map: OwnedArrayPtrMut::ArrayPtr((map.as_mut_ptr(), len)),
map: OwnedSliceMut::Ref(map),
name: name.to_string(),
initial,
}
@ -144,7 +144,7 @@ where
pub fn new_owned(name: &'static str, map: Vec<T>) -> Self {
let initial = if map.is_empty() { T::default() } else { map[0] };
Self {
map: OwnedArrayPtrMut::Owned(map),
map: OwnedSliceMut::Owned(map),
name: name.to_string(),
initial,
}
@ -156,7 +156,7 @@ where
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() };
StdMapObserver {
map: OwnedArrayPtrMut::ArrayPtr((map_ptr, len)),
map: OwnedSliceMut::Ref(from_raw_parts_mut(map_ptr, len)),
name: name.to_string(),
initial,
}
@ -164,25 +164,25 @@ where
}
/// Overlooking a variable bitmap
#[derive(Serialize, Deserialize, Clone, Debug)]
#[derive(Serialize, Deserialize, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")]
#[allow(clippy::unsafe_derive_deserialize)]
pub struct VariableMapObserver<T>
pub struct VariableMapObserver<'a, T>
where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{
map: OwnedArrayPtrMut<T>,
size: OwnedPtr<usize>,
map: OwnedSliceMut<'a, T>,
size: OwnedRefMut<'a, usize>,
initial: T,
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
{
}
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
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
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
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
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{
/// 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] };
Self {
map: OwnedArrayPtrMut::ArrayPtr((map.as_mut_ptr(), map.len())),
size: OwnedPtr::Ptr(size),
map: OwnedSliceMut::Ref(map),
size: OwnedRefMut::Ref(size),
name: name.into(),
initial,
}
@ -254,17 +254,17 @@ where
/// Creates a new MapObserver from a raw pointer
/// # 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(
name: &'static str,
map_ptr: *mut T,
max_len: usize,
size_ptr: *const usize,
size: &'a mut usize,
) -> Self {
let initial = if max_len > 0 { *map_ptr } else { T::default() };
VariableMapObserver {
map: OwnedArrayPtrMut::ArrayPtr((map_ptr, max_len)),
size: OwnedPtr::Ptr(size_ptr),
map: OwnedSliceMut::Ref(from_raw_parts_mut(map_ptr, max_len)),
size: OwnedRefMut::Ref(size),
name: name.into(),
initial,
}

View File

@ -8,7 +8,7 @@ use core::time::Duration;
use serde::{Deserialize, Serialize};
use crate::{
bolts::tuples::{MatchFirstType, MatchNameAndType, MatchType, Named},
bolts::tuples::{MatchName, Named},
executors::HasExecHooks,
utils::current_time,
Error,
@ -16,7 +16,7 @@ use crate::{
/// Observers observe different information about the target.
/// 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.
/// Reserved for future use.
#[inline]
@ -26,10 +26,7 @@ pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'st
}
/// A haskell-style tuple of observers
pub trait ObserversTuple:
MatchNameAndType + MatchType + MatchFirstType + serde::Serialize + serde::de::DeserializeOwned
{
}
pub trait ObserversTuple: MatchName + serde::Serialize + serde::de::DeserializeOwned {}
impl ObserversTuple for () {}
@ -99,7 +96,7 @@ mod tests {
fn test_observer_serde() {
let obv = tuple_list!(
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();
println!("{:?}", vec);

View File

@ -1663,7 +1663,7 @@ impl<EM, I, S> HasExecHooks<EM, I, S> for AsanErrorsObserver {
impl Named for AsanErrorsObserver {
#[inline]
fn name(&self) -> &str {
"AsanErrorsObserver"
"AsanErrors"
}
}
@ -1710,7 +1710,7 @@ where
_exit_kind: &ExitKind,
) -> Result<bool, Error> {
let observer = observers
.match_first_type::<AsanErrorsObserver>()
.match_name::<AsanErrorsObserver>("AsanErrors")
.expect("An AsanErrorsFeedback needs an AsanErrorsObserver");
match observer.errors() {
None => Ok(false),
@ -1742,7 +1742,7 @@ where
impl Named for AsanErrorsFeedback {
#[inline]
fn name(&self) -> &str {
"AsanErrorsFeedback"
"AsanErrors"
}
}