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 // Allow multi-memory but make it unlikely 20 if u.ratio(1, 20)? { 21 config.max_memories = config.max_memories.max(2); 22 } else { 23 config.max_memories = 1; 24 } 25 26 // Allow multi-table by default. 27 if config.reference_types_enabled { 28 config.max_tables = config.max_tables.max(4); 29 } 30 31 // Allow enabling some various wasm proposals by default. Note that 32 // these are all unconditionally turned off even with 33 // `SwarmConfig::arbitrary`. 34 config.memory64_enabled = u.ratio(1, 20)?; 35 36 // Allow the threads proposal if memory64 is not already enabled. FIXME: 37 // to allow threads and memory64 to coexist, see 38 // https://github.com/bytecodealliance/wasmtime/issues/4267. 39 config.threads_enabled = !config.memory64_enabled && u.ratio(1, 20)?; 40 41 // We get better differential execution when we disallow traps, so we'll 42 // do that most of the time. 43 config.disallow_traps = u.ratio(9, 10)?; 44 45 Ok(ModuleConfig { config }) 46 } 47 } 48 49 impl ModuleConfig { 50 /// Uses this configuration and the supplied source of data to generate a 51 /// Wasm module. 52 /// 53 /// If a `default_fuel` is provided, the resulting module will be configured 54 /// to ensure termination; as doing so will add an additional global to the 55 /// module, the pooling allocator, if configured, must also have its globals 56 /// limit updated. 57 pub fn generate( 58 &self, 59 input: &mut Unstructured<'_>, 60 default_fuel: Option<u32>, 61 ) -> arbitrary::Result<wasm_smith::Module> { 62 let mut module = wasm_smith::Module::new(self.config.clone(), input)?; 63 64 if let Some(default_fuel) = default_fuel { 65 module.ensure_termination(default_fuel).unwrap(); 66 } 67 68 Ok(module) 69 } 70 } 71