fix anymap traverse all

This commit is contained in:
Andrea Fioraldi 2020-12-07 22:20:28 +01:00
parent 5d2e7b5bc2
commit 4e1d844b7d
5 changed files with 147 additions and 85 deletions

View File

@ -1,11 +1,10 @@
use alloc::rc::Rc;
use core::cell::RefCell;
use core::ffi::c_void; use core::ffi::c_void;
use core::ptr; use core::ptr;
use crate::executors::{Executor, ExitKind}; use crate::executors::{Executor, ExitKind};
use crate::inputs::Input; use crate::inputs::Input;
use crate::metamap::NamedAnyMap; use crate::metamap::NamedAnyMap;
use crate::observers::Observer;
use crate::AflError; use crate::AflError;
type HarnessFunction<I> = fn(&dyn Executor<I>, &[u8]) -> ExitKind; type HarnessFunction<I> = fn(&dyn Executor<I>, &[u8]) -> ExitKind;
@ -15,7 +14,7 @@ where
I: Input, I: Input,
{ {
harness: HarnessFunction<I>, harness: HarnessFunction<I>,
observers: NamedAnyMap, observers: NamedAnyMap<dyn Observer>,
} }
static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null(); static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null();
@ -35,6 +34,14 @@ where
} }
Ok(ret) Ok(ret)
} }
fn observers(&self) -> &NamedAnyMap<dyn Observer> {
&self.observers
}
fn observers_mut(&mut self) -> &mut NamedAnyMap<dyn Observer> {
&mut self.observers
}
} }
impl<I> InMemoryExecutor<I> impl<I> InMemoryExecutor<I>
@ -48,6 +55,7 @@ where
} }
Self { Self {
harness: harness_fn, harness: harness_fn,
observers: NamedAnyMap::new(),
} }
} }
} }

View File

@ -1,8 +1,8 @@
pub mod inmemory; pub mod inmemory;
use crate::inputs::Input; use crate::inputs::Input;
use crate::observers::Observer;
use crate::metamap::NamedAnyMap; use crate::metamap::NamedAnyMap;
use crate::observers::Observer;
use crate::AflError; use crate::AflError;
pub enum ExitKind { pub enum ExitKind {
@ -22,29 +22,33 @@ where
fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError>; fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError>;
/// Get the linked observers /// Get the linked observers
fn observers(&self) -> &NamedAnyMap; fn observers(&self) -> &NamedAnyMap<dyn Observer>;
/// Get the linked observers /// Get the linked observers
fn observers_mut(&mut self) -> &mut NamedAnyMap; fn observers_mut(&mut self) -> &mut NamedAnyMap<dyn Observer>;
/// Add a linked observer /// Add a linked observer
fn add_observer(&mut self, observer: Box<dyn Observer>, name: &'static str) { fn add_observer(&mut self, observer: Box<dyn Observer>) {
self.observers_mut().push(observer); self.observers_mut().insert(observer, observer.name());
} }
/// Reset the state of all the observes linked to this executor /// Reset the state of all the observes linked to this executor
fn reset_observers(&mut self) -> Result<(), AflError> { fn reset_observers(&mut self) -> Result<(), AflError> {
for observer in self.observers_mut() { for typeid in self.observers().all_typeids() {
observer.reset()?; for observer in self.observers_mut().all_by_typeid_mut(typeid).unwrap() {
observer.reset()?;
}
} }
Ok(()) Ok(())
} }
/// Run the post exec hook for all the observes linked to this executor /// Run the post exec hook for all the observes linked to this executor
fn post_exec_observers(&mut self) -> Result<(), AflError> { fn post_exec_observers(&mut self) -> Result<(), AflError> {
self.observers_mut() for typeid in self.observers().all_typeids() {
.iter() for observer in self.observers_mut().all_by_typeid_mut(typeid).unwrap() {
.map(|x| x.post_exec()) observer.post_exec()?;
.fold(Ok(()), |acc, x| if x.is_err() { x } else { acc }) }
}
Ok(())
} }
} }

View File

@ -7,6 +7,7 @@ use num::Integer;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::corpus::{Testcase, TestcaseMetadata}; use crate::corpus::{Testcase, TestcaseMetadata};
use crate::executors::Executor;
use crate::inputs::Input; use crate::inputs::Input;
use crate::observers::MapObserver; use crate::observers::MapObserver;
use crate::serde_anymap::SerdeAny; use crate::serde_anymap::SerdeAny;
@ -17,7 +18,7 @@ where
I: Input, I: Input,
{ {
/// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55) /// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55)
fn is_interesting(&mut self, input: &I) -> Result<u32, AflError>; fn is_interesting(&mut self, input: &I, executor: &dyn Executor<I>) -> Result<u32, AflError>;
/// Append to the testcase the generated metadata in case of a new corpus item /// 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> { fn append_metadata(&mut self, _testcase: &mut Testcase<I>) -> Result<(), AflError> {
@ -28,6 +29,8 @@ where
fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> { fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> {
Ok(()) Ok(())
} }
fn name(&self) -> &'static str;
} }
/// A Reducer function is used to aggregate values for the novelty search /// A Reducer function is used to aggregate values for the novelty search
@ -78,16 +81,6 @@ where
} }
} }
/// Returns a usable history map of the given size
pub fn create_history_map<T>(map_size: usize) -> Rc<RefCell<Vec<T>>>
where
T: Default + Clone,
{
{
Rc::new(RefCell::new(vec![T::default(); map_size]))
}
}
/// The most common AFL-like feedback type /// The most common AFL-like feedback type
pub struct MapFeedback<T, R, O> pub struct MapFeedback<T, R, O>
where where
@ -96,11 +89,11 @@ where
O: MapObserver<T>, O: MapObserver<T>,
{ {
/// Contains information about untouched entries /// Contains information about untouched entries
history_map: Rc<RefCell<Vec<T>>>, history_map: Vec<T>,
/// The observer this feedback struct observes /// Name identifier of this instance
map_observer: Rc<RefCell<O>>, name: &'static str,
/// Phantom Data of Reducer /// Phantom Data of Reducer
phantom: PhantomData<R>, phantom: PhantomData<(R, O)>,
} }
impl<T, R, O, I> Feedback<I> for MapFeedback<T, R, O> impl<T, R, O, I> Feedback<I> for MapFeedback<T, R, O>
@ -110,9 +103,8 @@ where
O: MapObserver<T>, O: MapObserver<T>,
I: Input, I: Input,
{ {
fn is_interesting(&mut self, _input: &I) -> Result<u32, AflError> { fn is_interesting(&mut self, _input: &I, executor: &dyn Executor<I>) -> Result<u32, AflError> {
let mut interesting = 0; let mut interesting = 0;
// TODO optimize // TODO optimize
let size = self.map_observer.borrow().map().len(); let size = self.map_observer.borrow().map().len();
let mut history_map = self.history_map.borrow_mut(); let mut history_map = self.history_map.borrow_mut();
@ -129,6 +121,10 @@ where
Ok(interesting) Ok(interesting)
} }
fn name(&self) -> &'static str {
self.name
}
} }
impl<T, R, O> MapFeedback<T, R, O> impl<T, R, O> MapFeedback<T, R, O>
@ -137,11 +133,11 @@ where
R: Reducer<T>, R: Reducer<T>,
O: MapObserver<T>, O: MapObserver<T>,
{ {
/// Create new MapFeedback using a map observer /// Create new MapFeedback
pub fn new(map_observer: Rc<RefCell<O>>, map_size: usize) -> Self { pub fn new(name: &'static str, map_size: usize) -> Self {
Self { Self {
map_observer: map_observer, history_map: vec![T::default(); map_size],
history_map: create_history_map::<T>(map_size), name: name,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -155,13 +151,10 @@ where
{ {
/// Create new MapFeedback using a map observer, and a map. /// Create new MapFeedback using a map observer, and a map.
/// The map can be shared. /// The map can be shared.
pub fn with_history_map( pub fn with_history_map(name: &'static str, history_map: Vec<T>) -> Self {
map_observer: Rc<RefCell<O>>,
history_map: Rc<RefCell<Vec<T>>>,
) -> Self {
Self { Self {
map_observer: map_observer,
history_map: history_map, history_map: history_map,
name: name,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -206,11 +199,11 @@ where
O: MapObserver<T>, O: MapObserver<T>,
{ {
/// Contains information about untouched entries /// Contains information about untouched entries
history_map: Rc<RefCell<Vec<T>>>, history_map: Vec<T>,
/// The observer this feedback struct observes /// Name identifier of this instance
map_observer: Rc<RefCell<O>>, name: &'static str,
/// Phantom Data of Reducer /// Phantom Data of Reducer
phantom: PhantomData<R>, phantom: PhantomData<(R, O)>,
/// Track novel entries indexes /// Track novel entries indexes
novelties: Vec<usize>, novelties: Vec<usize>,
} }
@ -254,6 +247,10 @@ where
self.novelties.clear(); self.novelties.clear();
Ok(()) Ok(())
} }
fn name(&self) -> &'static str {
self.name
}
} }
impl<T, R, O> MapTrackerFeedback<T, R, O> impl<T, R, O> MapTrackerFeedback<T, R, O>

View File

@ -2,7 +2,7 @@ use alloc::boxed::Box;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::any::{Any, TypeId}; use core::any::{Any, TypeId};
use core::slice::{Iter, IterMut}; use core::slice::{Iter, IterMut};
use hashbrown::hash_map::{Values, ValuesMut}; use hashbrown::hash_map::{Keys, Values, ValuesMut};
use hashbrown::HashMap; use hashbrown::HashMap;
pub struct MetaMap { pub struct MetaMap {
@ -241,11 +241,22 @@ impl MetaInstanceMap {
} }
} }
pub struct NamedAnyMap { pub trait AsAny {
map: HashMap<TypeId, HashMap<&'static str, Box<dyn Any>>>, fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
} }
impl NamedAnyMap { pub struct NamedAnyMap<B>
where
B: ?Sized + Any + AsAny,
{
map: HashMap<TypeId, HashMap<&'static str, Box<B>>>,
}
impl<B> NamedAnyMap<B>
where
B: ?Sized + Any + AsAny,
{
pub fn get<T>(&self, name: &'static str) -> Option<&T> pub fn get<T>(&self, name: &'static str) -> Option<&T>
where where
T: Any, T: Any,
@ -254,7 +265,14 @@ impl NamedAnyMap {
None => None, None => None,
Some(h) => h Some(h) => h
.get(&name) .get(&name)
.map(|x| x.as_ref().downcast_ref::<T>().unwrap()), .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(typeid) {
None => None,
Some(h) => h.get(&name).map(|x| x.as_ref()),
} }
} }
@ -266,27 +284,42 @@ impl NamedAnyMap {
None => None, None => None,
Some(h) => h Some(h) => h
.get_mut(&name) .get_mut(&name)
.map(|x| x.as_mut().downcast_mut::<T>().unwrap()), .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(typeid) {
None => None,
Some(h) => h.get(&name).map(|x| x.as_mut()),
} }
} }
pub fn get_all<T>( pub fn get_all<T>(
&self, &self,
) -> Option<core::iter::Map<Values<'_, &'static str, Box<dyn Any>>, fn(&Box<dyn Any>) -> &T>> ) -> Option<core::iter::Map<Values<'_, &'static str, Box<B>>, fn(&Box<B>) -> &T>>
where where
T: Any, T: Any,
{ {
match self.map.get(&TypeId::of::<T>()) { match self.map.get(&TypeId::of::<T>()) {
None => None, None => None,
Some(h) => Some(h.values().map(|x| x.as_ref().downcast_ref::<T>().unwrap())), 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<'_, &'static str, Box<B>>, fn(&Box<B>) -> &B>> {
match self.map.get(typeid) {
None => None,
Some(h) => Some(h.values().map(|x| x.as_ref())),
} }
} }
pub fn get_all_mut<T>( pub fn get_all_mut<T>(
&mut self, &mut self,
) -> Option< ) -> Option<core::iter::Map<ValuesMut<'_, &'static str, Box<B>>, fn(&mut Box<B>) -> &mut T>>
core::iter::Map<ValuesMut<'_, &'static str, Box<dyn Any>>, fn(&mut Box<dyn Any>) -> &mut T>,
>
where where
T: Any, T: Any,
{ {
@ -294,23 +327,32 @@ impl NamedAnyMap {
None => None, None => None,
Some(h) => Some( Some(h) => Some(
h.values_mut() h.values_mut()
.map(|x| x.as_mut().downcast_mut::<T>().unwrap()), .map(|x| x.as_any_mut().downcast_mut::<T>().unwrap()),
), ),
} }
} }
pub fn insert<T>(&mut self, t: T, name: &'static str) pub fn all_by_typeid_mut(
where &mut self,
T: Any, typeid: &TypeId,
) -> Option<core::iter::Map<ValuesMut<'_, &'static str, Box<B>>, fn(&mut Box<B>) -> &mut B>>
{ {
let typeid = TypeId::of::<T>(); match self.map.get_mut(typeid) {
None => None,
Some(h) => Some(h.values_mut().map(|x| x.as_mut())),
}
}
pub fn all_typeids(&self) -> Keys<'_, TypeId, HashMap<&'static str, Box<B>>> {
self.map.keys()
}
pub fn insert(&mut self, val: Box<B>, name: &'static str) {
let typeid = val.type_id();
if !self.map.contains_key(&typeid) { if !self.map.contains_key(&typeid) {
self.map.insert(typeid, HashMap::default()); self.map.insert(typeid, HashMap::default());
} }
self.map self.map.get_mut(&typeid).unwrap().insert(name, val);
.get_mut(&typeid)
.unwrap()
.insert(name, Box::new(t));
} }
pub fn len(&self) -> usize { pub fn len(&self) -> usize {

View File

@ -1,16 +1,15 @@
extern crate num; extern crate num;
use alloc::rc::Rc;
use core::cell::RefCell;
use core::slice::from_raw_parts_mut;
use core::any::Any; use core::any::Any;
use core::slice::from_raw_parts_mut;
use num::Integer; use num::Integer;
use crate::metamap::AsAny;
use crate::AflError; use crate::AflError;
/// 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: Any { pub trait Observer: Any + AsAny {
fn flush(&mut self) -> Result<(), AflError> { fn flush(&mut self) -> Result<(), AflError> {
Ok(()) Ok(())
} }
@ -20,6 +19,8 @@ pub trait Observer: Any {
fn post_exec(&mut self) -> Result<(), AflError> { fn post_exec(&mut self) -> Result<(), AflError> {
Ok(()) Ok(())
} }
fn name(&self) -> &'static str;
} }
/// A MapObserver observes the static map, as oftentimes used for afl-like coverage information /// A MapObserver observes the static map, as oftentimes used for afl-like coverage information
@ -52,24 +53,41 @@ where
} }
} }
pub struct StdMapObserver<'a, T> pub struct StdMapObserver<T>
where where
T: Integer + Copy, T: Integer + Copy + 'static,
{ {
map: &'a mut [T], map: &'static mut [T],
initial: T, initial: T,
name: &'static str,
} }
impl<'a, T> Observer for StdMapObserver<'a, T> impl<T> Observer for StdMapObserver<T>
where where
T: Integer + Copy, T: Integer + Copy,
{ {
fn reset(&mut self) -> Result<(), AflError> { fn reset(&mut self) -> Result<(), AflError> {
self.reset_map() self.reset_map()
} }
fn name(&self) -> &'static str {
self.name
}
} }
impl<'a, T> MapObserver<T> for StdMapObserver<'a, T> impl<T> AsAny for StdMapObserver<T>
where
T: Integer + Copy,
{
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl<T> MapObserver<T> for StdMapObserver<T>
where where
T: Integer + Copy, T: Integer + Copy,
{ {
@ -94,36 +112,29 @@ where
} }
} }
impl<'a, T> StdMapObserver<'a, T> impl<T> StdMapObserver<T>
where where
T: Integer + Copy, T: Integer + Copy,
{ {
/// Creates a new MapObserver /// Creates a new MapObserver
pub fn new(map: &'a mut [T]) -> Self { pub fn new(name: &'static str, map: &'static mut [T]) -> Self {
let initial = if map.len() > 0 { map[0] } else { T::zero() }; let initial = if map.len() > 0 { map[0] } else { T::zero() };
Self { Self {
map: map, map: map,
initial: initial, initial: initial,
name: name,
} }
} }
/// Creates a new MapObserver from a raw pointer /// Creates a new MapObserver from a raw pointer
pub fn new_from_ptr(map_ptr: *mut T, len: usize) -> Self { pub fn new_from_ptr(name: &'static str, map_ptr: *mut T, len: usize) -> Self {
unsafe { unsafe {
let initial = if len > 0 { *map_ptr } else { T::zero() }; let initial = if len > 0 { *map_ptr } else { T::zero() };
StdMapObserver { StdMapObserver {
map: from_raw_parts_mut(map_ptr, len), map: from_raw_parts_mut(map_ptr, len),
initial: initial, initial: initial,
name: name,
} }
} }
} }
} }
impl<'a, T> Into<Rc<RefCell<Self>>> for StdMapObserver<'a, T>
where
T: Integer + Copy,
{
fn into(self) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(self))
}
}