1 //! Evaluate an exported Wasm function using the WebAssembly specification 2 //! reference interpreter. 3 4 use crate::generators::{DiffValue, ModuleConfig}; 5 use crate::oracles::engine::{DiffEngine, DiffInstance}; 6 use anyhow::{anyhow, bail, Result}; 7 use wasm_spec_interpreter::Value; 8 9 /// A wrapper for `wasm-spec-interpreter` as a [`DiffEngine`]. 10 pub struct SpecInterpreter; 11 12 impl SpecInterpreter { 13 /// Build a new [`SpecInterpreter`] but only if the configuration does not 14 /// rely on features that the current bindings (i.e., 15 /// `wasm-spec-interpreter`) do not support. 16 pub fn new(config: &ModuleConfig) -> Result<Box<Self>> { 17 if config.config.reference_types_enabled { 18 bail!("the spec interpreter bindings do not support reference types") 19 } 20 if config.config.max_funcs > 1 { 21 // TODO 22 bail!("the spec interpreter bindings can only support one function for now") 23 } 24 if config.config.max_tables > 0 { 25 // TODO 26 bail!("the spec interpreter bindings do not fail as they should with out-of-bounds table accesses") 27 } 28 Ok(Box::new(Self)) 29 } 30 } 31 32 impl DiffEngine for SpecInterpreter { 33 fn name(&self) -> &'static str { 34 "spec" 35 } 36 37 fn instantiate(&self, wasm: &[u8]) -> Result<Box<dyn DiffInstance>> { 38 // TODO: ideally we would avoid copying the module bytes here. 39 Ok(Box::new(SpecInstance { 40 wasm: wasm.to_vec(), 41 })) 42 } 43 } 44 45 struct SpecInstance { 46 wasm: Vec<u8>, 47 } 48 49 impl DiffInstance for SpecInstance { 50 fn name(&self) -> &'static str { 51 "spec" 52 } 53 54 fn evaluate( 55 &mut self, 56 _function_name: &str, 57 arguments: &[DiffValue], 58 ) -> Result<Vec<DiffValue>> { 59 // The spec interpreter needs some work before it can fully support this 60 // interface: 61 // - TODO adapt `wasm-spec-interpreter` to use function name to select 62 // function to run 63 // - TODO adapt `wasm-spec-interpreter` to expose an "instance" with 64 // so we can hash memory, globals, etc. 65 let arguments = arguments.iter().map(Value::from).collect(); 66 match wasm_spec_interpreter::interpret(&self.wasm, Some(arguments)) { 67 Ok(results) => Ok(results.into_iter().map(Value::into).collect()), 68 Err(err) => Err(anyhow!(err)), 69 } 70 } 71 72 fn is_hashable(&self) -> bool { 73 false 74 } 75 76 fn hash(&mut self, _state: &mut std::collections::hash_map::DefaultHasher) -> Result<()> { 77 unimplemented!() 78 } 79 } 80 81 impl From<&DiffValue> for Value { 82 fn from(v: &DiffValue) -> Self { 83 match *v { 84 DiffValue::I32(n) => Value::I32(n), 85 DiffValue::I64(n) => Value::I64(n), 86 DiffValue::F32(n) => Value::F32(n as i32), 87 DiffValue::F64(n) => Value::F64(n as i64), 88 DiffValue::V128(n) => Value::V128(n.to_le_bytes().to_vec()), 89 } 90 } 91 } 92 93 impl Into<DiffValue> for Value { 94 fn into(self) -> DiffValue { 95 match self { 96 Value::I32(n) => DiffValue::I32(n), 97 Value::I64(n) => DiffValue::I64(n), 98 Value::F32(n) => DiffValue::F32(n as u32), 99 Value::F64(n) => DiffValue::F64(n as u64), 100 Value::V128(n) => { 101 assert_eq!(n.len(), 16); 102 DiffValue::V128(u128::from_le_bytes(n.as_slice().try_into().unwrap())) 103 } 104 } 105 } 106 } 107 108 /// Set up the OCaml runtime for triggering its signal handler configuration. 109 /// 110 /// Because both the OCaml runtime and Wasmtime set up signal handlers, we must 111 /// carefully decide when to instantiate them; this function allows us to 112 /// control when. Wasmtime uses these signal handlers for catching various 113 /// WebAssembly failures. On certain OSes (e.g. Linux `x86_64`), the signal 114 /// handlers interfere, observable as an uncaught `SIGSEGV`--not even caught by 115 /// libFuzzer. 116 /// 117 /// This failure can be mitigated by always running Wasmtime second in 118 /// differential fuzzing. In some cases, however, this is not possible because 119 /// which engine will execute first is unknown. This function can be explicitly 120 /// executed first, e.g., during global initialization, to avoid this issue. 121 pub fn setup_ocaml_runtime() { 122 wasm_spec_interpreter::setup_ocaml_runtime(); 123 } 124