Skip to content

Commit 5a2652b

Browse files
riesentoastertokatoka
andauthoredJun 14, 2024··
Adding StdXObserver Docs (#2311)
* Adding StdXObserver Docs * fixing docs * code cleanup * moving example * improving exclusion rules * adding impls for features * adding test exclusions * excluding miri from OS including tests * fixing CI --------- Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
1 parent c3930b3 commit 5a2652b

File tree

3 files changed

+199
-2
lines changed

3 files changed

+199
-2
lines changed
 

‎libafl/src/fuzzer/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,7 @@ where
772772
}
773773
}
774774

775-
/// Runs the input and triggers observers and feedback
775+
/// Runs the input and triggers observers
776776
pub fn execute_input<E, EM>(
777777
&mut self,
778778
state: &mut <Self as UsesState>::State,

‎libafl/src/mutators/mod.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub use multi::*;
3333
#[cfg(feature = "nautilus")]
3434
pub mod nautilus;
3535

36-
use alloc::{boxed::Box, vec::Vec};
36+
use alloc::{borrow::Cow, boxed::Box, vec::Vec};
3737

3838
use libafl_bolts::{tuples::IntoVec, HasLen, Named};
3939
#[cfg(feature = "nautilus")]
@@ -407,3 +407,35 @@ impl<I, S> IntoVec<Box<dyn Mutator<I, S>>> for Vec<Box<dyn Mutator<I, S>>> {
407407
self
408408
}
409409
}
410+
411+
/// [`Mutator`] that does nothing, used for testing.
412+
///
413+
/// Example:
414+
///
415+
/// ```rust,ignore
416+
/// let mut stages = tuple_list!(StdMutationalStage::new(NopMutator(MutationResult::Mutated)));
417+
/// ```
418+
#[derive(Debug, Clone)]
419+
pub struct NopMutator {
420+
result: MutationResult,
421+
}
422+
423+
impl NopMutator {
424+
/// The passed argument is returned every time the mutator is called.
425+
#[must_use]
426+
pub fn new(result: MutationResult) -> Self {
427+
Self { result }
428+
}
429+
}
430+
431+
impl<I, S> Mutator<I, S> for NopMutator {
432+
fn mutate(&mut self, _state: &mut S, _input: &mut I) -> Result<MutationResult, Error> {
433+
Ok(self.result)
434+
}
435+
}
436+
437+
impl Named for NopMutator {
438+
fn name(&self) -> &Cow<'static, str> {
439+
&Cow::Borrowed("NopMutator")
440+
}
441+
}

‎libafl/src/observers/stdio.rs

+165
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,159 @@ use crate::{inputs::UsesInput, observers::Observer, state::State, Error};
1212

1313
/// An observer that captures stdout of a target.
1414
/// Only works for supported executors.
15+
///
16+
/// # Example usage
17+
#[cfg_attr(all(feature = "std", target_os = "linux", not(miri)), doc = " ```")] // miri doesn't like the Command crate, linux as a shorthand for the availability of base64
18+
#[cfg_attr(
19+
not(all(feature = "std", target_os = "linux", not(miri))),
20+
doc = " ```ignore"
21+
)]
22+
/// use std::borrow::Cow;
23+
///
24+
/// use libafl::{
25+
/// corpus::{Corpus, InMemoryCorpus, Testcase},
26+
/// events::{EventFirer, NopEventManager},
27+
/// executors::{CommandExecutor, ExitKind},
28+
/// feedbacks::Feedback,
29+
/// inputs::{BytesInput, UsesInput},
30+
/// mutators::{MutationResult, NopMutator},
31+
/// observers::{ObserversTuple, StdErrObserver, StdOutObserver},
32+
/// schedulers::QueueScheduler,
33+
/// stages::StdMutationalStage,
34+
/// state::{HasCorpus, State, StdState},
35+
/// Error, Fuzzer, StdFuzzer,
36+
/// };
37+
///
38+
/// use libafl_bolts::{
39+
/// current_nanos,
40+
/// rands::StdRand,
41+
/// tuples::{tuple_list, Handle, Handled, MatchNameRef},
42+
/// Named,
43+
/// };
44+
///
45+
/// static mut STDOUT: Option<Vec<u8>> = None;
46+
/// static mut STDERR: Option<Vec<u8>> = None;
47+
///
48+
/// #[derive(Clone)]
49+
/// struct ExportStdXObserver {
50+
/// stdout_observer: Handle<StdOutObserver>,
51+
/// stderr_observer: Handle<StdErrObserver>,
52+
/// }
53+
///
54+
/// impl<S> Feedback<S> for ExportStdXObserver
55+
/// where
56+
/// S: State
57+
/// {
58+
/// fn is_interesting<EM, OT>(
59+
/// &mut self,
60+
/// _state: &mut S,
61+
/// _manager: &mut EM,
62+
/// _input: &<S>::Input,
63+
/// observers: &OT,
64+
/// _exit_kind: &ExitKind,
65+
/// ) -> Result<bool, Error>
66+
/// where
67+
/// EM: EventFirer<State = S>,
68+
/// OT: ObserversTuple<S>,
69+
/// {
70+
/// unsafe {
71+
/// STDOUT = observers.get(&self.stdout_observer).unwrap().stdout.clone();
72+
/// STDERR = observers.get(&self.stderr_observer).unwrap().stderr.clone();
73+
/// }
74+
/// Ok(true)
75+
/// }
76+
///
77+
/// #[cfg(feature = "track_hit_feedbacks")]
78+
/// fn last_result(&self) -> Result<bool, Error> {
79+
/// Ok(true)
80+
/// }
81+
/// }
82+
///
83+
/// impl Named for ExportStdXObserver {
84+
/// fn name(&self) -> &Cow<'static, str> {
85+
/// &Cow::Borrowed("ExportStdXObserver")
86+
/// }
87+
/// }
88+
///
89+
/// fn main() {
90+
/// let input_text = "Hello, World!";
91+
/// let encoded_input_text = "SGVsbG8sIFdvcmxkIQo=";
92+
///
93+
/// let stdout_observer = StdOutObserver::new("stdout-observer");
94+
/// let stderr_observer = StdErrObserver::new("stderr-observer");
95+
///
96+
/// let mut feedback = ExportStdXObserver {
97+
/// stdout_observer: stdout_observer.handle(),
98+
/// stderr_observer: stderr_observer.handle(),
99+
/// };
100+
///
101+
/// let mut objective = ();
102+
///
103+
/// let mut executor = CommandExecutor::builder()
104+
/// .program("base64")
105+
/// .arg("--decode")
106+
/// .stdout_observer(stdout_observer.handle())
107+
/// .stderr_observer(stderr_observer.handle())
108+
/// .build(tuple_list!(stdout_observer, stderr_observer))
109+
/// .unwrap();
110+
///
111+
/// let mut state = StdState::new(
112+
/// StdRand::with_seed(current_nanos()),
113+
/// InMemoryCorpus::new(),
114+
/// InMemoryCorpus::new(),
115+
/// &mut feedback,
116+
/// &mut objective,
117+
/// )
118+
/// .unwrap();
119+
///
120+
/// let scheduler = QueueScheduler::new();
121+
/// let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
122+
/// let mut manager = NopEventManager::new();
123+
///
124+
/// let mut stages = tuple_list!(StdMutationalStage::new(NopMutator::new(
125+
/// MutationResult::Mutated
126+
/// )));
127+
///
128+
/// state
129+
/// .corpus_mut()
130+
/// .add(Testcase::new(BytesInput::from(
131+
/// encoded_input_text.as_bytes().to_vec(),
132+
/// )))
133+
/// .unwrap();
134+
///
135+
/// let corpus_id = fuzzer
136+
/// .fuzz_one(&mut stages, &mut executor, &mut state, &mut manager)
137+
/// .unwrap();
138+
///
139+
/// unsafe {
140+
/// assert!(input_text
141+
/// .as_bytes()
142+
/// .iter()
143+
/// .zip(STDOUT.as_ref().unwrap().iter().filter(|e| **e != 10)) // ignore newline chars
144+
/// .all(|(&a, &b)| a == b));
145+
/// assert!(STDERR.as_ref().unwrap().is_empty());
146+
/// }
147+
///
148+
/// state
149+
/// .corpus()
150+
/// .get(corpus_id)
151+
/// .unwrap()
152+
/// .replace(Testcase::new(BytesInput::from(
153+
/// encoded_input_text.bytes().skip(1).collect::<Vec<u8>>(), // skip one char to make it invalid code
154+
/// )));
155+
///
156+
/// fuzzer
157+
/// .fuzz_one(&mut stages, &mut executor, &mut state, &mut manager)
158+
/// .unwrap();
159+
///
160+
/// unsafe {
161+
/// let compare_vec: Vec<u8> = Vec::new();
162+
/// assert_eq!(compare_vec, *STDERR.as_ref().unwrap());
163+
/// // stdout will still contain data, we're just checking that there is an error message
164+
/// }
165+
/// }
166+
/// ```
167+
15168
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
16169
pub struct StdOutObserver {
17170
/// The name of the observer.
@@ -55,10 +208,17 @@ where
55208
self.stdout = None;
56209
Ok(())
57210
}
211+
212+
fn pre_exec(&mut self, _state: &mut S, _input: &<S as UsesInput>::Input) -> Result<(), Error> {
213+
self.stdout = None;
214+
Ok(())
215+
}
58216
}
59217

60218
/// An observer that captures stderr of a target.
61219
/// Only works for supported executors.
220+
///
221+
/// Check docs for [`StdOutObserver`] for example.
62222
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
63223
pub struct StdErrObserver {
64224
/// The name of the observer.
@@ -102,4 +262,9 @@ where
102262
self.stderr = None;
103263
Ok(())
104264
}
265+
266+
fn pre_exec(&mut self, _state: &mut S, _input: &<S as UsesInput>::Input) -> Result<(), Error> {
267+
self.stderr = None;
268+
Ok(())
269+
}
105270
}

0 commit comments

Comments
 (0)
Please sign in to comment.