NamedSerdeAnyMap observers

This commit is contained in:
Andrea Fioraldi 2020-12-08 12:37:49 +01:00
parent 4e1d844b7d
commit ff983ecf23
7 changed files with 295 additions and 64 deletions

View File

@ -85,14 +85,15 @@ where
/// Runs the input and triggers observers and feedback
fn evaluate_input(&mut self, input: &I) -> Result<u32, AflError> {
self.reset_observers()?;
self.executor_mut().reset_observers()?;
self.executor_mut().run_target(&input)?;
self.set_executions(self.executions() + 1);
self.post_exec_observers()?;
self.executor_mut().post_exec_observers()?;
let mut fitness = 0;
let observers = self.executor().observers();
for feedback in self.feedbacks_mut() {
fitness += feedback.is_interesting(&input)?;
fitness += feedback.is_interesting(&input, observers)?;
}
Ok(fitness)
}
@ -225,14 +226,6 @@ where
&mut self.metadatas
}
fn observers(&self) -> &[Rc<RefCell<dyn Observer>>] {
&self.observers
}
fn observers_mut(&mut self) -> &mut Vec<Rc<RefCell<dyn Observer>>> {
&mut self.observers
}
fn feedbacks(&self) -> &[Box<dyn Feedback<I>>] {
&self.feedbacks
}

View File

@ -3,7 +3,7 @@ use core::ptr;
use crate::executors::{Executor, ExitKind};
use crate::inputs::Input;
use crate::metamap::NamedAnyMap;
use crate::serde_anymap::NamedSerdeAnyMap;
use crate::observers::Observer;
use crate::AflError;
@ -14,7 +14,7 @@ where
I: Input,
{
harness: HarnessFunction<I>,
observers: NamedAnyMap<dyn Observer>,
observers: NamedSerdeAnyMap<dyn Observer>,
}
static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null();
@ -35,11 +35,11 @@ where
Ok(ret)
}
fn observers(&self) -> &NamedAnyMap<dyn Observer> {
fn observers(&self) -> &NamedSerdeAnyMap<dyn Observer> {
&self.observers
}
fn observers_mut(&mut self) -> &mut NamedAnyMap<dyn Observer> {
fn observers_mut(&mut self) -> &mut NamedSerdeAnyMap<dyn Observer> {
&mut self.observers
}
}
@ -55,7 +55,7 @@ where
}
Self {
harness: harness_fn,
observers: NamedAnyMap::new(),
observers: NamedSerdeAnyMap::new(),
}
}
}

View File

@ -1,7 +1,7 @@
pub mod inmemory;
use crate::inputs::Input;
use crate::metamap::NamedAnyMap;
use crate::serde_anymap::NamedSerdeAnyMap;
use crate::observers::Observer;
use crate::AflError;
@ -12,8 +12,6 @@ pub enum ExitKind {
Timeout,
}
// TODO unbox input
pub trait Executor<I>
where
I: Input,
@ -22,33 +20,26 @@ where
fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError>;
/// Get the linked observers
fn observers(&self) -> &NamedAnyMap<dyn Observer>;
fn observers(&self) -> &NamedSerdeAnyMap<dyn Observer>;
/// Get the linked observers
fn observers_mut(&mut self) -> &mut NamedAnyMap<dyn Observer>;
fn observers_mut(&mut self) -> &mut NamedSerdeAnyMap<dyn Observer>;
/// Add a linked observer
fn add_observer(&mut self, observer: Box<dyn Observer>) {
self.observers_mut().insert(observer, observer.name());
let name = observer.name();
self.observers_mut().insert(observer, name);
}
/// Reset the state of all the observes linked to this executor
fn reset_observers(&mut self) -> Result<(), AflError> {
for typeid in self.observers().all_typeids() {
for observer in self.observers_mut().all_by_typeid_mut(typeid).unwrap() {
observer.reset()?;
}
}
self.observers_mut().for_each_mut(|_, x| Ok(x.reset()?))?;
Ok(())
}
/// Run the post exec hook for all the observes linked to this executor
fn post_exec_observers(&mut self) -> Result<(), AflError> {
for typeid in self.observers().all_typeids() {
for observer in self.observers_mut().all_by_typeid_mut(typeid).unwrap() {
observer.post_exec()?;
}
}
self.observers_mut().for_each_mut(|_, x| Ok(x.post_exec()?))?;
Ok(())
}
}

View File

@ -1,16 +1,11 @@
use alloc::rc::Rc;
use alloc::vec::Vec;
use core::any::Any;
use core::cell::RefCell;
use core::marker::PhantomData;
use num::Integer;
use serde::{Deserialize, Serialize};
use crate::corpus::{Testcase, TestcaseMetadata};
use crate::executors::Executor;
use crate::inputs::Input;
use crate::observers::MapObserver;
use crate::serde_anymap::SerdeAny;
use crate::observers::{Observer, MapObserver};
use crate::serde_anymap::NamedSerdeAnyMap;
use crate::AflError;
pub trait Feedback<I>
@ -18,7 +13,7 @@ where
I: Input,
{
/// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55)
fn is_interesting(&mut self, input: &I, executor: &dyn Executor<I>) -> Result<u32, AflError>;
fn is_interesting(&mut self, input: &I, observers: &NamedSerdeAnyMap<dyn Observer>) -> Result<u32, AflError>;
/// Append to the testcase the generated metadata in case of a new corpus item
fn append_metadata(&mut self, _testcase: &mut Testcase<I>) -> Result<(), AflError> {
@ -100,21 +95,20 @@ impl<T, R, O, I> Feedback<I> for MapFeedback<T, R, O>
where
T: Integer + Copy + 'static,
R: Reducer<T>,
O: MapObserver<T>,
O: MapObserver<T> + 'static,
I: Input,
{
fn is_interesting(&mut self, _input: &I, executor: &dyn Executor<I>) -> Result<u32, AflError> {
fn is_interesting(&mut self, _input: &I, observers: &NamedSerdeAnyMap<dyn Observer>) -> Result<u32, AflError> {
let mut interesting = 0;
// TODO optimize
let size = self.map_observer.borrow().map().len();
let mut history_map = self.history_map.borrow_mut();
let observer = self.map_observer.borrow();
let observer = observers.get::<O>(self.name).unwrap();
let size = observer.map().len();
for i in 0..size {
let history = history_map[i];
let history = self.history_map[i];
let item = observer.map()[i];
let reduced = R::reduce(history, item);
if history != reduced {
history_map[i] = reduced;
self.history_map[i] = reduced;
interesting += 1;
}
}
@ -160,6 +154,7 @@ where
}
}
/*
#[derive(Serialize, Deserialize)]
pub struct MapNoveltiesMetadata {
novelties: Vec<usize>,
@ -290,9 +285,10 @@ where
}
}
}
*/
pub type MaxMapFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>;
pub type MinMapFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;
pub type MaxMapTrackerFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>;
pub type MinMapTrackerFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;
//pub type MaxMapTrackerFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>;
//pub type MinMapTrackerFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;

View File

@ -291,7 +291,7 @@ where
pub fn by_typeid_mut(&mut self, name: &'static str, typeid: &TypeId) -> Option<&mut B> {
match self.map.get_mut(typeid) {
None => None,
Some(h) => h.get(&name).map(|x| x.as_mut()),
Some(h) => h.get_mut(&name).map(|x| x.as_mut()),
}
}

View File

@ -3,13 +3,14 @@ extern crate num;
use core::any::Any;
use core::slice::from_raw_parts_mut;
use num::Integer;
use serde::{Deserialize, Serialize};
use crate::metamap::AsAny;
use crate::serde_anymap::{SerdeAny, SliceMut};
use crate::AflError;
/// Observers observe different information about the target.
/// They can then be used by various sorts of feedback.
pub trait Observer: Any + AsAny {
pub trait Observer: SerdeAny + 'static {
fn flush(&mut self) -> Result<(), AflError> {
Ok(())
}
@ -35,7 +36,7 @@ where
fn map_mut(&mut self) -> &mut [T];
/// Get the initial value for reset()
fn initial(&self) -> &T;
fn initial(&self) -> T;
/// Get the initial value for reset()
fn initial_mut(&mut self) -> &mut T;
@ -46,25 +47,27 @@ where
/// Reset the map
fn reset_map(&mut self) -> Result<(), AflError> {
// Normal memset, see https://rust.godbolt.org/z/Trs5hv
let initial = self.initial();
for i in self.map_mut().iter_mut() {
*i = T::zero();
*i = initial;
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
pub struct StdMapObserver<T>
where
T: Integer + Copy + 'static,
{
map: &'static mut [T],
map: SliceMut<'static, T>,
initial: T,
name: &'static str,
}
impl<T> Observer for StdMapObserver<T>
where
T: Integer + Copy,
T: Integer + Copy + 'static + serde::Serialize,
{
fn reset(&mut self) -> Result<(), AflError> {
self.reset_map()
@ -75,9 +78,9 @@ where
}
}
impl<T> AsAny for StdMapObserver<T>
impl<T> SerdeAny for StdMapObserver<T>
where
T: Integer + Copy,
T: Integer + Copy + 'static + serde::Serialize,
{
fn as_any(&self) -> &dyn Any {
self
@ -92,15 +95,21 @@ where
T: Integer + Copy,
{
fn map(&self) -> &[T] {
&self.map
match &self.map {
SliceMut::Ref(r) => r,
SliceMut::Owned(v) => v.as_slice()
}
}
fn map_mut(&mut self) -> &mut [T] {
&mut self.map
match &mut self.map {
SliceMut::Ref(r) => r,
SliceMut::Owned(v) => v.as_mut_slice()
}
}
fn initial(&self) -> &T {
&self.initial
fn initial(&self) -> T {
self.initial
}
fn initial_mut(&mut self) -> &mut T {
@ -120,7 +129,7 @@ where
pub fn new(name: &'static str, map: &'static mut [T]) -> Self {
let initial = if map.len() > 0 { map[0] } else { T::zero() };
Self {
map: map,
map: SliceMut::Ref(map),
initial: initial,
name: name,
}
@ -131,7 +140,7 @@ where
unsafe {
let initial = if len > 0 { *map_ptr } else { T::zero() };
StdMapObserver {
map: from_raw_parts_mut(map_ptr, len),
map: SliceMut::Ref(from_raw_parts_mut(map_ptr, len)),
initial: initial,
name: name,
}

View File

@ -5,6 +5,10 @@ use alloc::boxed::Box;
use core::any::{Any, TypeId};
use core::default::Default;
use core::fmt;
use core::slice::{Iter, IterMut};
use hashbrown::hash_map::{Keys, Values, ValuesMut};
use crate::AflError;
pub fn pack_type_id(id: u64) -> TypeId {
unsafe { *(&id as *const u64 as *const TypeId) }
@ -199,3 +203,241 @@ impl SerdeAnyMap {
}
}
}
#[derive(Serialize, Deserialize)]
pub struct NamedSerdeAnyMap<B>
where
B: ?Sized + SerdeAny,
{
map: HashMap<u64, HashMap<u64, Box<B>>>,
}
impl<B> NamedSerdeAnyMap<B>
where
B: ?Sized + SerdeAny,
{
pub fn get<T>(&self, name: &'static str) -> Option<&T>
where
T: Any,
{
match self.map.get(&unpack_type_id(TypeId::of::<T>())) {
None => None,
Some(h) => h
.get(&xxhash_rust::xxh3::xxh3_64(name.as_bytes()))
.map(|x| x.as_any().downcast_ref::<T>().unwrap()),
}
}
pub fn by_typeid(&self, name: &'static str, typeid: &TypeId) -> Option<&B> {
match self.map.get(&unpack_type_id(*typeid)) {
None => None,
Some(h) => h.get(&xxhash_rust::xxh3::xxh3_64(name.as_bytes())).map(|x| x.as_ref()),
}
}
pub fn get_mut<T>(&mut self, name: &'static str) -> Option<&mut T>
where
T: Any,
{
match self.map.get_mut(&unpack_type_id(TypeId::of::<T>())) {
None => None,
Some(h) => h
.get_mut(&xxhash_rust::xxh3::xxh3_64(name.as_bytes()))
.map(|x| x.as_any_mut().downcast_mut::<T>().unwrap()),
}
}
pub fn by_typeid_mut(&mut self, name: &'static str, typeid: &TypeId) -> Option<&mut B> {
match self.map.get_mut(&unpack_type_id(*typeid)) {
None => None,
Some(h) => h.get_mut(&xxhash_rust::xxh3::xxh3_64(name.as_bytes())).map(|x| x.as_mut()),
}
}
pub fn get_all<T>(
&self,
) -> Option<core::iter::Map<Values<'_, u64, Box<B>>, fn(&Box<B>) -> &T>>
where
T: Any,
{
match self.map.get(&unpack_type_id(TypeId::of::<T>())) {
None => None,
Some(h) => Some(h.values().map(|x| x.as_any().downcast_ref::<T>().unwrap())),
}
}
pub fn all_by_typeid(
&self,
typeid: &TypeId,
) -> Option<core::iter::Map<Values<'_, u64, Box<B>>, fn(&Box<B>) -> &B>> {
match self.map.get(&unpack_type_id(*typeid)) {
None => None,
Some(h) => Some(h.values().map(|x| x.as_ref())),
}
}
pub fn get_all_mut<T>(
&mut self,
) -> Option<core::iter::Map<ValuesMut<'_, u64, Box<B>>, fn(&mut Box<B>) -> &mut T>>
where
T: Any,
{
match self.map.get_mut(&unpack_type_id(TypeId::of::<T>())) {
None => None,
Some(h) => Some(
h.values_mut()
.map(|x| x.as_any_mut().downcast_mut::<T>().unwrap()),
),
}
}
pub fn all_by_typeid_mut(
&mut self,
typeid: &TypeId,
) -> Option<core::iter::Map<ValuesMut<'_, u64, Box<B>>, fn(&mut Box<B>) -> &mut B>>
{
match self.map.get_mut(&unpack_type_id(*typeid)) {
None => None,
Some(h) => Some(h.values_mut().map(|x| x.as_mut())),
}
}
pub fn all_typeids(&self) -> core::iter::Map<Keys<'_, u64, HashMap<u64, Box<B>>>, fn(&u64) -> TypeId> {
self.map.keys().map(|x| pack_type_id(*x))
}
pub fn for_each(&self, func: fn(&TypeId, &Box<B>) -> Result<(), AflError>) -> Result<(), AflError> {
for (id, h) in self.map.iter() {
for x in h.values() {
func(&pack_type_id(*id), x)?;
}
}
Ok(())
}
pub fn for_each_mut(&mut self, func: fn(&TypeId, &mut Box<B>) -> Result<(), AflError>) -> Result<(), AflError> {
for (id, h) in self.map.iter_mut() {
for x in h.values_mut() {
func(&pack_type_id(*id), x)?;
}
}
Ok(())
}
pub fn insert(&mut self, val: Box<B>, name: &'static str) {
let id = unpack_type_id(val.type_id());
if !self.map.contains_key(&id) {
self.map.insert(id, HashMap::default());
}
self.map.get_mut(&id).unwrap().insert(xxhash_rust::xxh3::xxh3_64(name.as_bytes()), val);
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn contains_type<T>(&self) -> bool
where
T: Any,
{
self.map.contains_key(&unpack_type_id(TypeId::of::<T>()))
}
pub fn contains<T>(&self, name: &'static str) -> bool
where
T: Any,
{
match self.map.get(&unpack_type_id(TypeId::of::<T>())) {
None => false,
Some(h) => h.contains_key(&xxhash_rust::xxh3::xxh3_64(name.as_bytes())),
}
}
pub fn new() -> Self {
Self {
map: HashMap::default(),
}
}
}
impl<B> Default for NamedSerdeAnyMap<B>
where
B: ?Sized + SerdeAny,
{
fn default() -> Self {
Self::new()
}
}
#[derive(Serialize)]
pub enum Ptr<'a, T: 'a + ?Sized> {
Ref(&'a T),
Owned(Box<T>),
}
impl<'de, 'a, T: 'a + ?Sized> Deserialize<'de> for Ptr<'a, T>
where
Box<T>: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(Ptr::Owned)
}
}
#[derive(Serialize)]
pub enum PtrMut<'a, T: 'a + ?Sized> {
Ref(&'a mut T),
Owned(Box<T>),
}
impl<'de, 'a, T: 'a + ?Sized> Deserialize<'de> for PtrMut<'a, T>
where
Box<T>: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(PtrMut::Owned)
}
}
#[derive(Serialize)]
pub enum Slice<'a, T: 'a + Sized> {
Ref(&'a [T]),
Owned(Vec<T>),
}
impl<'de, 'a, T: 'a + Sized> Deserialize<'de> for Slice<'a, T>
where
Vec<T>: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(Slice::Owned)
}
}
#[derive(Serialize)]
pub enum SliceMut<'a, T: 'a + Sized> {
Ref(&'a mut [T]),
Owned(Vec<T>),
}
impl<'de, 'a, T: 'a + Sized> Deserialize<'de> for SliceMut<'a, T>
where
Vec<T>: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(SliceMut::Owned)
}
}