Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/fuzzing/src/generators/module.rs
3063 views
1
//! Generate a Wasm module and the configuration for generating it.
2
3
use arbitrary::{Arbitrary, Unstructured};
4
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
5
6
/// Default module-level configuration for fuzzing Wasmtime.
7
///
8
/// Internally this uses `wasm-smith`'s own `Config` but we further refine
9
/// the defaults here as well.
10
#[derive(Debug, Clone)]
11
#[expect(missing_docs, reason = "self-describing fields")]
12
pub struct ModuleConfig {
13
pub config: wasm_smith::Config,
14
15
// These knobs aren't exposed in `wasm-smith` at this time but are exposed
16
// in our `*.wast` testing so keep knobs here so they can be read during
17
// config-to-`wasmtime::Config` translation.
18
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_threading: bool,
23
pub component_model_error_context: bool,
24
pub component_model_gc: bool,
25
pub component_model_fixed_length_lists: bool,
26
pub legacy_exceptions: bool,
27
pub shared_memory: bool,
28
}
29
30
impl<'a> Arbitrary<'a> for ModuleConfig {
31
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<ModuleConfig> {
32
let mut config = wasm_smith::Config::arbitrary(u)?;
33
34
// This list is intended to be the definitive source of truth for
35
// what's at least possible to fuzz within Wasmtime. This is a
36
// combination of features in `wasm-smith` where some proposals are
37
// on-by-default (as determined by fuzz input) and others are
38
// off-by-default (as they aren't stage4+). Wasmtime will default-fuzz
39
// proposals that a pre-stage-4 to test our own implementation. Wasmtime
40
// might also unconditionally disable proposals that it doesn't
41
// implement yet which are stage4+. This is intended to be an exhaustive
42
// list of all the wasm proposals that `wasm-smith` supports and the
43
// fuzzing status within Wasmtime too.
44
let _ = config.multi_value_enabled;
45
let _ = config.saturating_float_to_int_enabled;
46
let _ = config.sign_extension_ops_enabled;
47
let _ = config.bulk_memory_enabled;
48
let _ = config.reference_types_enabled;
49
let _ = config.simd_enabled;
50
let _ = config.relaxed_simd_enabled;
51
let _ = config.tail_call_enabled;
52
let _ = config.extended_const_enabled;
53
let _ = config.gc_enabled;
54
let _ = config.exceptions_enabled;
55
config.custom_page_sizes_enabled = u.arbitrary()?;
56
config.wide_arithmetic_enabled = u.arbitrary()?;
57
config.memory64_enabled = u.ratio(1, 20)?;
58
// Fuzzing threads is an open question. Even without actual parallel
59
// threads `SharedMemory` still poses a problem where it isn't hooked
60
// into resource limits the same way `Memory` is. Overall not clear what
61
// to do so it's disabled for now.
62
config.threads_enabled = false;
63
// Allow multi-memory but make it unlikely
64
if u.ratio(1, 20)? {
65
config.max_memories = config.max_memories.max(2);
66
} else {
67
config.max_memories = 1;
68
}
69
// ... NB: if you add something above this line please be sure to update
70
// `docs/stability-wasm-proposals.md`
71
72
// We get better differential execution when we disallow traps, so we'll
73
// do that most of the time.
74
config.disallow_traps = u.ratio(9, 10)?;
75
76
Ok(ModuleConfig {
77
component_model_async: false,
78
component_model_async_builtins: false,
79
component_model_async_stackful: false,
80
component_model_threading: false,
81
component_model_error_context: false,
82
component_model_gc: false,
83
component_model_fixed_length_lists: false,
84
legacy_exceptions: false,
85
shared_memory: false,
86
function_references_enabled: config.gc_enabled,
87
config,
88
})
89
}
90
}
91
92
impl ModuleConfig {
93
/// Uses this configuration and the supplied source of data to generate a
94
/// Wasm module.
95
///
96
/// If a `default_fuel` is provided, the resulting module will be configured
97
/// to ensure termination; as doing so will add an additional global to the
98
/// module, the pooling allocator, if configured, must also have its globals
99
/// limit updated.
100
pub fn generate(
101
&self,
102
input: &mut Unstructured<'_>,
103
default_fuel: Option<u32>,
104
) -> arbitrary::Result<wasm_smith::Module> {
105
crate::init_fuzzing();
106
107
// If requested, save `*.{dna,json}` files for recreating this module
108
// in wasm-tools alone.
109
let input_before = if log::log_enabled!(log::Level::Debug) {
110
let len = input.len();
111
Some(input.peek_bytes(len).unwrap().to_vec())
112
} else {
113
None
114
};
115
116
let mut module = wasm_smith::Module::new(self.config.clone(), input)?;
117
118
if let Some(before) = input_before {
119
static GEN_CNT: AtomicUsize = AtomicUsize::new(0);
120
let used = before.len() - input.len();
121
let i = GEN_CNT.fetch_add(1, Relaxed);
122
let dna = format!("testcase{i}.dna");
123
let config = format!("testcase{i}.json");
124
log::debug!("writing `{dna}` and `{config}`");
125
std::fs::write(&dna, &before[..used]).unwrap();
126
std::fs::write(&config, serde_json::to_string_pretty(&self.config).unwrap()).unwrap();
127
}
128
129
if let Some(default_fuel) = default_fuel {
130
module.ensure_termination(default_fuel).unwrap();
131
}
132
133
Ok(module)
134
}
135
}
136
137