1 //! Test case generators. 2 //! 3 //! Test case generators take raw, unstructured input from a fuzzer 4 //! (e.g. libFuzzer) and translate that into a structured test case (e.g. a 5 //! valid Wasm binary). 6 //! 7 //! These are generally implementations of the `Arbitrary` trait, or some 8 //! wrapper over an external tool, such that the wrapper implements the 9 //! `Arbitrary` trait for the wrapped external tool. 10 11 #[cfg(feature = "binaryen")] 12 pub mod api; 13 14 use arbitrary::Arbitrary; 15 16 /// A Wasm test case generator that is powered by Binaryen's `wasm-opt -ttf`. 17 #[derive(Clone)] 18 #[cfg(feature = "binaryen")] 19 pub struct WasmOptTtf { 20 /// The raw, encoded Wasm bytes. 21 pub wasm: Vec<u8>, 22 } 23 24 #[cfg(feature = "binaryen")] 25 impl std::fmt::Debug for WasmOptTtf { 26 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 27 write!( 28 f, 29 "WasmOptTtf {{ wasm: wat::parse_str(r###\"\n{}\n\"###).unwrap() }}", 30 wasmprinter::print_bytes(&self.wasm).expect("valid wasm should always disassemble") 31 ) 32 } 33 } 34 35 #[cfg(feature = "binaryen")] 36 impl Arbitrary for WasmOptTtf { 37 fn arbitrary(input: &mut arbitrary::Unstructured) -> arbitrary::Result<Self> { 38 crate::init_fuzzing(); 39 let seed: Vec<u8> = Arbitrary::arbitrary(input)?; 40 let module = binaryen::tools::translate_to_fuzz_mvp(&seed); 41 let wasm = module.write(); 42 Ok(WasmOptTtf { wasm }) 43 } 44 45 fn arbitrary_take_rest(input: arbitrary::Unstructured) -> arbitrary::Result<Self> { 46 crate::init_fuzzing(); 47 let seed: Vec<u8> = Arbitrary::arbitrary_take_rest(input)?; 48 let module = binaryen::tools::translate_to_fuzz_mvp(&seed); 49 let wasm = module.write(); 50 Ok(WasmOptTtf { wasm }) 51 } 52 53 fn size_hint(depth: usize) -> (usize, Option<usize>) { 54 <Vec<u8> as Arbitrary>::size_hint(depth) 55 } 56 } 57 58 /// A description of configuration options that we should do differential 59 /// testing between. 60 #[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)] 61 pub struct DifferentialConfig { 62 strategy: DifferentialStrategy, 63 opt_level: DifferentialOptLevel, 64 } 65 66 impl DifferentialConfig { 67 /// Convert this differential fuzzing config into a `wasmtime::Config`. 68 pub fn to_wasmtime_config(&self) -> anyhow::Result<wasmtime::Config> { 69 let mut config = wasmtime::Config::new(); 70 config.cranelift_debug_verifier(true); 71 config.strategy(match self.strategy { 72 DifferentialStrategy::Cranelift => wasmtime::Strategy::Cranelift, 73 DifferentialStrategy::Lightbeam => wasmtime::Strategy::Lightbeam, 74 })?; 75 config.cranelift_opt_level(match self.opt_level { 76 DifferentialOptLevel::None => wasmtime::OptLevel::None, 77 DifferentialOptLevel::Speed => wasmtime::OptLevel::Speed, 78 DifferentialOptLevel::SpeedAndSize => wasmtime::OptLevel::SpeedAndSize, 79 }); 80 Ok(config) 81 } 82 } 83 84 #[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)] 85 enum DifferentialStrategy { 86 Cranelift, 87 Lightbeam, 88 } 89 90 #[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)] 91 enum DifferentialOptLevel { 92 None, 93 Speed, 94 SpeedAndSize, 95 } 96