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:
parent
2730515c46
commit
b459933d29
26
TODO.md
26
TODO.md
@ -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
436
libafl/src/bolts/anymap.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
//! Bolts are no conceptual fuzzing elements, but they keep libafl-based fuzzers together.
|
||||
|
||||
pub mod anymap;
|
||||
#[cfg(feature = "llmp_compression")]
|
||||
pub mod compress;
|
||||
pub mod cpu;
|
||||
|
@ -3,35 +3,7 @@
|
||||
use serde::{de::DeserializeSeed, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use core::{
|
||||
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) }
|
||||
}
|
||||
use core::{any::Any, fmt::Debug};
|
||||
|
||||
/// A (de)serializable Any trait
|
||||
pub trait SerdeAny: Any + erased_serde::Serialize + Debug {
|
||||
@ -97,7 +69,7 @@ macro_rules! create_serde_registry_for_trait {
|
||||
pub mod $mod_name {
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use core::any::{Any, TypeId};
|
||||
use core::any::TypeId;
|
||||
use core::fmt;
|
||||
use postcard;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -105,8 +77,9 @@ macro_rules! create_serde_registry_for_trait {
|
||||
use hashbrown::hash_map::{Keys, Values, ValuesMut};
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use $crate::bolts::serdeany::{
|
||||
pack_type_id, unpack_type_id, DeserializeCallback, DeserializeCallbackSeed,
|
||||
use $crate::bolts::{
|
||||
anymap::{pack_type_id, unpack_type_id},
|
||||
serdeany::{DeserializeCallback, DeserializeCallbackSeed},
|
||||
};
|
||||
use $crate::Error;
|
||||
|
||||
@ -336,7 +309,7 @@ macro_rules! create_serde_registry_for_trait {
|
||||
#[inline]
|
||||
pub fn get<T>(&self, name: &str) -> Option<&T>
|
||||
where
|
||||
T: Any,
|
||||
T: $trait_name,
|
||||
{
|
||||
match self.map.get(&unpack_type_id(TypeId::of::<T>())) {
|
||||
None => None,
|
||||
@ -364,7 +337,7 @@ macro_rules! create_serde_registry_for_trait {
|
||||
#[inline]
|
||||
pub fn get_mut<T>(&mut self, name: &str) -> Option<&mut T>
|
||||
where
|
||||
T: Any,
|
||||
T: $trait_name,
|
||||
{
|
||||
match self.map.get_mut(&unpack_type_id(TypeId::of::<T>())) {
|
||||
None => None,
|
||||
@ -403,7 +376,7 @@ macro_rules! create_serde_registry_for_trait {
|
||||
>,
|
||||
>
|
||||
where
|
||||
T: Any,
|
||||
T: $trait_name,
|
||||
{
|
||||
#[allow(clippy::manual_map)]
|
||||
match self.map.get(&unpack_type_id(TypeId::of::<T>())) {
|
||||
@ -446,7 +419,7 @@ macro_rules! create_serde_registry_for_trait {
|
||||
>,
|
||||
>
|
||||
where
|
||||
T: Any,
|
||||
T: $trait_name,
|
||||
{
|
||||
#[allow(clippy::manual_map)]
|
||||
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.
|
||||
#[inline]
|
||||
#[allow(unused_qualifications)]
|
||||
pub fn for_each(
|
||||
pub fn for_each<F: FnMut(&TypeId, &Box<dyn $trait_name>) -> Result<(), Error>>(
|
||||
&self,
|
||||
func: fn(&TypeId, &Box<dyn $trait_name>) -> Result<(), Error>,
|
||||
func: &mut F,
|
||||
) -> Result<(), Error> {
|
||||
for (id, h) in self.map.iter() {
|
||||
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.
|
||||
#[inline]
|
||||
pub fn for_each_mut(
|
||||
pub fn for_each_mut<
|
||||
F: FnMut(&TypeId, &mut Box<dyn $trait_name>) -> Result<(), Error>,
|
||||
>(
|
||||
&mut self,
|
||||
func: fn(&TypeId, &mut Box<dyn $trait_name>) -> Result<(), Error>,
|
||||
func: &mut F,
|
||||
) -> Result<(), Error> {
|
||||
for (id, h) in self.map.iter_mut() {
|
||||
for x in h.values_mut() {
|
||||
@ -550,7 +525,7 @@ macro_rules! create_serde_registry_for_trait {
|
||||
#[inline]
|
||||
pub fn contains_type<T>(&self) -> bool
|
||||
where
|
||||
T: Any,
|
||||
T: $trait_name,
|
||||
{
|
||||
self.map.contains_key(&unpack_type_id(TypeId::of::<T>()))
|
||||
}
|
||||
@ -560,7 +535,7 @@ macro_rules! create_serde_registry_for_trait {
|
||||
#[inline]
|
||||
pub fn contains<T>(&self, name: &str) -> bool
|
||||
where
|
||||
T: Any,
|
||||
T: $trait_name,
|
||||
{
|
||||
match self.map.get(&unpack_type_id(TypeId::of::<T>())) {
|
||||
None => false,
|
||||
@ -592,7 +567,7 @@ macro_rules! create_serde_registry_for_trait {
|
||||
{
|
||||
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))?;
|
||||
seq.serialize_element(&id)?;
|
||||
seq.serialize_element(&$crate::bolts::serdeany::Wrap(self))?;
|
||||
|
@ -3,7 +3,10 @@ Welcome to `LibAFL`
|
||||
*/
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
// For `type_eq`
|
||||
#![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(clippy::pedantic)]
|
||||
#![allow(
|
||||
|
@ -8,6 +8,11 @@ pub use cmp::*;
|
||||
|
||||
pub mod concolic;
|
||||
|
||||
#[cfg(unstable_feature)]
|
||||
pub mod owned;
|
||||
#[cfg(unstable_feature)]
|
||||
pub use owned::*;
|
||||
|
||||
use alloc::string::{String, ToString};
|
||||
use core::{fmt::Debug, time::Duration};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
97
libafl/src/observers/owned.rs
Normal file
97
libafl/src/observers/owned.rs
Normal 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()))
|
||||
}
|
||||
}
|
||||
}
|
@ -19,6 +19,9 @@ pub use calibrate::{CalibrationStage, PowerScheduleMetadata};
|
||||
pub mod power;
|
||||
pub use power::PowerMutationalStage;
|
||||
|
||||
pub mod owned;
|
||||
pub use owned::StagesOwnedList;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub mod concolic;
|
||||
#[cfg(feature = "std")]
|
||||
|
44
libafl/src/stages/owned.rs
Normal file
44
libafl/src/stages/owned.rs
Normal 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 }
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user