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 // We get better differential execution when we disallow traps, so we'll 43 // do that most of the time. 44 config.disallow_traps = u.ratio(9, 10)?; 45 46 Ok(ModuleConfig { config }) 47 } 48 } 49 50 impl ModuleConfig { 51 /// Uses this configuration and the supplied source of data to generate a 52 /// Wasm module. 53 /// 54 /// If a `default_fuel` is provided, the resulting module will be configured 55 /// to ensure termination; as doing so will add an additional global to the 56 /// module, the pooling allocator, if configured, must also have its globals 57 /// limit updated. 58 pub fn generate( 59 &self, 60 input: &mut Unstructured<'_>, 61 default_fuel: Option<u32>, 62 ) -> arbitrary::Result<wasm_smith::Module> { 63 let mut module = wasm_smith::Module::new(self.config.clone(), input)?; 64 65 if let Some(default_fuel) = default_fuel { 66 module.ensure_termination(default_fuel); 67 } 68 69 Ok(module) 70 } 71 } 72