Skip to content

Commit 950866a

Browse files
domenukkmzfr
authored andcommitted
Add BoolValueFeedback (AFLplusplus#2815)
* Add BoolValueFeedback * No_std * clippy * Fix tests * More clip * fix no_std tests
1 parent 353de37 commit 950866a

File tree

8 files changed

+222
-43
lines changed

8 files changed

+222
-43
lines changed

libafl/src/events/llmp/restarting.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,13 @@ mod tests {
737737
#[serial]
738738
#[cfg_attr(miri, ignore)]
739739
fn test_mgr_state_restore() {
740+
// # Safety
741+
// The same testcase doesn't usually run twice
742+
#[cfg(any(not(feature = "serdeany_autoreg"), miri))]
743+
unsafe {
744+
crate::stages::RetryCountRestartHelper::register();
745+
}
746+
740747
let rand = StdRand::with_seed(0);
741748

742749
let time = TimeObserver::new("time");

libafl/src/feedbacks/bool.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
//! The [`BoolValueFeedback`] is a [`Feedback`] returning `true` or `false` as the `is_interesting` value.
2+
3+
use alloc::borrow::Cow;
4+
5+
use libafl_bolts::{
6+
tuples::{Handle, MatchNameRef},
7+
Error, Named,
8+
};
9+
10+
use crate::{
11+
feedbacks::{Feedback, StateInitializer},
12+
observers::{ObserversTuple, ValueObserver},
13+
HasNamedMetadata,
14+
};
15+
16+
/// This feedback returns `true` or `false` as the `is_interesting` value.
17+
#[derive(Debug)]
18+
pub struct BoolValueFeedback<'a> {
19+
name: Cow<'static, str>,
20+
observer_hnd: Handle<ValueObserver<'a, bool>>,
21+
#[cfg(feature = "track_hit_feedbacks")]
22+
last_result: Option<bool>,
23+
}
24+
25+
impl<'a> BoolValueFeedback<'a> {
26+
/// Create a new [`BoolValueFeedback`]
27+
#[must_use]
28+
pub fn new(observer_hnd: &Handle<ValueObserver<'a, bool>>) -> Self {
29+
Self::with_name(observer_hnd.name().clone(), observer_hnd)
30+
}
31+
32+
/// Create a new [`BoolValueFeedback`] with a given name
33+
#[must_use]
34+
pub fn with_name(
35+
name: Cow<'static, str>,
36+
observer_hnd: &Handle<ValueObserver<'a, bool>>,
37+
) -> Self {
38+
Self {
39+
name,
40+
observer_hnd: observer_hnd.clone(),
41+
#[cfg(feature = "track_hit_feedbacks")]
42+
last_result: None,
43+
}
44+
}
45+
}
46+
47+
impl Named for BoolValueFeedback<'_> {
48+
fn name(&self) -> &Cow<'static, str> {
49+
&self.name
50+
}
51+
}
52+
53+
impl<S> StateInitializer<S> for BoolValueFeedback<'_> {
54+
fn init_state(&mut self, _state: &mut S) -> Result<(), Error> {
55+
Ok(())
56+
}
57+
}
58+
59+
impl<EM, I, OT, S> Feedback<EM, I, OT, S> for BoolValueFeedback<'_>
60+
where
61+
OT: ObserversTuple<I, S>,
62+
S: HasNamedMetadata,
63+
{
64+
fn is_interesting(
65+
&mut self,
66+
_state: &mut S,
67+
_manager: &mut EM,
68+
_input: &I,
69+
observers: &OT,
70+
_exit_kind: &crate::executors::ExitKind,
71+
) -> Result<bool, Error> {
72+
let Some(observer) = observers.get(&self.observer_hnd) else {
73+
return Err(Error::illegal_state(format!(
74+
"Observer {:?} not found",
75+
self.observer_hnd
76+
)));
77+
};
78+
79+
let val = observer.value.as_ref();
80+
81+
Ok(*val)
82+
}
83+
84+
fn append_metadata(
85+
&mut self,
86+
_state: &mut S,
87+
_manager: &mut EM,
88+
_observers: &OT,
89+
_testcase: &mut crate::corpus::Testcase<I>,
90+
) -> Result<(), Error> {
91+
Ok(())
92+
}
93+
94+
fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
95+
Ok(())
96+
}
97+
98+
#[cfg(feature = "track_hit_feedbacks")]
99+
fn last_result(&self) -> Result<bool, Error> {
100+
self.last_result.ok_or_else(|| Error::illegal_state("No last result set in `BoolValuefeedback`. Either `is_interesting` has never been called or the fuzzer restarted in the meantime."))
101+
}
102+
}
103+
104+
#[cfg(test)]
105+
mod test {
106+
use core::{cell::UnsafeCell, ptr::write_volatile};
107+
108+
use libafl_bolts::{ownedref::OwnedRef, tuples::Handled};
109+
use tuple_list::tuple_list;
110+
111+
use crate::{
112+
executors::ExitKind,
113+
feedbacks::{BoolValueFeedback, Feedback, StateInitializer},
114+
observers::ValueObserver,
115+
state::NopState,
116+
};
117+
118+
#[test]
119+
fn test_bool_value_feedback() {
120+
let value: UnsafeCell<bool> = false.into();
121+
122+
// # Safety
123+
// The value is only read from in the feedback, not while we change the value.
124+
let value_ptr = unsafe { OwnedRef::from_ptr(value.get()) };
125+
126+
let observer = ValueObserver::new("test_value", value_ptr);
127+
128+
let mut bool_feedback = BoolValueFeedback::new(&observer.handle());
129+
130+
let mut state: NopState<()> = NopState::new();
131+
bool_feedback.init_state(&mut state).unwrap();
132+
133+
let observers = tuple_list!(observer);
134+
let mut mgr = ();
135+
let input = ();
136+
let exit_ok = ExitKind::Ok;
137+
138+
let false_eval = bool_feedback
139+
.is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok)
140+
.unwrap();
141+
assert!(!false_eval);
142+
143+
// # Safety
144+
// The feedback is not keeping a borrow around, only the pointer.
145+
unsafe {
146+
write_volatile(value.get(), true);
147+
}
148+
149+
let true_eval = bool_feedback
150+
.is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok)
151+
.unwrap();
152+
assert!(true_eval);
153+
}
154+
}

libafl/src/feedbacks/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ use crate::{corpus::Testcase, executors::ExitKind, observers::TimeObserver, Erro
3131
#[cfg(feature = "std")]
3232
pub mod capture_feedback;
3333

34+
pub mod bool;
35+
pub use bool::BoolValueFeedback;
36+
3437
#[cfg(feature = "std")]
3538
pub mod concolic;
3639
#[cfg(feature = "std")]

libafl/src/feedbacks/new_hash_feedback.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! The ``NewHashFeedback`` uses the backtrace hash and a hashset to only keep novel cases
1+
//! The [`NewHashFeedback`] uses the backtrace hash and a hashset to only keep novel cases
22
33
use alloc::{borrow::Cow, string::ToString};
44
use std::fmt::Debug;

libafl/src/feedbacks/value_bloom.rs

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ use libafl_bolts::{
1212
};
1313
use serde::{Deserialize, Serialize};
1414

15-
use super::{Feedback, StateInitializer};
1615
use crate::{
1716
executors::ExitKind,
17+
feedbacks::{Feedback, StateInitializer},
1818
observers::{ObserversTuple, ValueObserver},
1919
HasNamedMetadata,
2020
};
@@ -117,73 +117,66 @@ impl<EM, I, OT: ObserversTuple<I, S>, S: HasNamedMetadata, T: Hash> Feedback<EM,
117117

118118
#[cfg(test)]
119119
mod test {
120-
use core::ptr::write_volatile;
120+
use core::{cell::UnsafeCell, ptr::write_volatile};
121121

122-
use libafl_bolts::{ownedref::OwnedRef, serdeany::NamedSerdeAnyMap, tuples::Handled};
122+
use libafl_bolts::{ownedref::OwnedRef, tuples::Handled};
123123
use tuple_list::tuple_list;
124124

125125
use super::ValueBloomFeedback;
126126
use crate::{
127-
events::NopEventManager,
128127
executors::ExitKind,
129128
feedbacks::{Feedback, StateInitializer},
130-
inputs::NopInput,
131129
observers::ValueObserver,
132-
HasNamedMetadata,
130+
state::NopState,
133131
};
134132

135-
static mut VALUE: u32 = 0;
136-
137-
struct NamedMetadataState {
138-
map: NamedSerdeAnyMap,
139-
}
133+
#[test]
134+
fn test_value_bloom_feedback() {
135+
let value: UnsafeCell<u32> = 0_u32.into();
140136

141-
impl HasNamedMetadata for NamedMetadataState {
142-
fn named_metadata_map(&self) -> &NamedSerdeAnyMap {
143-
&self.map
137+
// # Safety
138+
// The same testcase doesn't usually run twice
139+
#[cfg(any(not(feature = "serdeany_autoreg"), miri))]
140+
unsafe {
141+
super::ValueBloomFeedbackMetadata::register();
144142
}
145143

146-
fn named_metadata_map_mut(&mut self) -> &mut NamedSerdeAnyMap {
147-
&mut self.map
148-
}
149-
}
150-
151-
#[test]
152-
fn test_value_bloom_feedback() {
153-
let value_ptr = unsafe { OwnedRef::from_ptr(&raw mut VALUE) };
144+
// # Safety
145+
// The value is only read from in the feedback, not while we change the value.
146+
let value_ptr = unsafe { OwnedRef::from_ptr(value.get()) };
154147

155148
let observer = ValueObserver::new("test_value", value_ptr);
156-
157149
let mut vbf = ValueBloomFeedback::new(&observer.handle());
158150

159-
let mut state = NamedMetadataState {
160-
map: NamedSerdeAnyMap::new(),
161-
};
162-
vbf.init_state(&mut state).unwrap();
163-
164151
let observers = tuple_list!(observer);
165-
let mut mgr = NopEventManager::<NamedMetadataState>::new();
166-
let input = NopInput {};
152+
153+
let mut state: NopState<()> = NopState::new();
154+
let mut mgr = ();
155+
let input = ();
167156
let exit_ok = ExitKind::Ok;
168157

158+
vbf.init_state(&mut state).unwrap();
159+
169160
let first_eval = vbf
170161
.is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok)
171162
.unwrap();
172-
assert_eq!(first_eval, true);
163+
assert!(first_eval);
173164

174165
let second_eval = vbf
175166
.is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok)
176167
.unwrap();
177168

178-
assert_ne!(first_eval, second_eval);
169+
assert!(!second_eval);
179170

171+
// # Safety
172+
// The feedback is not keeping a borrow around, only the pointer.
180173
unsafe {
181-
write_volatile(&raw mut VALUE, 1234_u32);
174+
write_volatile(value.get(), 1234_u32);
182175
}
183176

184177
let next_eval = vbf
185178
.is_interesting(&mut state, &mut mgr, &input, &observers, &exit_ok)
186179
.unwrap();
187-
assert_eq!(next_eval, true);
180+
assert!(next_eval);
188181
}
189182
}

libafl/src/inputs/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,23 @@ macro_rules! none_input_converter {
116116
}
117117

118118
/// An input for tests, mainly. There is no real use much else.
119-
#[derive(Copy, Clone, Serialize, Deserialize, Debug, Hash)]
119+
#[derive(Copy, Clone, Serialize, Deserialize, Debug, Default, Hash)]
120120
pub struct NopInput {}
121+
122+
impl NopInput {
123+
/// Creates a new [`NopInput`]
124+
#[must_use]
125+
pub fn new() -> Self {
126+
Self {}
127+
}
128+
}
129+
121130
impl Input for NopInput {
122131
fn generate_name(&self, _id: Option<CorpusId>) -> String {
123132
"nop-input".to_string()
124133
}
125134
}
135+
126136
impl HasTargetBytes for NopInput {
127137
fn target_bytes(&self) -> OwnedSlice<u8> {
128138
OwnedSlice::from(vec![0])

libafl/src/stages/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -612,13 +612,6 @@ mod test {
612612
/// Test to test retries in stages
613613
#[test]
614614
fn test_tries_progress() -> Result<(), Error> {
615-
// # Safety
616-
// No concurrency per testcase
617-
#[cfg(any(not(feature = "serdeany_autoreg"), miri))]
618-
unsafe {
619-
RetryCountRestartHelper::register();
620-
}
621-
622615
struct StageWithOneTry;
623616

624617
impl Named for StageWithOneTry {
@@ -628,6 +621,13 @@ mod test {
628621
}
629622
}
630623

624+
// # Safety
625+
// No concurrency per testcase
626+
#[cfg(any(not(feature = "serdeany_autoreg"), miri))]
627+
unsafe {
628+
RetryCountRestartHelper::register();
629+
}
630+
631631
let mut state = StdState::nop()?;
632632
let stage = StageWithOneTry;
633633

libafl/src/state/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,6 +1242,7 @@ impl<I, C, R, SC> HasScalabilityMonitor for StdState<I, C, R, SC> {
12421242
#[derive(Debug, Serialize, Deserialize, Default)]
12431243
pub struct NopState<I> {
12441244
metadata: SerdeAnyMap,
1245+
named_metadata: NamedSerdeAnyMap,
12451246
execution: u64,
12461247
stop_requested: bool,
12471248
rand: StdRand,
@@ -1254,6 +1255,7 @@ impl<I> NopState<I> {
12541255
pub fn new() -> Self {
12551256
NopState {
12561257
metadata: SerdeAnyMap::new(),
1258+
named_metadata: NamedSerdeAnyMap::new(),
12571259
execution: 0,
12581260
rand: StdRand::default(),
12591261
stop_requested: false,
@@ -1323,6 +1325,16 @@ impl<I> HasMetadata for NopState<I> {
13231325
}
13241326
}
13251327

1328+
impl<I> HasNamedMetadata for NopState<I> {
1329+
fn named_metadata_map(&self) -> &NamedSerdeAnyMap {
1330+
&self.named_metadata
1331+
}
1332+
1333+
fn named_metadata_map_mut(&mut self) -> &mut NamedSerdeAnyMap {
1334+
&mut self.named_metadata
1335+
}
1336+
}
1337+
13261338
impl<I> HasRand for NopState<I> {
13271339
type Rand = StdRand;
13281340

0 commit comments

Comments
 (0)