Add ValueObserver, an observer for a single value (#923)

* libafl: ValueObserver, a simple and safe observer of a single value

* libafl: Generalize ValueObserver, don't force it to be a RefCell

There are other types with interior mutability that may be more suitable.

Add a few more methods, too.

* libafl: Use OwnedRef in ValueObserver

The previous version had ValueObserver take ownership, but that doesn't
actually work for working with types with interior mutability: both the
observer and the target need to take immutable references.

* libafl: ValueObserver shouldn't reset the contained value

Otherwise, it is useless for containing a `RefCell`.

* libafl: Add doctests to ValueObserver

* libafl: Fix clippy lints

Co-authored-by: Dominik Maier <domenukk@gmail.com>
This commit is contained in:
Langston Barrett 2022-12-04 12:55:04 -05:00 committed by GitHub
parent 8444cf7cc8
commit 2a2e70a636
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 111 additions and 0 deletions

View File

@ -18,6 +18,9 @@ pub use stacktrace::*;
pub mod concolic; 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 // 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)] //#[cfg(unstable_feature)]
//pub mod owned; //pub mod owned;

View File

@ -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<S> 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
}
}