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 guard_before_linear_memory: bool, 76 } 77 78 impl Config { 79 /// Converts this to a `wasmtime::Config` object 80 pub fn to_wasmtime(&self) -> wasmtime::Config { 81 let mut cfg = crate::fuzz_default_config(wasmtime::Strategy::Auto).unwrap(); 82 cfg.debug_info(self.debug_info) 83 .static_memory_maximum_size(self.static_memory_maximum_size.unwrap_or(0).into()) 84 .static_memory_guard_size(self.static_memory_guard_size.unwrap_or(0).into()) 85 .dynamic_memory_guard_size(self.dynamic_memory_guard_size.unwrap_or(0).into()) 86 .guard_before_linear_memory(self.guard_before_linear_memory) 87 .cranelift_nan_canonicalization(self.canonicalize_nans) 88 .cranelift_opt_level(self.opt_level.to_wasmtime()) 89 .interruptable(self.interruptable) 90 .consume_fuel(self.consume_fuel); 91 return cfg; 92 } 93 } 94 95 include!(concat!(env!("OUT_DIR"), "/spectests.rs")); 96 97 /// A spec test from the upstream wast testsuite, arbitrarily chosen from the 98 /// list of known spec tests. 99 #[derive(Debug)] 100 pub struct SpecTest { 101 /// The filename of the spec test 102 pub file: &'static str, 103 /// The `*.wast` contents of the spec test 104 pub contents: &'static str, 105 } 106 107 impl<'a> Arbitrary<'a> for SpecTest { 108 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { 109 // NB: this does get a uniform value in the provided range. 110 let i = u.int_in_range(0..=FILES.len() - 1)?; 111 let (file, contents) = FILES[i]; 112 Ok(SpecTest { file, contents }) 113 } 114 115 fn size_hint(_depth: usize) -> (usize, Option<usize>) { 116 (1, Some(std::mem::size_of::<usize>())) 117 } 118 } 119 120 /// Type alias for wasm-smith generated modules using wasmtime's default 121 /// configuration. 122 pub type GeneratedModule = wasm_smith::ConfiguredModule<WasmtimeDefaultConfig>; 123 124 /// Wasmtime-specific default configuration for wasm-smith-generated modules. 125 #[derive(Arbitrary, Clone, Debug)] 126 pub struct WasmtimeDefaultConfig; 127 128 impl wasm_smith::Config for WasmtimeDefaultConfig { 129 // Allow multi-memory to get exercised 130 fn max_memories(&self) -> usize { 131 2 132 } 133 134 // Allow multi-table (reference types) to get exercised 135 fn max_tables(&self) -> usize { 136 4 137 } 138 139 // Turn some wasm features default-on for those that have a finished 140 // implementation in Wasmtime. 141 fn simd_enabled(&self) -> bool { 142 true 143 } 144 145 fn reference_types_enabled(&self) -> bool { 146 true 147 } 148 149 fn bulk_memory_enabled(&self) -> bool { 150 true 151 } 152 153 fn memory64_enabled(&self) -> bool { 154 true 155 } 156 } 157