serde anymap, todo remove testcase clone() in event
This commit is contained in:
parent
83a05049bf
commit
f4fa7e7b8b
@ -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
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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] {
|
||||
|
@ -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 {
|
||||
|
@ -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
165
afl/src/serde_anymap.rs
Normal 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() }
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user