serde anymap, todo remove testcase clone() in event

This commit is contained in:
Andrea Fioraldi 2020-12-05 16:27:28 +01:00
parent 83a05049bf
commit f4fa7e7b8b
6 changed files with 191 additions and 27 deletions

View File

@ -32,5 +32,5 @@ libc = "0.2" # For (*nix) libc
num = "*"
xxhash-rust = { version = "0.8.0-beta.5", features = ["xxh3"] } # xxh3 hashing for rust
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
typetag = "0.1"
postcard = "0.5.1" # no_std compatible serde serialization fromat
erased-serde = "0.3.12"
postcard = "0.5.1" # no_std compatible serde serialization fromat

View File

@ -1,7 +1,5 @@
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::string::String;
use core::any::Any;
use core::cell::RefCell;
use core::convert::Into;
use core::default::Default;
@ -10,6 +8,7 @@ use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use crate::inputs::Input;
use crate::serde_anymap::{SerdeAny, SerdeAnyMap};
use crate::AflError;
// TODO PathBuf for no_std and change filename to PathBuf
@ -18,14 +17,12 @@ use crate::AflError;
// TODO: Give example
/// Metadata for a testcase
#[typetag::serde(tag = "type")]
pub trait TestcaseMetadata: Any {
pub trait TestcaseMetadata: SerdeAny {
/// The name of this metadata - used to find it in the list of avaliable metadatas
fn name(&self) -> &'static str;
fn clone(&self) -> Box<dyn TestcaseMetadata>;
}
/*
/// Just a wrapper of Boxed TestcaseMetadata trait object for Clone
#[derive(Serialize, Deserialize)]
pub struct TestcaseMetadataContainer {
@ -45,10 +42,10 @@ impl TestcaseMetadataContainer {
pub fn meta_mut(&mut self) -> &mut Box<dyn TestcaseMetadata> {
&mut self.meta
}
}
}*/
/// An entry in the Testcase Corpus
#[derive(Default, Clone, Serialize, Deserialize)]
#[derive(Default, Serialize, Deserialize)]
pub struct Testcase<I>
where
I: Input,
@ -61,7 +58,7 @@ where
fitness: u32,
// TODO find a way to use TypeId
/// Map of metadatas associated with this testcase
metadatas: HashMap<String, TestcaseMetadataContainer>,
metadatas: SerdeAnyMap,
}
impl<I> Into<Rc<RefCell<Self>>> for Testcase<I>
@ -124,7 +121,7 @@ where
}
/// Get all the metadatas into an HashMap (mutable)
pub fn metadatas(&mut self) -> &mut HashMap<String, TestcaseMetadataContainer> {
pub fn metadatas(&mut self) -> &mut SerdeAnyMap {
&mut self.metadatas
}
/// Add a metadata
@ -132,12 +129,7 @@ where
where
TM: TestcaseMetadata + 'static,
{
self.metadatas.insert(
meta.name().to_string(),
TestcaseMetadataContainer {
meta: Box::new(meta),
},
);
self.metadatas.insert(meta);
}
/// Create a new Testcase instace given an input
@ -149,7 +141,7 @@ where
input: Some(input.into()),
filename: None,
fitness: 0,
metadatas: HashMap::default(),
metadatas: SerdeAnyMap::new(),
}
}
@ -159,7 +151,7 @@ where
input: Some(input),
filename: Some(filename),
fitness: 0,
metadatas: HashMap::default(),
metadatas: SerdeAnyMap::new(),
}
}
@ -168,7 +160,7 @@ where
input: None,
filename: None,
fitness: 0,
metadatas: HashMap::default(),
metadatas: SerdeAnyMap::new(),
}
}
}

View File

@ -3,12 +3,14 @@ use alloc::rc::Rc;
use alloc::vec::Vec;
use core::cell::RefCell;
use core::marker::PhantomData;
use core::any::Any;
use num::Integer;
use serde::{Deserialize, Serialize};
use crate::corpus::{Testcase, TestcaseMetadata};
use crate::inputs::Input;
use crate::observers::MapObserver;
use crate::serde_anymap::SerdeAny;
use crate::AflError;
pub trait Feedback<I>
@ -171,15 +173,19 @@ pub struct MapNoveltiesMetadata {
novelties: Vec<usize>,
}
#[typetag::serde]
impl SerdeAny for MapNoveltiesMetadata {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl TestcaseMetadata for MapNoveltiesMetadata {
fn name(&self) -> &'static str {
"MapNoveltiesMetadata"
}
fn clone(&self) -> Box<dyn TestcaseMetadata> {
Box::new(MapNoveltiesMetadata::new(self.novelties.clone()))
}
}
impl MapNoveltiesMetadata {
pub fn novelties(&self) -> &[usize] {

View File

@ -10,7 +10,7 @@ use crate::AflError;
/// A bytes input is the basic input
#[derive(Clone, Debug, Default)]
pub struct BytesInput {
pub bytes: Vec<u8>,
bytes: Vec<u8>,
}
impl Input for BytesInput {

View File

@ -14,6 +14,7 @@ pub mod mutators;
pub mod observers;
pub mod stages;
pub mod utils;
pub mod serde_anymap;
use alloc::string::String;
use core::fmt;

165
afl/src/serde_anymap.rs Normal file
View File

@ -0,0 +1,165 @@
use hashbrown::HashMap;
use serde::{Serialize, Deserialize};
use core::default::Default;
use core::any::{TypeId, Any};
use core::fmt;
pub fn pack_type_id(id: u64) -> TypeId {
unsafe {
*(&id as *const u64 as *const TypeId)
}
}
pub fn unpack_type_id(id: TypeId) -> u64 {
unsafe {
*(&id as *const _ as *const u64)
}
}
pub trait SerdeAny : Any + erased_serde::Serialize {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
type DeserializeCallback = fn(&mut dyn erased_serde::Deserializer) -> Result<Box<dyn SerdeAny>, erased_serde::Error>;
struct Wrap<'a, T: ?Sized>(pub &'a T);
impl<'a, T> Serialize for Wrap<'a, T>
where
T: ?Sized + erased_serde::Serialize + 'a,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
erased_serde::serialize(self.0, serializer)
}
}
impl<'a> serde::Serialize for dyn SerdeAny + 'a {
fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer
{
use serde::ser::SerializeSeq;
let id = unpack_type_id(self.type_id());
let mut seq = se.serialize_seq(Some(2))?;
seq.serialize_element(&id)?;
seq.serialize_element(&Wrap(self))?;
seq.end()
}
}
struct DeserializeCallbackSeed {
pub cb: DeserializeCallback,
}
impl<'de> serde::de::DeserializeSeed<'de> for DeserializeCallbackSeed{
type Value = Box<dyn SerdeAny>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let mut erased = erased_serde::Deserializer::erase(deserializer);
(self.cb)(&mut erased).map_err(serde::de::Error::custom)
}
}
struct BoxAnyVisitor {}
impl<'de> serde::de::Visitor<'de> for BoxAnyVisitor {
type Value = Box<dyn SerdeAny>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Expecting a serialized SerdeAny trait object (Box<dyn SerdeAny>)")
}
fn visit_seq<V>(self, mut visitor: V) -> Result<Box<dyn SerdeAny>, V::Error>
where
V: serde::de::SeqAccess<'de>,
{
let id: u64 = visitor.next_element()?.unwrap();
let cb = unsafe { *REGISTRY.deserializers.as_ref().unwrap().get(&id).expect("Cannot deserialize an unregistered SerdeAny") };
let seed = DeserializeCallbackSeed { cb: cb };
let obj: Box<dyn SerdeAny> = visitor.next_element_seed(seed)?.unwrap();
Ok(obj)
}
}
impl<'de> Deserialize<'de> for Box<dyn SerdeAny> {
fn deserialize<D>(deserializer: D) -> Result<Box<dyn SerdeAny>, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_seq(BoxAnyVisitor {})
}
}
pub struct Registry {
deserializers: Option<HashMap<u64, DeserializeCallback>>,
finalized: bool
}
impl Registry {
pub fn register<T>(&mut self) where T: SerdeAny + Serialize + serde::de::DeserializeOwned {
if self.finalized {
panic!("Global Registry of SerdeAny types is already finalized!");
}
let deserializers = self.deserializers.get_or_insert_with(|| HashMap::default());
deserializers.insert(unpack_type_id(TypeId::of::<T>()), |de| Ok(Box::new(erased_serde::deserialize::<T>(de)?)));
}
pub fn finalize(&mut self) {
self.finalized = true;
}
}
static mut REGISTRY: Registry = Registry { deserializers: None, finalized: false };
pub struct RegistryBuilder {}
impl RegistryBuilder {
pub fn register<T>() where T: SerdeAny + Serialize + serde::de::DeserializeOwned {
unsafe {
REGISTRY.register::<T>();
}
}
pub fn finalize() {
unsafe {
REGISTRY.finalize();
}
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct SerdeAnyMap {
map: HashMap<u64, Box<dyn SerdeAny>>
}
impl SerdeAnyMap {
pub fn get<T>(&self) -> Option<&T> where T: SerdeAny {
self.map.get(&unpack_type_id(TypeId::of::<T>())).map(|x| x.as_ref().as_any().downcast_ref::<T>().unwrap())
}
pub fn get_mut<T>(&mut self) -> Option<&mut T> where T: SerdeAny {
self.map.get_mut(&unpack_type_id(TypeId::of::<T>())).map(|x| x.as_mut().as_any_mut().downcast_mut::<T>().unwrap())
}
pub fn insert<T>(&mut self, t: T) where T: SerdeAny {
self.map.insert(unpack_type_id(TypeId::of::<T>()), Box::new(t));
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn contains<T>(&self) -> bool where T: SerdeAny {
self.map.contains_key(&unpack_type_id(TypeId::of::<T>()))
}
pub fn new() -> Self {
SerdeAnyMap { map: HashMap::default() }
}
}