1 use crate::config::Config;
2 use crate::function_generator::FunctionGenerator;
3 use crate::settings::{Flags, OptLevel};
4 use anyhow::Result;
5 use arbitrary::{Arbitrary, Unstructured};
6 use cranelift::codegen::data_value::DataValue;
7 use cranelift::codegen::ir::types::*;
8 use cranelift::codegen::ir::Function;
9 use cranelift::codegen::Context;
10 use cranelift::prelude::isa;
11 use cranelift::prelude::*;
12 use cranelift_native::builder_with_options;
13 use std::fmt;
14 use target_lexicon::{Architecture, Triple};
15 
16 mod config;
17 mod function_generator;
18 mod passes;
19 
20 pub type TestCaseInput = Vec<DataValue>;
21 
22 /// Simple wrapper to generate a single Cranelift `Function`.
23 #[derive(Debug)]
24 pub struct SingleFunction(pub Function);
25 
26 impl<'a> Arbitrary<'a> for SingleFunction {
27     fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
28         FuzzGen::new(u)
29             .generate_func(Triple::host())
30             .map_err(|_| arbitrary::Error::IncorrectFormat)
31             .map(Self)
32     }
33 }
34 
35 /// Print only non default flags.
36 fn write_non_default_flags(f: &mut fmt::Formatter<'_>, flags: &settings::Flags) -> fmt::Result {
37     let default_flags = settings::Flags::new(settings::builder());
38     for (default, flag) in default_flags.iter().zip(flags.iter()) {
39         assert_eq!(default.name, flag.name);
40 
41         if default.value_string() != flag.value_string() {
42             writeln!(f, "set {}={}", flag.name, flag.value_string())?;
43         }
44     }
45 
46     Ok(())
47 }
48 
49 /// A generated function with an ISA that targets one of cranelift's backends.
50 pub struct FunctionWithIsa {
51     /// TargetIsa to use when compiling this test case
52     pub isa: Box<dyn isa::TargetIsa>,
53 
54     /// Function under test
55     pub func: Function,
56 }
57 
58 impl fmt::Debug for FunctionWithIsa {
59     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60         writeln!(f, ";; Compile test case\n")?;
61 
62         write_non_default_flags(f, self.isa.flags())?;
63 
64         writeln!(f, "test compile")?;
65         writeln!(f, "target {}", self.isa.triple().architecture)?;
66         writeln!(f, "{}", self.func)?;
67 
68         Ok(())
69     }
70 }
71 
72 impl<'a> Arbitrary<'a> for FunctionWithIsa {
73     fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
74         // We filter out targets that aren't supported in the current build
75         // configuration after randomly choosing one, instead of randomly choosing
76         // a supported one, so that the same fuzz input works across different build
77         // configurations.
78         let target = u.choose(isa::ALL_ARCHITECTURES)?;
79         let builder = isa::lookup_by_name(target).map_err(|_| arbitrary::Error::IncorrectFormat)?;
80 
81         let mut gen = FuzzGen::new(u);
82         let flags = gen
83             .generate_flags(builder.triple().architecture)
84             .map_err(|_| arbitrary::Error::IncorrectFormat)?;
85         let isa = builder
86             .finish(flags)
87             .map_err(|_| arbitrary::Error::IncorrectFormat)?;
88 
89         let func = gen
90             .generate_func(isa.triple().clone())
91             .map_err(|_| arbitrary::Error::IncorrectFormat)?;
92 
93         Ok(FunctionWithIsa { isa, func })
94     }
95 }
96 
97 pub struct TestCase {
98     /// TargetIsa to use when compiling this test case
99     pub isa: Box<dyn isa::TargetIsa>,
100     /// Function under test
101     pub func: Function,
102     /// Generate multiple test inputs for each test case.
103     /// This allows us to get more coverage per compilation, which may be somewhat expensive.
104     pub inputs: Vec<TestCaseInput>,
105 }
106 
107 impl fmt::Debug for TestCase {
108     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109         writeln!(f, ";; Fuzzgen test case\n")?;
110         writeln!(f, "test interpret")?;
111         writeln!(f, "test run")?;
112 
113         write_non_default_flags(f, self.isa.flags())?;
114 
115         writeln!(f, "target {}", self.isa.triple().architecture)?;
116         writeln!(f, "{}", self.func)?;
117         writeln!(f, "; Note: the results in the below test cases are simply a placeholder and probably will be wrong\n")?;
118 
119         for input in self.inputs.iter() {
120             // TODO: We don't know the expected outputs, maybe we can run the interpreter
121             // here to figure them out? Should work, however we need to be careful to catch
122             // panics in case its the interpreter that is failing.
123             // For now create a placeholder output consisting of the zero value for the type
124             let returns = &self.func.signature.returns;
125             let placeholder_output = returns
126                 .iter()
127                 .map(|param| DataValue::read_from_slice(&[0; 16][..], param.value_type))
128                 .map(|val| format!("{}", val))
129                 .collect::<Vec<_>>()
130                 .join(", ");
131 
132             // If we have no output, we don't need the == condition
133             let test_condition = match returns.len() {
134                 0 => String::new(),
135                 1 => format!(" == {}", placeholder_output),
136                 _ => format!(" == [{}]", placeholder_output),
137             };
138 
139             let args = input
140                 .iter()
141                 .map(|val| format!("{}", val))
142                 .collect::<Vec<_>>()
143                 .join(", ");
144 
145             writeln!(f, "; run: {}({}){}", self.func.name, args, test_condition)?;
146         }
147 
148         Ok(())
149     }
150 }
151 
152 impl<'a> Arbitrary<'a> for TestCase {
153     fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
154         FuzzGen::new(u)
155             .generate_host_test()
156             .map_err(|_| arbitrary::Error::IncorrectFormat)
157     }
158 }
159 
160 pub struct FuzzGen<'r, 'data>
161 where
162     'data: 'r,
163 {
164     u: &'r mut Unstructured<'data>,
165     config: Config,
166 }
167 
168 impl<'r, 'data> FuzzGen<'r, 'data>
169 where
170     'data: 'r,
171 {
172     pub fn new(u: &'r mut Unstructured<'data>) -> Self {
173         Self {
174             u,
175             config: Config::default(),
176         }
177     }
178 
179     fn generate_datavalue(&mut self, ty: Type) -> Result<DataValue> {
180         Ok(match ty {
181             ty if ty.is_int() => {
182                 let imm = match ty {
183                     I8 => self.u.arbitrary::<i8>()? as i128,
184                     I16 => self.u.arbitrary::<i16>()? as i128,
185                     I32 => self.u.arbitrary::<i32>()? as i128,
186                     I64 => self.u.arbitrary::<i64>()? as i128,
187                     I128 => self.u.arbitrary::<i128>()?,
188                     _ => unreachable!(),
189                 };
190                 DataValue::from_integer(imm, ty)?
191             }
192             // f{32,64}::arbitrary does not generate a bunch of important values
193             // such as Signaling NaN's / NaN's with payload, so generate floats from integers.
194             F32 => DataValue::F32(Ieee32::with_bits(u32::arbitrary(self.u)?)),
195             F64 => DataValue::F64(Ieee64::with_bits(u64::arbitrary(self.u)?)),
196             _ => unimplemented!(),
197         })
198     }
199 
200     fn generate_test_inputs(mut self, signature: &Signature) -> Result<Vec<TestCaseInput>> {
201         let mut inputs = Vec::new();
202 
203         // Generate up to "max_test_case_inputs" inputs, we need an upper bound here since
204         // the fuzzer at some point starts trying to feed us way too many inputs. (I found one
205         // test case with 130k inputs!)
206         for _ in 0..self.config.max_test_case_inputs {
207             let last_len = self.u.len();
208 
209             let test_args = signature
210                 .params
211                 .iter()
212                 .map(|p| self.generate_datavalue(p.value_type))
213                 .collect::<Result<TestCaseInput>>()?;
214 
215             inputs.push(test_args);
216 
217             // Continue generating input as long as we just consumed some of self.u. Otherwise
218             // we'll generate the same test input again and again, forever. Note that once self.u
219             // becomes empty we obviously can't consume any more of it, so this check is more
220             // general. Also note that we need to generate at least one input or the fuzz target
221             // won't actually test anything, so checking at the end of the loop is good, even if
222             // self.u is empty from the start and we end up with all zeros in test_args.
223             assert!(self.u.len() <= last_len);
224             if self.u.len() == last_len {
225                 break;
226             }
227         }
228 
229         Ok(inputs)
230     }
231 
232     fn run_func_passes(&mut self, func: Function) -> Result<Function> {
233         // Do a NaN Canonicalization pass on the generated function.
234         //
235         // Both IEEE754 and the Wasm spec are somewhat loose about what is allowed
236         // to be returned from NaN producing operations. And in practice this changes
237         // from X86 to Aarch64 and others. Even in the same host machine, the
238         // interpreter may produce a code sequence different from cranelift that
239         // generates different NaN's but produces legal results according to the spec.
240         //
241         // These differences cause spurious failures in the fuzzer. To fix this
242         // we enable the NaN Canonicalization pass that replaces any NaN's produced
243         // with a single fixed canonical NaN value.
244         //
245         // This is something that we can enable via flags for the compiled version, however
246         // the interpreter won't get that version, so call that pass manually here.
247 
248         let mut ctx = Context::for_function(func);
249         // Assume that we are generating this function for the current ISA.
250         // We disable the verifier here, since if it fails it prevents a test case from
251         // being generated and formatted by `cargo fuzz fmt`.
252         // We run the verifier before compiling the code, so it always gets verified.
253         let flags = settings::Flags::new({
254             let mut builder = settings::builder();
255             builder.set("enable_verifier", "false").unwrap();
256             builder
257         });
258 
259         let isa = builder_with_options(false)
260             .expect("Unable to build a TargetIsa for the current host")
261             .finish(flags)
262             .expect("Failed to build TargetISA");
263 
264         ctx.canonicalize_nans(isa.as_ref())
265             .expect("Failed NaN canonicalization pass");
266 
267         // Run the int_divz pass
268         //
269         // This pass replaces divs and rems with sequences that do not trap
270         passes::do_int_divz_pass(self, &mut ctx.func)?;
271 
272         // This pass replaces fcvt* instructions with sequences that do not trap
273         passes::do_fcvt_trap_pass(self, &mut ctx.func)?;
274 
275         Ok(ctx.func)
276     }
277 
278     fn generate_func(&mut self, target_triple: Triple) -> Result<Function> {
279         let func = FunctionGenerator::new(&mut self.u, &self.config, target_triple).generate()?;
280         self.run_func_passes(func)
281     }
282 
283     /// Generate a random set of cranelift flags.
284     /// Only semantics preserving flags are considered
285     fn generate_flags(&mut self, target_arch: Architecture) -> Result<Flags> {
286         let mut builder = settings::builder();
287 
288         let opt = self.u.choose(OptLevel::all())?;
289         builder.set("opt_level", &format!("{}", opt)[..])?;
290 
291         // Boolean flags
292         // TODO: enable_pinned_reg does not work with our current trampolines. See: #4376
293         // TODO: is_pic has issues:
294         //   x86: https://github.com/bytecodealliance/wasmtime/issues/5005
295         //   aarch64: https://github.com/bytecodealliance/wasmtime/issues/2735
296         let bool_settings = [
297             "enable_alias_analysis",
298             "enable_safepoints",
299             "unwind_info",
300             "preserve_frame_pointers",
301             "enable_jump_tables",
302             "enable_heap_access_spectre_mitigation",
303             "enable_table_access_spectre_mitigation",
304             "enable_incremental_compilation_cache_checks",
305             "regalloc_checker",
306             "enable_llvm_abi_extensions",
307             "use_egraphs",
308         ];
309         for flag_name in bool_settings {
310             let enabled = self
311                 .config
312                 .compile_flag_ratio
313                 .get(&flag_name)
314                 .map(|&(num, denum)| self.u.ratio(num, denum))
315                 .unwrap_or_else(|| bool::arbitrary(self.u))?;
316 
317             let value = format!("{}", enabled);
318             builder.set(flag_name, value.as_str())?;
319         }
320 
321         let supports_inline_probestack = match target_arch {
322             Architecture::X86_64 => true,
323             Architecture::Aarch64(_) => true,
324             _ => false,
325         };
326 
327         // Optionally test inline stackprobes on supported platforms
328         // TODO: Test outlined stack probes.
329         if supports_inline_probestack && bool::arbitrary(self.u)? {
330             builder.enable("enable_probestack")?;
331             builder.set("probestack_strategy", "inline")?;
332 
333             let size = self
334                 .u
335                 .int_in_range(self.config.stack_probe_size_log2.clone())?;
336             builder.set("probestack_size_log2", &format!("{}", size))?;
337         }
338 
339         // Fixed settings
340 
341         // We need llvm ABI extensions for i128 values on x86, so enable it regardless of
342         // what we picked above.
343         if target_arch == Architecture::X86_64 {
344             builder.enable("enable_llvm_abi_extensions")?;
345         }
346 
347         // This is the default, but we should ensure that it wasn't accidentally turned off anywhere.
348         builder.enable("enable_verifier")?;
349 
350         // These settings just panic when they're not enabled and we try to use their respective functionality
351         // so they aren't very interesting to be automatically generated.
352         builder.enable("enable_atomics")?;
353         builder.enable("enable_float")?;
354         builder.enable("enable_simd")?;
355 
356         // `machine_code_cfg_info` generates additional metadata for the embedder but this doesn't feed back
357         // into compilation anywhere, we leave it on unconditionally to make sure the generation doesn't panic.
358         builder.enable("machine_code_cfg_info")?;
359 
360         Ok(Flags::new(builder))
361     }
362 
363     pub fn generate_host_test(mut self) -> Result<TestCase> {
364         // If we're generating test inputs as well as a function, then we're planning to execute
365         // this function. That means that any function references in it need to exist. We don't yet
366         // have infrastructure for generating multiple functions, so just don't generate funcrefs.
367         self.config.funcrefs_per_function = 0..=0;
368 
369         // TestCase is meant to be consumed by a runner, so we make the assumption here that we're
370         // generating a TargetIsa for the host.
371         let builder =
372             builder_with_options(true).expect("Unable to build a TargetIsa for the current host");
373         let flags = self.generate_flags(builder.triple().architecture)?;
374         let isa = builder.finish(flags)?;
375         let func = self.generate_func(isa.triple().clone())?;
376         let inputs = self.generate_test_inputs(&func.signature)?;
377         Ok(TestCase { isa, func, inputs })
378     }
379 }
380