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