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 pub mod api; 12 13 pub mod table_ops; 14 15 use arbitrary::{Arbitrary, Unstructured}; 16 17 /// A description of configuration options that we should do differential 18 /// testing between. 19 #[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)] 20 pub struct DifferentialConfig { 21 strategy: DifferentialStrategy, 22 opt_level: OptLevel, 23 } 24 25 impl DifferentialConfig { 26 /// Convert this differential fuzzing config into a `wasmtime::Config`. 27 pub fn to_wasmtime_config(&self) -> anyhow::Result<wasmtime::Config> { 28 let mut config = crate::fuzz_default_config(match self.strategy { 29 DifferentialStrategy::Cranelift => wasmtime::Strategy::Cranelift, 30 DifferentialStrategy::Lightbeam => wasmtime::Strategy::Lightbeam, 31 })?; 32 config.cranelift_opt_level(self.opt_level.to_wasmtime()); 33 Ok(config) 34 } 35 } 36 37 #[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)] 38 enum DifferentialStrategy { 39 Cranelift, 40 Lightbeam, 41 } 42 43 #[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)] 44 enum OptLevel { 45 None, 46 Speed, 47 SpeedAndSize, 48 } 49 50 impl OptLevel { 51 fn to_wasmtime(&self) -> wasmtime::OptLevel { 52 match self { 53 OptLevel::None => wasmtime::OptLevel::None, 54 OptLevel::Speed => wasmtime::OptLevel::Speed, 55 OptLevel::SpeedAndSize => wasmtime::OptLevel::SpeedAndSize, 56 } 57 } 58 } 59 60 /// Implementation of generating a `wasmtime::Config` arbitrarily 61 #[derive(Arbitrary, Debug)] 62 pub struct Config { 63 opt_level: OptLevel, 64 debug_info: bool, 65 canonicalize_nans: bool, 66 interruptable: bool, 67 #[allow(missing_docs)] 68 pub consume_fuel: bool, 69 70 // Note that we use 32-bit values here to avoid blowing the 64-bit address 71 // space by requesting ungodly-large sizes/guards. 72 static_memory_maximum_size: Option<u32>, 73 static_memory_guard_size: Option<u32>, 74 dynamic_memory_guard_size: Option<u32>, 75 } 76 77 impl Config { 78 /// Converts this to a `wasmtime::Config` object 79 pub fn to_wasmtime(&self) -> wasmtime::Config { 80 let mut cfg = crate::fuzz_default_config(wasmtime::Strategy::Auto).unwrap(); 81 cfg.debug_info(self.debug_info) 82 .static_memory_maximum_size(self.static_memory_maximum_size.unwrap_or(0).into()) 83 .static_memory_guard_size(self.static_memory_guard_size.unwrap_or(0).into()) 84 .dynamic_memory_guard_size(self.dynamic_memory_guard_size.unwrap_or(0).into()) 85 .cranelift_nan_canonicalization(self.canonicalize_nans) 86 .cranelift_opt_level(self.opt_level.to_wasmtime()) 87 .interruptable(self.interruptable) 88 .consume_fuel(self.consume_fuel); 89 return cfg; 90 } 91 } 92 93 include!(concat!(env!("OUT_DIR"), "/spectests.rs")); 94 95 /// A spec test from the upstream wast testsuite, arbitrarily chosen from the 96 /// list of known spec tests. 97 #[derive(Debug)] 98 pub struct SpecTest { 99 /// The filename of the spec test 100 pub file: &'static str, 101 /// The `*.wast` contents of the spec test 102 pub contents: &'static str, 103 } 104 105 impl<'a> Arbitrary<'a> for SpecTest { 106 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { 107 // NB: this does get a uniform value in the provided range. 108 let i = u.int_in_range(0..=FILES.len() - 1)?; 109 let (file, contents) = FILES[i]; 110 Ok(SpecTest { file, contents }) 111 } 112 113 fn size_hint(_depth: usize) -> (usize, Option<usize>) { 114 (1, Some(std::mem::size_of::<usize>())) 115 } 116 } 117