wasmtime_fuzzing/generators/
module.rs1use arbitrary::{Arbitrary, Unstructured};
4use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
5
6#[derive(Debug, Clone)]
11#[expect(missing_docs, reason = "self-describing fields")]
12pub struct ModuleConfig {
13 pub config: wasm_smith::Config,
14
15 pub function_references_enabled: bool,
19 pub component_model_async: bool,
20 pub component_model_async_builtins: bool,
21 pub component_model_async_stackful: bool,
22 pub component_model_error_context: bool,
23 pub component_model_gc: bool,
24 pub legacy_exceptions: bool,
25}
26
27impl<'a> Arbitrary<'a> for ModuleConfig {
28 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<ModuleConfig> {
29 let mut config = wasm_smith::Config::arbitrary(u)?;
30
31 let _ = config.multi_value_enabled;
42 let _ = config.saturating_float_to_int_enabled;
43 let _ = config.sign_extension_ops_enabled;
44 let _ = config.bulk_memory_enabled;
45 let _ = config.reference_types_enabled;
46 let _ = config.simd_enabled;
47 let _ = config.relaxed_simd_enabled;
48 let _ = config.tail_call_enabled;
49 let _ = config.extended_const_enabled;
50 let _ = config.gc_enabled;
51 config.exceptions_enabled = false;
52 config.custom_page_sizes_enabled = u.arbitrary()?;
53 config.wide_arithmetic_enabled = u.arbitrary()?;
54 config.memory64_enabled = u.ratio(1, 20)?;
55 config.threads_enabled = u.ratio(1, 20)?;
56 if u.ratio(1, 20)? {
58 config.max_memories = config.max_memories.max(2);
59 } else {
60 config.max_memories = 1;
61 }
62 config.disallow_traps = u.ratio(9, 10)?;
68
69 Ok(ModuleConfig {
70 component_model_async: false,
71 component_model_async_builtins: false,
72 component_model_async_stackful: false,
73 component_model_error_context: false,
74 component_model_gc: false,
75 legacy_exceptions: false,
76 function_references_enabled: config.gc_enabled,
77 config,
78 })
79 }
80}
81
82impl ModuleConfig {
83 pub fn generate(
91 &self,
92 input: &mut Unstructured<'_>,
93 default_fuel: Option<u32>,
94 ) -> arbitrary::Result<wasm_smith::Module> {
95 crate::init_fuzzing();
96
97 let input_before = if log::log_enabled!(log::Level::Debug) {
100 let len = input.len();
101 Some(input.peek_bytes(len).unwrap().to_vec())
102 } else {
103 None
104 };
105
106 let mut module = wasm_smith::Module::new(self.config.clone(), input)?;
107
108 if let Some(before) = input_before {
109 static GEN_CNT: AtomicUsize = AtomicUsize::new(0);
110 let used = before.len() - input.len();
111 let i = GEN_CNT.fetch_add(1, Relaxed);
112 let dna = format!("testcase{i}.dna");
113 let config = format!("testcase{i}.json");
114 log::debug!("writing `{dna}` and `{config}`");
115 std::fs::write(&dna, &before[..used]).unwrap();
116 std::fs::write(&config, serde_json::to_string_pretty(&self.config).unwrap()).unwrap();
117 }
118
119 if let Some(default_fuel) = default_fuel {
120 module.ensure_termination(default_fuel).unwrap();
121 }
122
123 Ok(module)
124 }
125}