Add RefCellValueObserver (#1363)

* add RefCellValueObserver

* appease the clippy gods

* Update libafl/src/observers/value.rs

Co-authored-by: Langston Barrett <langston.barrett@gmail.com>

---------

Co-authored-by: Langston Barrett <langston.barrett@gmail.com>
This commit is contained in:
Addison Crump 2023-07-13 18:02:02 +02:00 committed by GitHub
parent a95b322b1c
commit f76331eac7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -5,8 +5,10 @@ use alloc::{
string::{String, ToString}, string::{String, ToString},
}; };
use core::{ use core::{
cell::{Ref, RefCell},
fmt::Debug, fmt::Debug,
hash::{BuildHasher, Hash, Hasher}, hash::{BuildHasher, Hash, Hasher},
ops::Deref,
}; };
use ahash::RandomState; use ahash::RandomState;
@ -22,9 +24,8 @@ use crate::{
/// A simple observer with a single value. /// A simple observer with a single value.
/// ///
/// The intent is that the value is something with interior mutability (e.g., a /// The intent is that the value is something with interior mutability which the target could write to even though this
/// `RefCell`), which the target could write to even though this observer has a /// observer has a reference to it. Use [`RefCellValueObserver`] if using a [`RefCell`] around the value.
/// reference to it.
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")] #[serde(bound = "T: serde::de::DeserializeOwned")]
pub struct ValueObserver<'a, T> pub struct ValueObserver<'a, T>
@ -104,3 +105,87 @@ where
Some(s.finish()) Some(s.finish())
} }
} }
/// A simple observer with a single [`RefCell`]'d value.
#[derive(Serialize, Deserialize, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")]
pub struct RefCellValueObserver<'a, T>
where
T: Debug + Serialize,
{
/// The name of this observer.
name: String,
/// The value.
pub value: OwnedRef<'a, RefCell<T>>,
}
impl<'a, T> RefCellValueObserver<'a, T>
where
T: Debug + Serialize + serde::de::DeserializeOwned,
{
/// Creates a new [`RefCellValueObserver`] with the given name.
#[must_use]
pub fn new(name: &'static str, value: &'a RefCell<T>) -> Self {
Self {
name: name.to_string(),
value: OwnedRef::Ref(value),
}
}
/// Get a reference to the underlying value.
#[must_use]
pub fn get_ref<'b>(&'b self) -> Ref<'a, T>
where
'b: 'a,
{
self.value.as_ref().borrow()
}
/// Set the value.
pub fn set(&mut self, new_value: T) {
self.value.as_ref().replace(new_value);
}
/// Clone or move the current value out of this object.
#[must_use]
pub fn take(self) -> T
where
T: Clone,
{
match self.value {
OwnedRef::Ref(r) => r.borrow().deref().clone(),
OwnedRef::Owned(v) => v.borrow().clone(),
}
}
}
/// This *does not* reset the value inside the observer.
impl<'a, S, T> Observer<S> for RefCellValueObserver<'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 RefCellValueObserver<'a, T>
where
T: Debug + Serialize + serde::de::DeserializeOwned,
{
fn name(&self) -> &str {
&self.name
}
}
impl<'a, T: Hash> ObserverWithHashField for RefCellValueObserver<'a, T>
where
T: Debug + Serialize + serde::de::DeserializeOwned,
{
fn hash(&self) -> Option<u64> {
let mut s = RandomState::with_seeds(1, 2, 3, 4).build_hasher();
self.value.as_ref().borrow().hash(&mut s);
Some(s.finish())
}
}