1 //! Test case generators.
2 //!
3 //! Test case generators take raw, unstructured input from a fuzzer
4 //! (e.g. libFuzzer) and translate that into a structured test case (e.g. a
5 //! valid Wasm binary).
6 //!
7 //! These are generally implementations of the `Arbitrary` trait, or some
8 //! wrapper over an external tool, such that the wrapper implements the
9 //! `Arbitrary` trait for the wrapped external tool.
10 
11 #[cfg(feature = "binaryen")]
12 pub mod api;
13 
14 use arbitrary::Arbitrary;
15 
16 /// A Wasm test case generator that is powered by Binaryen's `wasm-opt -ttf`.
17 #[derive(Clone)]
18 #[cfg(feature = "binaryen")]
19 pub struct WasmOptTtf {
20     /// The raw, encoded Wasm bytes.
21     pub wasm: Vec<u8>,
22 }
23 
24 #[cfg(feature = "binaryen")]
25 impl std::fmt::Debug for WasmOptTtf {
26     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
27         write!(
28             f,
29             "WasmOptTtf {{ wasm: wat::parse_str(r###\"\n{}\n\"###).unwrap() }}",
30             wasmprinter::print_bytes(&self.wasm).expect("valid wasm should always disassemble")
31         )
32     }
33 }
34 
35 #[cfg(feature = "binaryen")]
36 impl Arbitrary for WasmOptTtf {
37     fn arbitrary(input: &mut arbitrary::Unstructured) -> arbitrary::Result<Self> {
38         crate::init_fuzzing();
39         let seed: Vec<u8> = Arbitrary::arbitrary(input)?;
40         let module = binaryen::tools::translate_to_fuzz_mvp(&seed);
41         let wasm = module.write();
42         Ok(WasmOptTtf { wasm })
43     }
44 
45     fn arbitrary_take_rest(input: arbitrary::Unstructured) -> arbitrary::Result<Self> {
46         crate::init_fuzzing();
47         let seed: Vec<u8> = Arbitrary::arbitrary_take_rest(input)?;
48         let module = binaryen::tools::translate_to_fuzz_mvp(&seed);
49         let wasm = module.write();
50         Ok(WasmOptTtf { wasm })
51     }
52 
53     fn size_hint(depth: usize) -> (usize, Option<usize>) {
54         <Vec<u8> as Arbitrary>::size_hint(depth)
55     }
56 }
57 
58 /// A description of configuration options that we should do differential
59 /// testing between.
60 #[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
61 pub struct DifferentialConfig {
62     strategy: DifferentialStrategy,
63     opt_level: DifferentialOptLevel,
64 }
65 
66 impl DifferentialConfig {
67     /// Convert this differential fuzzing config into a `wasmtime::Config`.
68     pub fn to_wasmtime_config(&self) -> anyhow::Result<wasmtime::Config> {
69         let mut config = crate::fuzz_default_config(match self.strategy {
70             DifferentialStrategy::Cranelift => wasmtime::Strategy::Cranelift,
71             DifferentialStrategy::Lightbeam => wasmtime::Strategy::Lightbeam,
72         })?;
73         config.cranelift_opt_level(match self.opt_level {
74             DifferentialOptLevel::None => wasmtime::OptLevel::None,
75             DifferentialOptLevel::Speed => wasmtime::OptLevel::Speed,
76             DifferentialOptLevel::SpeedAndSize => wasmtime::OptLevel::SpeedAndSize,
77         });
78         Ok(config)
79     }
80 }
81 
82 #[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
83 enum DifferentialStrategy {
84     Cranelift,
85     Lightbeam,
86 }
87 
88 #[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
89 enum DifferentialOptLevel {
90     None,
91     Speed,
92     SpeedAndSize,
93 }
94