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