AnyMap and owned collections of Observers and Stages (#491)

* AnyMap and owned observers

* owned stages

* alloc

* panic on (de)serializing ObserversOwnedMap

* clippy
This commit is contained in:
Andrea Fioraldi 2022-01-24 20:59:37 +01:00 committed by GitHub
parent 2730515c46
commit b459933d29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 607 additions and 69 deletions

26
TODO.md
View File

@ -1,26 +0,0 @@
# TODOs
- [ ] Objective-Specific Corpuses (named per objective)
- [ ] Good documentation
- [ ] More informative outputs, deeper introspection (monitor, what mutation did x, etc.)
- [ ] Timeout handling for llmp clients (no ping for n seconds -> treat as disconnected)
- [ ] Heap for signal handling (bumpallo or llmp directly?)
- [x] Frida support for Windows
- [x] LAIN / structured fuzzing example
- [x] LLMP compression
- [x] AFL-Style Forkserver Executor
- [x] "Launcher" example that spawns broker + n clients
- [x] QEMU based instrumentation
- [x] AFL++ LLVM passes in libafl_cc
- [x] LLMP Cross Machine Link (2 brokers connected via TCP)
- [x] Conditional composition of feedbacks (issue #24)
- [x] Other objectives examples (e.g. execution of a given program point)
- [x] Restart Count in Fuzzing Loop
- [x] Minset corpus scheduler
- [x] Win32 shared mem and crash handler to have Windows in-process executor
- [x] Other feedbacks examples (e.g. maximize allocations to spot OOMs)
- [x] A macro crate with derive directives (e.g. for SerdeAny impl).
- [x] Restarting EventMgr could use forks on Unix
- [x] Android Ashmem support
- [x] Errors in the Fuzzer should exit the fuzz run
- [x] Timeouts for executors (WIP on Windows)

436
libafl/src/bolts/anymap.rs Normal file
View File

@ -0,0 +1,436 @@
//! Poor-rust-man's downcasts to have `AnyMap`
use alloc::boxed::Box;
use core::{
any::{Any, TypeId},
ptr::addr_of,
};
/// Convert to an Any trait object
pub trait AsAny: Any {
/// returns this as Any trait
fn as_any(&self) -> &dyn Any;
/// returns this as mutable Any trait
fn as_any_mut(&mut self) -> &mut dyn Any;
/// returns this as boxed Any trait
fn as_any_boxed(self: Box<Self>) -> Box<dyn Any>;
}
/// Implement `AsAny` for a type
#[macro_export]
macro_rules! impl_asany {
($struct_name:ident $(< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)?) => {
impl $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $crate::bolts::anymap::AsAny for $struct_name $(< $( $lt ),+ >)? {
fn as_any(&self) -> &dyn ::core::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any {
self
}
fn as_any_boxed(
self: ::alloc::boxed::Box<Self>,
) -> ::alloc::boxed::Box<dyn ::core::any::Any> {
self
}
}
};
}
// yolo
/// Get a `type_id` from its previously unpacked `u64`.
/// Opposite of [`unpack_type_id(id)`].
///
/// # Safety
/// Probably not safe for future compilers, fine for now.
#[must_use]
pub fn pack_type_id(id: u64) -> TypeId {
assert_eq_size!(TypeId, u64);
unsafe { *(addr_of!(id) as *const TypeId) }
}
/// Unpack a `type_id` to an `u64`
/// Opposite of [`pack_type_id(id)`].
///
/// # Safety
/// Probably not safe for future compilers, fine for now.
#[must_use]
pub fn unpack_type_id(id: TypeId) -> u64 {
assert_eq_size!(TypeId, u64);
unsafe { *(addr_of!(id) as *const u64) }
}
/// Create `AnyMap` and `NamedAnyMap` for a given trait
#[macro_export]
macro_rules! create_anymap_for_trait {
( $mod_name:ident, $parent_mod:path, $trait_name:ident $(< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)? $(, $attrs:meta)*) => {
mod $mod_name {
use alloc::boxed::Box;
use core::any::TypeId;
use hashbrown::hash_map::{Keys, Values, ValuesMut};
use hashbrown::HashMap;
use $crate::bolts::anymap::{pack_type_id, unpack_type_id};
use $crate::Error;
use super::*;
#[allow(unused_import_braces)]
use $parent_mod::{$trait_name};
/// An anymap containing trait objects
#[derive(Default)]
$(#[$attrs])*
pub struct AnyMap $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? {
map: HashMap<u64, Box<dyn $trait_name $(< $( $lt ),+ >)?>>,
}
#[allow(unused_qualifications)]
impl $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? AnyMap $(< $( $lt ),+ >)? {
/// Get an element from the map.
#[must_use]
#[inline]
pub fn get<T>(&self) -> Option<&T>
where
T: $trait_name $(< $( $lt ),+ >)?,
{
self.map
.get(&unpack_type_id(TypeId::of::<T>()))
.map(|x| x.as_ref().as_any().downcast_ref::<T>().unwrap())
}
/// Get a mutable borrow for an element in the map.
#[must_use]
#[inline]
pub fn get_mut<T>(&mut self) -> Option<&mut T>
where
T: $trait_name $(< $( $lt ),+ >)?,
{
self.map
.get_mut(&unpack_type_id(TypeId::of::<T>()))
.map(|x| x.as_mut().as_any_mut().downcast_mut::<T>().unwrap())
}
/// Remove an element in the map. Returns the removed element.
#[must_use]
#[inline]
pub fn remove<T>(&mut self) -> Option<Box<T>>
where
T: $trait_name $(< $( $lt ),+ >)?,
{
self.map
.remove(&unpack_type_id(TypeId::of::<T>()))
.map(|x| x.as_any_boxed().downcast::<T>().unwrap())
}
/// Insert an element into the map.
#[inline]
pub fn insert<T>(&mut self, t: T)
where
T: $trait_name $(< $( $lt ),+ >)?,
{
self.map
.insert(unpack_type_id(TypeId::of::<T>()), Box::new(t));
}
/// Insert a boxed element into the map.
#[inline]
pub fn insert_boxed<T>(&mut self, t: Box<T>)
where
T: $trait_name $(< $( $lt ),+ >)?,
{
self.map.insert(unpack_type_id(TypeId::of::<T>()), t);
}
/// Returns the count of elements in this map.
#[must_use]
#[inline]
pub fn len(&self) -> usize {
self.map.len()
}
/// Returns `true` if this map is empty.
#[must_use]
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
/// Returns if the map contains the given type.
#[must_use]
#[inline]
pub fn contains<T>(&self) -> bool
where
T: $trait_name $(< $( $lt ),+ >)?,
{
self.map.contains_key(&unpack_type_id(TypeId::of::<T>()))
}
/// Create a new [`AnyMap`].
#[must_use]
pub fn new() -> Self {
AnyMap {
map: HashMap::default(),
}
}
}
/// An anymap, addressable by name and type, containing trait objects
#[allow(unused_qualifications)]
#[derive(Default)]
$(#[$attrs])*
pub struct NamedAnyMap $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? {
map: HashMap<u64, HashMap<u64, Box<dyn $trait_name $(< $( $lt ),+ >)?>>>,
}
#[allow(unused_qualifications)]
impl $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? NamedAnyMap $(< $( $lt ),+ >)? {
/// Get an element by name
#[must_use]
#[inline]
pub fn get<T>(&self, name: &str) -> Option<&T>
where
T: $trait_name $(< $( $lt ),+ >)?,
{
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()),
}
}
/// Get an element of a given type contained in this map by [`TypeId`].
#[must_use]
#[allow(unused_qualifications)]
#[inline]
pub fn by_typeid(&self, name: &str, typeid: &TypeId) -> Option<&dyn $trait_name $(< $( $lt ),+ >)?> {
match self.map.get(&unpack_type_id(*typeid)) {
None => None,
Some(h) => h
.get(&xxhash_rust::xxh3::xxh3_64(name.as_bytes()))
.map(AsRef::as_ref),
}
}
/// Get an element of a given type contained in this map by [`TypeId`], as mut.
#[must_use]
#[inline]
pub fn get_mut<T>(&mut self, name: &str) -> Option<&mut T>
where
T: $trait_name $(< $( $lt ),+ >)?,
{
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()),
}
}
/// Get an element of a given type contained in this map by [`TypeId`], as mut.
#[must_use]
#[inline]
pub fn by_typeid_mut(
&mut self,
name: &str,
typeid: &TypeId,
) -> Option<&mut dyn $trait_name $(< $( $lt ),+ >)?> {
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(AsMut::as_mut),
}
}
/// Get all elements of a type contained in this map.
#[must_use]
#[allow(unused_qualifications)]
#[inline]
pub fn get_all<T>(
&self,
) -> Option<
core::iter::Map<
Values<'_, u64, Box<dyn $trait_name $(< $( $lt ),+ >)?>>,
fn(&Box<dyn $trait_name $(< $( $lt ),+ >)?>) -> &T,
>,
>
where
T: $trait_name $(< $( $lt ),+ >)?,
{
#[allow(clippy::manual_map)]
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()))
}
}
}
/// Get all elements of a given type contained in this map by [`TypeId`].
#[must_use]
#[allow(unused_qualifications)]
#[inline]
pub fn all_by_typeid(
&self,
typeid: &TypeId,
) -> Option<
core::iter::Map<
Values<'_, u64, Box<dyn $trait_name $(< $( $lt ),+ >)?>>,
fn(&Box<dyn $trait_name $(< $( $lt ),+ >)?>) -> &dyn $trait_name $(< $( $lt ),+ >)?,
>,
> {
#[allow(clippy::manual_map)]
match self.map.get(&unpack_type_id(*typeid)) {
None => None,
Some(h) => Some(h.values().map(|x| x.as_ref())),
}
}
/// Get all elements contained in this map, as mut.
#[inline]
#[allow(unused_qualifications)]
pub fn get_all_mut<T>(
&mut self,
) -> Option<
core::iter::Map<
ValuesMut<'_, u64, Box<dyn $trait_name $(< $( $lt ),+ >)?>>,
fn(&mut Box<dyn $trait_name $(< $( $lt ),+ >)?>) -> &mut T,
>,
>
where
T: $trait_name $(< $( $lt ),+ >)?,
{
#[allow(clippy::manual_map)]
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()),
),
}
}
/// Get all [`TypeId`]`s` contained in this map, as mut.
#[inline]
#[allow(unused_qualifications)]
pub fn all_by_typeid_mut(
&mut self,
typeid: &TypeId,
) -> Option<
core::iter::Map<
ValuesMut<'_, u64, Box<dyn $trait_name $(< $( $lt ),+ >)?>>,
fn(&mut Box<dyn $trait_name $(< $( $lt ),+ >)?>) -> &mut dyn $trait_name $(< $( $lt ),+ >)?,
>,
> {
#[allow(clippy::manual_map)]
match self.map.get_mut(&unpack_type_id(*typeid)) {
None => None,
Some(h) => Some(h.values_mut().map(|x| x.as_mut())),
}
}
/// Get all [`TypeId`]`s` contained in this map.
#[inline]
#[allow(unused_qualifications)]
pub fn all_typeids(
&self,
) -> core::iter::Map<
Keys<'_, u64, HashMap<u64, Box<dyn $trait_name $(< $( $lt ),+ >)?>>>,
fn(&u64) -> TypeId,
> {
self.map.keys().map(|x| pack_type_id(*x))
}
/// Run `func` for each element in this map.
#[inline]
#[allow(unused_qualifications)]
pub fn for_each<F: FnMut(&TypeId, &Box<dyn $trait_name $(< $( $lt ),+ >)?>) -> Result<(), Error>>(
&self,
func: &mut F,
) -> Result<(), Error> {
for (id, h) in self.map.iter() {
for x in h.values() {
func(&pack_type_id(*id), x)?;
}
}
Ok(())
}
/// Run `func` for each element in this map, getting a mutable borrow.
#[inline]
pub fn for_each_mut<F: FnMut(&TypeId, &mut Box<dyn $trait_name $(< $( $lt ),+ >)?>) -> Result<(), Error>>(
&mut self,
func: &mut F,
) -> Result<(), Error> {
for (id, h) in self.map.iter_mut() {
for x in h.values_mut() {
func(&pack_type_id(*id), x)?;
}
}
Ok(())
}
/// Insert an element into this map.
#[inline]
#[allow(unused_qualifications)]
pub fn insert(&mut self, val: Box<dyn $trait_name $(< $( $lt ),+ >)?>, name: &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);
}
/// Returns the `len` of this map.
#[must_use]
#[inline]
pub fn len(&self) -> usize {
self.map.len()
}
/// Returns `true` if this map is empty.
#[must_use]
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
/// Returns if the element with a given type is contained in this map.
#[must_use]
#[inline]
pub fn contains_type<T>(&self) -> bool
where
T: $trait_name $(< $( $lt ),+ >)?,
{
self.map.contains_key(&unpack_type_id(TypeId::of::<T>()))
}
/// Returns if the element by a given `name` is contained in this map.
#[must_use]
#[inline]
pub fn contains<T>(&self, name: &str) -> bool
where
T: $trait_name $(< $( $lt ),+ >)?,
{
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())),
}
}
/// Create a new `SerdeAny` map.
#[must_use]
pub fn new() -> Self {
Self {
map: HashMap::default(),
}
}
}
}
}
}

View File

@ -1,5 +1,6 @@
//! Bolts are no conceptual fuzzing elements, but they keep libafl-based fuzzers together. //! Bolts are no conceptual fuzzing elements, but they keep libafl-based fuzzers together.
pub mod anymap;
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
pub mod compress; pub mod compress;
pub mod cpu; pub mod cpu;

View File

@ -3,35 +3,7 @@
use serde::{de::DeserializeSeed, Deserialize, Deserializer, Serialize, Serializer}; use serde::{de::DeserializeSeed, Deserialize, Deserializer, Serialize, Serializer};
use alloc::boxed::Box; use alloc::boxed::Box;
use core::{ use core::{any::Any, fmt::Debug};
any::{Any, TypeId},
fmt::Debug,
ptr::addr_of,
};
// yolo
/// Get a `type_id` from its previously unpacked `u64`.
/// Opposite of [`unpack_type_id(id)`].
///
/// # Safety
/// Probably not safe for future compilers, fine for now.
#[must_use]
pub fn pack_type_id(id: u64) -> TypeId {
assert_eq_size!(TypeId, u64);
unsafe { *(addr_of!(id) as *const TypeId) }
}
/// Unpack a `type_id` to an `u64`
/// Opposite of [`pack_type_id(id)`].
///
/// # Safety
/// Probably not safe for future compilers, fine for now.
#[must_use]
pub fn unpack_type_id(id: TypeId) -> u64 {
assert_eq_size!(TypeId, u64);
unsafe { *(addr_of!(id) as *const u64) }
}
/// A (de)serializable Any trait /// A (de)serializable Any trait
pub trait SerdeAny: Any + erased_serde::Serialize + Debug { pub trait SerdeAny: Any + erased_serde::Serialize + Debug {
@ -97,7 +69,7 @@ macro_rules! create_serde_registry_for_trait {
pub mod $mod_name { pub mod $mod_name {
use alloc::boxed::Box; use alloc::boxed::Box;
use core::any::{Any, TypeId}; use core::any::TypeId;
use core::fmt; use core::fmt;
use postcard; use postcard;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -105,8 +77,9 @@ macro_rules! create_serde_registry_for_trait {
use hashbrown::hash_map::{Keys, Values, ValuesMut}; use hashbrown::hash_map::{Keys, Values, ValuesMut};
use hashbrown::HashMap; use hashbrown::HashMap;
use $crate::bolts::serdeany::{ use $crate::bolts::{
pack_type_id, unpack_type_id, DeserializeCallback, DeserializeCallbackSeed, anymap::{pack_type_id, unpack_type_id},
serdeany::{DeserializeCallback, DeserializeCallbackSeed},
}; };
use $crate::Error; use $crate::Error;
@ -336,7 +309,7 @@ macro_rules! create_serde_registry_for_trait {
#[inline] #[inline]
pub fn get<T>(&self, name: &str) -> Option<&T> pub fn get<T>(&self, name: &str) -> Option<&T>
where where
T: Any, T: $trait_name,
{ {
match self.map.get(&unpack_type_id(TypeId::of::<T>())) { match self.map.get(&unpack_type_id(TypeId::of::<T>())) {
None => None, None => None,
@ -364,7 +337,7 @@ macro_rules! create_serde_registry_for_trait {
#[inline] #[inline]
pub fn get_mut<T>(&mut self, name: &str) -> Option<&mut T> pub fn get_mut<T>(&mut self, name: &str) -> Option<&mut T>
where where
T: Any, T: $trait_name,
{ {
match self.map.get_mut(&unpack_type_id(TypeId::of::<T>())) { match self.map.get_mut(&unpack_type_id(TypeId::of::<T>())) {
None => None, None => None,
@ -403,7 +376,7 @@ macro_rules! create_serde_registry_for_trait {
>, >,
> >
where where
T: Any, T: $trait_name,
{ {
#[allow(clippy::manual_map)] #[allow(clippy::manual_map)]
match self.map.get(&unpack_type_id(TypeId::of::<T>())) { match self.map.get(&unpack_type_id(TypeId::of::<T>())) {
@ -446,7 +419,7 @@ macro_rules! create_serde_registry_for_trait {
>, >,
> >
where where
T: Any, T: $trait_name,
{ {
#[allow(clippy::manual_map)] #[allow(clippy::manual_map)]
match self.map.get_mut(&unpack_type_id(TypeId::of::<T>())) { match self.map.get_mut(&unpack_type_id(TypeId::of::<T>())) {
@ -492,9 +465,9 @@ macro_rules! create_serde_registry_for_trait {
/// Run `func` for each element in this map. /// Run `func` for each element in this map.
#[inline] #[inline]
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
pub fn for_each( pub fn for_each<F: FnMut(&TypeId, &Box<dyn $trait_name>) -> Result<(), Error>>(
&self, &self,
func: fn(&TypeId, &Box<dyn $trait_name>) -> Result<(), Error>, func: &mut F,
) -> Result<(), Error> { ) -> Result<(), Error> {
for (id, h) in self.map.iter() { for (id, h) in self.map.iter() {
for x in h.values() { for x in h.values() {
@ -506,9 +479,11 @@ macro_rules! create_serde_registry_for_trait {
/// Run `func` for each element in this map, getting a mutable borrow. /// Run `func` for each element in this map, getting a mutable borrow.
#[inline] #[inline]
pub fn for_each_mut( pub fn for_each_mut<
F: FnMut(&TypeId, &mut Box<dyn $trait_name>) -> Result<(), Error>,
>(
&mut self, &mut self,
func: fn(&TypeId, &mut Box<dyn $trait_name>) -> Result<(), Error>, func: &mut F,
) -> Result<(), Error> { ) -> Result<(), Error> {
for (id, h) in self.map.iter_mut() { for (id, h) in self.map.iter_mut() {
for x in h.values_mut() { for x in h.values_mut() {
@ -550,7 +525,7 @@ macro_rules! create_serde_registry_for_trait {
#[inline] #[inline]
pub fn contains_type<T>(&self) -> bool pub fn contains_type<T>(&self) -> bool
where where
T: Any, T: $trait_name,
{ {
self.map.contains_key(&unpack_type_id(TypeId::of::<T>())) self.map.contains_key(&unpack_type_id(TypeId::of::<T>()))
} }
@ -560,7 +535,7 @@ macro_rules! create_serde_registry_for_trait {
#[inline] #[inline]
pub fn contains<T>(&self, name: &str) -> bool pub fn contains<T>(&self, name: &str) -> bool
where where
T: Any, T: $trait_name,
{ {
match self.map.get(&unpack_type_id(TypeId::of::<T>())) { match self.map.get(&unpack_type_id(TypeId::of::<T>())) {
None => false, None => false,
@ -592,7 +567,7 @@ macro_rules! create_serde_registry_for_trait {
{ {
use serde::ser::SerializeSeq; use serde::ser::SerializeSeq;
let id = $crate::bolts::serdeany::unpack_type_id(self.type_id()); let id = $crate::bolts::anymap::unpack_type_id(self.type_id());
let mut seq = se.serialize_seq(Some(2))?; let mut seq = se.serialize_seq(Some(2))?;
seq.serialize_element(&id)?; seq.serialize_element(&id)?;
seq.serialize_element(&$crate::bolts::serdeany::Wrap(self))?; seq.serialize_element(&$crate::bolts::serdeany::Wrap(self))?;

View File

@ -3,7 +3,10 @@ Welcome to `LibAFL`
*/ */
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// For `type_eq`
#![cfg_attr(unstable_feature, feature(specialization))] #![cfg_attr(unstable_feature, feature(specialization))]
// For `type_id` and owned things
#![cfg_attr(unstable_feature, feature(intrinsics))]
#![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::broken_intra_doc_links)]
#![deny(clippy::pedantic)] #![deny(clippy::pedantic)]
#![allow( #![allow(

View File

@ -8,6 +8,11 @@ pub use cmp::*;
pub mod concolic; pub mod concolic;
#[cfg(unstable_feature)]
pub mod owned;
#[cfg(unstable_feature)]
pub use owned::*;
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use core::{fmt::Debug, time::Duration}; use core::{fmt::Debug, time::Duration};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@ -0,0 +1,97 @@
//! A dynamic collection of owned observers, working only with unstable rust
use core::{any::Any, fmt::Debug};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{
bolts::{
anymap::{pack_type_id, AsAny},
tuples::MatchName,
},
observers::{Observer, ObserversTuple},
Error,
};
////////// Warning, unsafe as hell, this bypass the standard library ///////////
extern "rust-intrinsic" {
fn type_id<T: ?Sized>() -> u64;
}
unsafe fn downcast_ref_unsafe<T>(any: &dyn Any) -> &T {
&*(any as *const dyn Any as *const T)
}
unsafe fn downcast_mut_unsafe<T>(any: &mut dyn Any) -> &mut T {
&mut *(any as *mut dyn Any as *mut T)
}
////////////////////////////////////////////////////////////////////////////////
/// Combine `Observer` and `AsAny`
pub trait AnyObserver<I: 'static + Debug, S: 'static + Debug>: Observer<I, S> + AsAny {}
crate::create_anymap_for_trait!(
observers_anymap,
super,
AnyObserver<I: 'static + Debug, S: 'static + Debug>,
derive(Debug)
);
pub use observers_anymap::{AnyMap as ObserversAnyMap, NamedAnyMap as NamedObserversAnyMap};
/// An owned list of `Observer` trait objects
/// This is not really serializable, using this struct needs [`EventConfig::AlwaysUnique`] as configuration
#[derive(Debug, Default)]
pub struct ObserversOwnedMap<I: 'static + Debug, S: 'static + Debug> {
/// The named trait objects map
pub map: NamedObserversAnyMap<I, S>,
}
impl<I: 'static + Debug, S: 'static + Debug> Serialize for ObserversOwnedMap<I, S> {
fn serialize<T>(&self, _serializer: T) -> Result<T::Ok, T::Error>
where
T: Serializer,
{
panic!("Cannot serialize ObserversOwnedMap, use EventConfig::AlwaysUnique as event manager configuration");
}
}
impl<'de, I: 'static + Debug, S: 'static + Debug> Deserialize<'de> for ObserversOwnedMap<I, S> {
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
panic!("Cannot deserialize ObserversOwnedMap, use EventConfig::AlwaysUnique as event manager configuration");
}
}
impl<I: 'static + Debug, S: 'static + Debug> ObserversTuple<I, S> for ObserversOwnedMap<I, S> {
fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
self.map
.for_each_mut(&mut |_, ob| ob.pre_exec(state, input))
}
fn post_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
self.map
.for_each_mut(&mut |_, ob| ob.post_exec(state, input))
}
}
impl<I: 'static + Debug, S: 'static + Debug> MatchName for ObserversOwnedMap<I, S> {
fn match_name<T>(&self, name: &str) -> Option<&T> {
unsafe {
let t = pack_type_id(type_id::<T>());
self.map
.by_typeid(name, &t)
.map(|x| downcast_ref_unsafe(x.as_any()))
}
}
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T> {
unsafe {
let t = pack_type_id(type_id::<T>());
self.map
.by_typeid_mut(name, &t)
.map(|x| downcast_mut_unsafe(x.as_any_mut()))
}
}
}

View File

@ -19,6 +19,9 @@ pub use calibrate::{CalibrationStage, PowerScheduleMetadata};
pub mod power; pub mod power;
pub use power::PowerMutationalStage; pub use power::PowerMutationalStage;
pub mod owned;
pub use owned::StagesOwnedList;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub mod concolic; pub mod concolic;
#[cfg(feature = "std")] #[cfg(feature = "std")]

View File

@ -0,0 +1,44 @@
//! A dynamic collection of owned Stages
use alloc::{boxed::Box, vec::Vec};
use crate::{
bolts::anymap::AsAny,
stages::{Stage, StagesTuple},
Error,
};
/// Combine `Stage` and `AsAny`
pub trait AnyStage<E, EM, S, Z>: Stage<E, EM, S, Z> + AsAny {}
/// An owned list of `Observer` trait objects
#[derive(Default)]
#[allow(missing_debug_implementations)]
pub struct StagesOwnedList<E, EM, S, Z> {
/// The named trait objects map
pub list: Vec<Box<dyn AnyStage<E, EM, S, Z>>>,
}
impl<E, EM, S, Z> StagesTuple<E, EM, S, Z> for StagesOwnedList<E, EM, S, Z> {
fn perform_all(
&mut self,
fuzzer: &mut Z,
executor: &mut E,
state: &mut S,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), Error> {
for s in &mut self.list {
s.perform(fuzzer, executor, state, manager, corpus_idx)?;
}
Ok(())
}
}
impl<E, EM, S, Z> StagesOwnedList<E, EM, S, Z> {
/// Create a new instance
#[must_use]
pub fn new(list: Vec<Box<dyn AnyStage<E, EM, S, Z>>>) -> Self {
Self { list }
}
}