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