xref: /wasmtime-44.0.1/crates/fuzzing/src/lib.rs (revision e2f9ca6b)
1 //! Fuzzing infrastructure for Wasmtime.
2 
3 #![deny(missing_docs)]
4 
5 use std::task::{Context, Poll, Waker};
6 
7 pub use wasm_mutate;
8 pub use wasm_smith;
9 pub mod generators;
10 pub mod mutators;
11 pub mod oom;
12 pub mod oracles;
13 pub mod single_module_fuzzer;
14 
15 /// One time start up initialization for fuzzing:
16 ///
17 /// * Enables `env_logger`.
18 ///
19 /// * Restricts `rayon` to a single thread in its thread pool, for more
20 ///   deterministic executions.
21 ///
22 /// If a fuzz target is taking raw input bytes from the fuzzer, it is fine to
23 /// call this function in the fuzz target's oracle or in the fuzz target
24 /// itself. However, if the fuzz target takes an `Arbitrary` type, and the
25 /// `Arbitrary` implementation is not derived and does interesting things, then
26 /// the `Arbitrary` implementation should call this function, since it runs
27 /// before the fuzz target itself.
28 pub fn init_fuzzing() {
29     static INIT: std::sync::Once = std::sync::Once::new();
30 
31     INIT.call_once(|| {
32         let _ = env_logger::try_init();
33     });
34 }
35 
36 fn block_on<F: Future>(future: F) -> F::Output {
37     let mut f = Box::pin(future);
38     let mut cx = Context::from_waker(Waker::noop());
39     loop {
40         match f.as_mut().poll(&mut cx) {
41             Poll::Ready(val) => break val,
42             Poll::Pending => {}
43         }
44     }
45 }
46 
47 #[cfg(test)]
48 mod test {
49     use arbitrary::{Arbitrary, Unstructured};
50     use rand::prelude::*;
51 
52     pub fn gen_until_pass<T: for<'a> Arbitrary<'a>>(
53         mut f: impl FnMut(T, &mut Unstructured<'_>) -> anyhow::Result<bool>,
54     ) -> bool {
55         let mut rng = SmallRng::seed_from_u64(0);
56         let mut buf = vec![0; 2048];
57         let n = 3000;
58         for _ in 0..n {
59             rng.fill_bytes(&mut buf);
60             let mut u = Unstructured::new(&buf);
61 
62             if let Ok(config) = u.arbitrary() {
63                 if f(config, &mut u).unwrap() {
64                     return true;
65                 }
66             }
67         }
68         false
69     }
70 
71     /// Runs `f` with random data until it returns `Ok(())` `iters` times.
72     pub fn test_n_times<T: for<'a> Arbitrary<'a>>(
73         iters: u32,
74         mut f: impl FnMut(T, &mut Unstructured<'_>) -> arbitrary::Result<()>,
75     ) {
76         let mut to_test = 0..iters;
77         let ok = gen_until_pass(|a, b| {
78             if f(a, b).is_ok() {
79                 Ok(to_test.next().is_none())
80             } else {
81                 Ok(false)
82             }
83         });
84         assert!(ok);
85     }
86 }
87