/src/wasm-tools/fuzz/fuzz_targets/run.rs
Line | Count | Source |
1 | | #![cfg_attr(fuzzing, no_main)] |
2 | | |
3 | | use arbitrary::Unstructured; |
4 | | use std::sync::OnceLock; |
5 | | |
6 | | #[cfg(fuzzing)] |
7 | | use libfuzzer_sys::fuzz_target; |
8 | | #[cfg(not(fuzzing))] |
9 | | macro_rules! fuzz_target { |
10 | | ($e:expr) => { |
11 | | fn main() { |
12 | | let _ = $e(&[]); |
13 | | } |
14 | | }; |
15 | | } |
16 | | |
17 | | // Helper macro which takes a static list of fuzzers as input which are then |
18 | | // delegated to internally based on the fuzz target selected. |
19 | | // |
20 | | // In general this fuzz target will execute a number of fuzzers all with the |
21 | | // same input. The `FUZZER` environment variable can be used to forcibly disable |
22 | | // all but one. |
23 | | macro_rules! run_fuzzers { |
24 | | ($($fuzzer:ident: $kind:ident,)*) => { |
25 | | static ENABLED: OnceLock<u32> = OnceLock::new(); |
26 | | |
27 | | fuzz_target!(|bytes: &[u8]| { |
28 | | // Lazily initialize this fuzzer in terms of logging as well as |
29 | | // enabled fuzzers via the `FUZZER` env var. |
30 | 1 | let enabled = *ENABLED.get_or_init(|| { |
31 | 1 | env_logger::init(); |
32 | 1 | let configured = std::env::var("FUZZER").ok(); |
33 | 1 | let configured = configured.as_deref(); |
34 | 1 | let mut enabled = 0; |
35 | 1 | let mut index = 0; |
36 | | |
37 | | $( |
38 | 1 | if configured.is_none() || configured == Some(stringify!($fuzzer)) { |
39 | 1 | enabled |= 1 << index; |
40 | 1 | } |
41 | 1 | index += 1; |
42 | | )* |
43 | 1 | let _ = index; |
44 | | |
45 | 1 | enabled |
46 | 1 | }); |
47 | | |
48 | | let mut index = 0; |
49 | | $( |
50 | | if enabled & (1 << index) != 0 { |
51 | | run_fuzzers!(@run $fuzzer $kind bytes index); |
52 | | } |
53 | | index += 1; |
54 | | )* |
55 | | let _ = index; |
56 | | }); |
57 | | }; |
58 | | |
59 | | (@run $fuzzer:ident unstructured $bytes:ident $index:ident) => { |
60 | | // Use the first byte of input as a discriminant of which fuzzer to |
61 | | // select. |
62 | | // |
63 | | // Afterwards run the specific fuzzer that the fuzz input is |
64 | | // targeted for so long as it's enabled. |
65 | | if let Some((which_fuzzer, bytes)) = $bytes.split_first() { |
66 | | if *which_fuzzer == $index { |
67 | | let mut u = Unstructured::new(bytes); |
68 | | let _ = wasm_tools_fuzz::$fuzzer::run(&mut u); |
69 | | } |
70 | | } |
71 | | }; |
72 | | |
73 | | (@run $fuzzer:ident string $bytes:ident $index:ident) => { |
74 | | // For string-based fuzzers run all fuzzers enabled for all |
75 | | // string-looking inputs. |
76 | | if let Ok(s) = std::str::from_utf8($bytes) { |
77 | | wasm_tools_fuzz::$fuzzer::run(s); |
78 | | } |
79 | | }; |
80 | | } |
81 | | |
82 | | run_fuzzers! { |
83 | | mutate: unstructured, |
84 | | validate_valid_module: unstructured, |
85 | | roundtrip_wit: unstructured, |
86 | | no_traps: unstructured, |
87 | | validate: unstructured, |
88 | | incremental_parse: unstructured, |
89 | | print: unstructured, |
90 | | roundtrip: string, |
91 | | text_parser: string, |
92 | | reencode: unstructured, |
93 | | wit64: unstructured, |
94 | | } |