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