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. 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. 50 pub fn misc_init() { 51 init_fuzzing(); 52 oracles::component_async::init(); 53 } 54 55 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 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 92 pub fn gen_until_pass<T: for<'a> Arbitrary<'a>>( 93 mut f: impl FnMut(T, &mut Unstructured<'_>) -> anyhow::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. 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