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.
|
//! 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;
|
||||||
|
@ -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))?;
|
||||||
|
@ -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(
|
||||||
|
@ -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};
|
||||||
|
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 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")]
|
||||||
|
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