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