1 //! Generate a Wasm module and the configuration for generating it. 2 3 use arbitrary::{Arbitrary, Unstructured}; 4 5 /// Default module-level configuration for fuzzing Wasmtime. 6 /// 7 /// Internally this uses `wasm-smith`'s own `Config` but we further refine 8 /// the defaults here as well. 9 #[derive(Debug, Clone)] 10 pub struct ModuleConfig { 11 #[allow(missing_docs)] 12 pub config: wasm_smith::Config, 13 } 14 15 impl<'a> Arbitrary<'a> for ModuleConfig { 16 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<ModuleConfig> { 17 let mut config = wasm_smith::Config::arbitrary(u)?; 18 19 // This list is intended to be the definintive source of truth for 20 // what's at least possible to fuzz within Wasmtime. This is a 21 // combination of features in `wasm-smith` where some proposals are 22 // on-by-default (as determined by fuzz input) and others are 23 // off-by-default (as they aren't stage4+). Wasmtime will default-fuzz 24 // proposals that a pre-stage-4 to test our own implementation. Wasmtime 25 // might also unconditionally disable proposals that it doesn't 26 // implement yet which are stage4+. This is intended to be an exhaustive 27 // list of all the wasm proposals that `wasm-smith` supports and the 28 // fuzzing status within Wasmtime too. 29 let _ = config.multi_value_enabled; 30 let _ = config.saturating_float_to_int_enabled; 31 let _ = config.sign_extension_ops_enabled; 32 let _ = config.bulk_memory_enabled; 33 let _ = config.reference_types_enabled; 34 let _ = config.simd_enabled; 35 let _ = config.relaxed_simd_enabled; 36 let _ = config.tail_call_enabled; 37 config.exceptions_enabled = false; 38 config.gc_enabled = false; 39 config.wide_arithmetic_enabled = u.arbitrary()?; 40 config.memory64_enabled = u.ratio(1, 20)?; 41 // Allow the threads proposal if memory64 is not already enabled. FIXME: 42 // to allow threads and memory64 to coexist, see 43 // https://github.com/bytecodealliance/wasmtime/issues/4267. 44 config.threads_enabled = !config.memory64_enabled && u.ratio(1, 20)?; 45 // FIXME: this may be safe to enable 46 config.custom_page_sizes_enabled = false; 47 // Allow multi-memory but make it unlikely 48 if u.ratio(1, 20)? { 49 config.max_memories = config.max_memories.max(2); 50 } else { 51 config.max_memories = 1; 52 } 53 // ... NB: if you add something above this line please be sure to update 54 // `docs/stability-wasm-proposals.md` 55 56 // We get better differential execution when we disallow traps, so we'll 57 // do that most of the time. 58 config.disallow_traps = u.ratio(9, 10)?; 59 60 Ok(ModuleConfig { config }) 61 } 62 } 63 64 impl ModuleConfig { 65 /// Uses this configuration and the supplied source of data to generate a 66 /// Wasm module. 67 /// 68 /// If a `default_fuel` is provided, the resulting module will be configured 69 /// to ensure termination; as doing so will add an additional global to the 70 /// module, the pooling allocator, if configured, must also have its globals 71 /// limit updated. 72 pub fn generate( 73 &self, 74 input: &mut Unstructured<'_>, 75 default_fuel: Option<u32>, 76 ) -> arbitrary::Result<wasm_smith::Module> { 77 let mut module = wasm_smith::Module::new(self.config.clone(), input)?; 78 79 if let Some(default_fuel) = default_fuel { 80 module.ensure_termination(default_fuel).unwrap(); 81 } 82 83 Ok(module) 84 } 85 } 86