1 #![no_main]
2
3 use libfuzzer_sys::arbitrary::{Arbitrary, Result, Unstructured};
4 use wasmtime_fuzzing::generators::Config;
5 use wasmtime_fuzzing::oracles::{Timeout, instantiate};
6 use wasmtime_fuzzing::single_module_fuzzer::KnownValid;
7
8 wasmtime_fuzzing::single_module_fuzzer!(execute gen_module);
9
10 #[derive(Debug)]
11 struct InstantiateInput {
12 config: Config,
13 timeout: Timeout,
14 }
15
16 impl<'a> Arbitrary<'a> for InstantiateInput {
arbitrary(u: &mut Unstructured<'a>) -> Result<Self>17 fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
18 let mut config: Config = u.arbitrary()?;
19
20 // Pick either fuel, duration-based, or module-based timeout. Note that
21 // the module-based timeout is implemented with wasm-smith's
22 // `ensure_termination` option.
23 let timeout = if u.arbitrary()? {
24 config.generate_timeout(u)?
25 } else {
26 Timeout::None
27 };
28
29 Ok(InstantiateInput { config, timeout })
30 }
31 }
32
execute( module: &[u8], known_valid: KnownValid, mut input: InstantiateInput, u: &mut Unstructured<'_>, ) -> Result<()>33 fn execute(
34 module: &[u8],
35 known_valid: KnownValid,
36 mut input: InstantiateInput,
37 u: &mut Unstructured<'_>,
38 ) -> Result<()> {
39 let timeout = match input.timeout {
40 // If the input module isn't a "known valid" module then it can't be
41 // relied on self-regulating itself, so force a timeout via epochs/fuel
42 // in the configuration.
43 Timeout::None if known_valid == KnownValid::No => input.config.generate_timeout(u)?,
44 other => other,
45 };
46 instantiate(module, known_valid, &input.config, timeout);
47 Ok(())
48 }
49
gen_module( input: &mut InstantiateInput, u: &mut Unstructured<'_>, ) -> Result<(Vec<u8>, KnownValid)>50 fn gen_module(
51 input: &mut InstantiateInput,
52 u: &mut Unstructured<'_>,
53 ) -> Result<(Vec<u8>, KnownValid)> {
54 // With a small-ish chance take raw fuzz input and put it in the module to
55 // stress module compilation/validation. In such a situation we can't use
56 // `ensure_termination` in wasm-smith so list the timeout as `None` to time
57 // out via epochs or Wasmtime-level fuel.
58 //
59 // Otherwise though if no timeout is configured use wasm-smith fuel to
60 // ensure termination.
61 let allow_invalid_funcs = u.ratio(1, 10)?;
62
63 let default_fuel = if allow_invalid_funcs {
64 input.config.module_config.config.allow_invalid_funcs = true;
65 input.timeout = Timeout::None;
66 None
67 } else if let Timeout::None = input.timeout {
68 Some(1000)
69 } else {
70 None
71 };
72 let module = input.config.generate(u, default_fuel)?;
73 let known_valid = if allow_invalid_funcs {
74 KnownValid::No
75 } else {
76 KnownValid::Yes
77 };
78 Ok((module.to_bytes(), known_valid))
79 }
80