1 //! Generate a Wasm module and the configuration for generating it. 2 3 use arbitrary::{Arbitrary, Unstructured}; 4 use wasm_smith::SwarmConfig; 5 6 /// Default module-level configuration for fuzzing Wasmtime. 7 /// 8 /// Internally this uses `wasm-smith`'s own `SwarmConfig` but we further refine 9 /// the defaults here as well. 10 #[derive(Debug, Clone)] 11 pub struct ModuleConfig { 12 #[allow(missing_docs)] 13 pub config: SwarmConfig, 14 } 15 16 impl<'a> Arbitrary<'a> for ModuleConfig { 17 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<ModuleConfig> { 18 let mut config = SwarmConfig::arbitrary(u)?; 19 20 // Allow multi-memory but make it unlikely 21 if u.ratio(1, 20)? { 22 config.max_memories = config.max_memories.max(2); 23 } else { 24 config.max_memories = 1; 25 } 26 27 // Allow multi-table by default. 28 if config.reference_types_enabled { 29 config.max_tables = config.max_tables.max(4); 30 } 31 32 // Allow enabling some various wasm proposals by default. Note that 33 // these are all unconditionally turned off even with 34 // `SwarmConfig::arbitrary`. 35 config.memory64_enabled = u.ratio(1, 20)?; 36 37 // Allow the threads proposal if memory64 is not already enabled. FIXME: 38 // to allow threads and memory64 to coexist, see 39 // https://github.com/bytecodealliance/wasmtime/issues/4267. 40 config.threads_enabled = !config.memory64_enabled && u.ratio(1, 20)?; 41 42 Ok(ModuleConfig { config }) 43 } 44 } 45 46 impl ModuleConfig { 47 /// Uses this configuration and the supplied source of data to generate a 48 /// Wasm module. 49 /// 50 /// If a `default_fuel` is provided, the resulting module will be configured 51 /// to ensure termination; as doing so will add an additional global to the 52 /// module, the pooling allocator, if configured, must also have its globals 53 /// limit updated. 54 pub fn generate( 55 &self, 56 input: &mut Unstructured<'_>, 57 default_fuel: Option<u32>, 58 ) -> arbitrary::Result<wasm_smith::Module> { 59 let mut module = wasm_smith::Module::new(self.config.clone(), input)?; 60 61 if let Some(default_fuel) = default_fuel { 62 module.ensure_termination(default_fuel); 63 } 64 65 Ok(module) 66 } 67 } 68