diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index 8e571cc19d..28d099b57a 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -18,6 +18,9 @@ pub use stacktrace::*; pub mod concolic; +pub mod value; +pub use value::*; + // Rust is breaking this with 'error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `type_id`' and so we disable this component for the moment //#[cfg(unstable_feature)] //pub mod owned; diff --git a/libafl/src/observers/value.rs b/libafl/src/observers/value.rs new file mode 100644 index 0000000000..fc6cf5aeca --- /dev/null +++ b/libafl/src/observers/value.rs @@ -0,0 +1,108 @@ +//! A simple observer with a single value. + +use alloc::boxed::Box; +use alloc::string::{String, ToString}; +use core::fmt::Debug; + +use serde::{Deserialize, Serialize}; + +use crate::{ + bolts::{ownedref::OwnedRef, tuples::Named}, + inputs::UsesInput, + Error, +}; + +use super::Observer; + +/// A simple observer with a single value. +/// +/// The intent is that the value is something with interior mutability (e.g., a +/// `RefCell`), which the target could write to even though this observer has a +/// reference to it. +#[derive(Serialize, Deserialize, Debug)] +#[serde(bound = "T: serde::de::DeserializeOwned")] +pub struct ValueObserver<'a, T> +where + T: Debug + Serialize, +{ + /// The name of this observer. + name: String, + /// The value. + pub value: OwnedRef<'a, T>, +} + +impl<'a, T> ValueObserver<'a, T> +where + T: Debug + Serialize + serde::de::DeserializeOwned, +{ + /// Creates a new [`ValueObserver`] with the given name. + #[must_use] + pub fn new(name: &'static str, value: &'a T) -> Self { + Self { + name: name.to_string(), + value: OwnedRef::Ref(value), + } + } + + /// Get a reference to the underlying value. + /// + /// ``` + /// # use libafl::observers::value::ValueObserver; + /// let mut obs = ValueObserver::new("example", &2); + /// assert_eq!(&2, obs.get_ref()); + /// ``` + #[must_use] + pub fn get_ref(&self) -> &T { + self.value.as_ref() + } + + /// Set the value. + /// + /// ``` + /// # use libafl::observers::value::ValueObserver; + /// let mut obs = ValueObserver::new("example", &2); + /// obs.set(3); + /// assert_eq!(3, obs.take()); + /// ``` + pub fn set(&mut self, new_value: T) { + self.value = OwnedRef::Owned(Box::new(new_value)); + } + + /// Clone or move the current value out of this object. + /// + /// ``` + /// # use libafl::observers::value::ValueObserver; + /// let mut obs = ValueObserver::new("example", &2); + /// assert_eq!(2, obs.take()); + /// ``` + #[must_use] + pub fn take(self) -> T + where + T: Clone, + { + match self.value { + OwnedRef::Ref(r) => r.clone(), + OwnedRef::Owned(v) => *v, + } + } +} + +/// This *does not* reset the value inside the observer. +impl<'a, S, T> Observer for ValueObserver<'a, T> +where + S: UsesInput, + T: Debug + Serialize + serde::de::DeserializeOwned, +{ + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { + Ok(()) + } +} + +impl<'a, T> Named for ValueObserver<'a, T> +where + T: Debug + Serialize + serde::de::DeserializeOwned, +{ + fn name(&self) -> &str { + &self.name + } +}