xref: /wasmtime-44.0.1/crates/fuzzing/src/lib.rs (revision 93d22fcd)
1 //! Fuzzing infrastructure for Wasmtime.
2 
3 #![deny(missing_docs)]
4 
5 use std::pin::Pin;
6 use std::task::{Context, Poll, Waker};
7 
8 pub use wasm_mutate;
9 pub use wasm_smith;
10 pub mod generators;
11 pub mod mutators;
12 pub mod oom;
13 pub mod oracles;
14 pub mod single_module_fuzzer;
15 
16 /// One time start up initialization for fuzzing:
17 ///
18 /// * Enables `env_logger`.
19 ///
20 /// * Restricts `rayon` to a single thread in its thread pool, for more
21 ///   deterministic executions.
22 ///
23 /// If a fuzz target is taking raw input bytes from the fuzzer, it is fine to
24 /// call this function in the fuzz target's oracle or in the fuzz target
25 /// itself. However, if the fuzz target takes an `Arbitrary` type, and the
26 /// `Arbitrary` implementation is not derived and does interesting things, then
27 /// the `Arbitrary` implementation should call this function, since it runs
28 /// before the fuzz target itself.
init_fuzzing()29 pub fn init_fuzzing() {
30     static INIT: std::sync::Once = std::sync::Once::new();
31 
32     INIT.call_once(|| {
33         let _ = env_logger::try_init();
34     });
35 }
36 
37 /// One time start up initialization for fuzzing:
38 ///
39 /// * Enables `env_logger`.
40 ///
41 /// * Restricts `rayon` to a single thread in its thread pool, for more
42 ///   deterministic executions.
43 ///
44 /// If a fuzz target is taking raw input bytes from the fuzzer, it is fine to
45 /// call this function in the fuzz target's oracle or in the fuzz target
46 /// itself. However, if the fuzz target takes an `Arbitrary` type, and the
47 /// `Arbitrary` implementation is not derived and does interesting things, then
48 /// the `Arbitrary` implementation should call this function, since it runs
49 /// before the fuzz target itself.
misc_init()50 pub fn misc_init() {
51     init_fuzzing();
52     oracles::component_async::init();
53 }
54 
block_on<F: Future>(future: F) -> F::Output55 fn block_on<F: Future>(future: F) -> F::Output {
56     const MAX_POLLS: u32 = 100_000;
57 
58     let mut f = Box::pin(future);
59     let mut cx = Context::from_waker(Waker::noop());
60     for _ in 0..MAX_POLLS {
61         match f.as_mut().poll(&mut cx) {
62             Poll::Ready(val) => return val,
63             Poll::Pending => {}
64         }
65     }
66 
67     panic!("future didn't become ready")
68 }
69 
70 /// Helper future to yield N times before resolving.
71 struct YieldN(u32);
72 
73 impl Future for YieldN {
74     type Output = ();
75 
poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()>76     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
77         if self.0 == 0 {
78             Poll::Ready(())
79         } else {
80             self.0 -= 1;
81             cx.waker().wake_by_ref();
82             Poll::Pending
83         }
84     }
85 }
86 
87 #[cfg(test)]
88 mod test {
89     use arbitrary::{Arbitrary, Unstructured};
90     use rand::prelude::*;
91 
gen_until_pass<T: for<'a> Arbitrary<'a>>( mut f: impl FnMut(T, &mut Unstructured<'_>) -> wasmtime::Result<bool>, ) -> bool92     pub fn gen_until_pass<T: for<'a> Arbitrary<'a>>(
93         mut f: impl FnMut(T, &mut Unstructured<'_>) -> wasmtime::Result<bool>,
94     ) -> bool {
95         let mut rng = SmallRng::seed_from_u64(0);
96         let mut buf = vec![0; 2048];
97         let n = 3000;
98         for _ in 0..n {
99             rng.fill_bytes(&mut buf);
100             let mut u = Unstructured::new(&buf);
101 
102             if let Ok(config) = u.arbitrary() {
103                 if f(config, &mut u).unwrap() {
104                     return true;
105                 }
106             }
107         }
108         false
109     }
110 
111     /// Runs `f` with random data until it returns `Ok(())` `iters` times.
test_n_times<T: for<'a> Arbitrary<'a>>( iters: u32, mut f: impl FnMut(T, &mut Unstructured<'_>) -> arbitrary::Result<()>, )112     pub fn test_n_times<T: for<'a> Arbitrary<'a>>(
113         iters: u32,
114         mut f: impl FnMut(T, &mut Unstructured<'_>) -> arbitrary::Result<()>,
115     ) {
116         let mut to_test = 0..iters;
117         let ok = gen_until_pass(|a, b| {
118             if f(a, b).is_ok() {
119                 Ok(to_test.next().is_none())
120             } else {
121                 Ok(false)
122             }
123         });
124         assert!(ok);
125     }
126 }
127