1 //! Compile arbitrary bytes from the fuzzer as if they were Wasm, checking that 2 //! compilation is deterministic. 3 //! 4 //! Also use `wasm-mutate` to mutate the fuzz inputs. 5 6 #![no_main] 7 8 use libfuzzer_sys::{fuzz_mutator, fuzz_target}; 9 use wasmtime::{Config, Engine, Module, Result}; 10 11 fn create_engine() -> Engine { 12 let mut config = Config::default(); 13 // Safety: the Cranelift option `regalloc_checker` does not alter 14 // the generated code at all; it only does extra checking after 15 // compilation. 16 unsafe { 17 config.cranelift_flag_enable("regalloc_checker"); 18 } 19 Engine::new(&config).expect("Could not construct Engine") 20 } 21 22 fn compile_and_serialize(engine: &Engine, wasm: &[u8]) -> Result<Vec<u8>> { 23 let module = Module::new(&engine, wasm)?; 24 module.serialize() 25 } 26 27 fuzz_target!(|data: &[u8]| { 28 let engine = create_engine(); 29 wasmtime_fuzzing::oracles::log_wasm(data); 30 31 if let Ok(bytes1) = compile_and_serialize(&engine, data) { 32 let bytes2 = compile_and_serialize(&engine, data) 33 .expect("successfully compiled once, should successfully compile again"); 34 35 // NB: Don't use `assert_eq!` here because it prints out the LHS and RHS 36 // to stderr on failure, which isn't helpful here since it is just a 37 // huge serialized binary. 38 assert!(bytes1 == bytes2, "Wasm compilation should be deterministic"); 39 } 40 }); 41 42 fuzz_mutator!(|data: &mut [u8], size: usize, max_size: usize, seed: u32| { 43 // Half of the time use libfuzzer's built in mutators, and the other half of 44 // the time use `wasm-mutate`. 45 if seed.count_ones() % 2 == 0 { 46 libfuzzer_sys::fuzzer_mutate(data, size, max_size) 47 } else { 48 wasmtime_fuzzing::mutators::wasm_mutate( 49 data, 50 size, 51 max_size, 52 seed, 53 libfuzzer_sys::fuzzer_mutate, 54 ) 55 } 56 }); 57