15ec92d59SAndrew Brown //! Evaluate an exported Wasm function using the WebAssembly specification
25ec92d59SAndrew Brown //! reference interpreter.
35ec92d59SAndrew Brown 
4543a4879SAlex Crichton use crate::generators::{Config, DiffValue, DiffValueType};
55ec92d59SAndrew Brown use crate::oracles::engine::{DiffEngine, DiffInstance};
6c3f8415aSAndrew Brown use wasm_spec_interpreter::SpecValue;
7*93d22fcdSNick Fitzgerald use wasmtime::{Error, Result, Trap, format_err};
85ec92d59SAndrew Brown 
95ec92d59SAndrew Brown /// A wrapper for `wasm-spec-interpreter` as a [`DiffEngine`].
105ec92d59SAndrew Brown pub struct SpecInterpreter;
115ec92d59SAndrew Brown 
125ec92d59SAndrew Brown impl SpecInterpreter {
new(config: &mut Config) -> Self13543a4879SAlex Crichton     pub(crate) fn new(config: &mut Config) -> Self {
14543a4879SAlex Crichton         let config = &mut config.module_config.config;
15543a4879SAlex Crichton 
16543a4879SAlex Crichton         config.min_memories = config.min_memories.min(1);
17543a4879SAlex Crichton         config.max_memories = config.max_memories.min(1);
18c3f8415aSAndrew Brown         config.min_tables = config.min_tables.min(1);
19c3f8415aSAndrew Brown         config.max_tables = config.max_tables.min(1);
20fd98814bSAlex Crichton 
21543a4879SAlex Crichton         config.memory64_enabled = false;
22543a4879SAlex Crichton         config.threads_enabled = false;
23543a4879SAlex Crichton         config.bulk_memory_enabled = false;
24543a4879SAlex Crichton         config.reference_types_enabled = false;
2580ed395eSAlex Crichton         config.tail_call_enabled = false;
2680ed395eSAlex Crichton         config.relaxed_simd_enabled = false;
27edad0bbcSNick Fitzgerald         config.custom_page_sizes_enabled = false;
2872ded108SAlex Crichton         config.wide_arithmetic_enabled = false;
29d79555adSAlex Crichton         config.extended_const_enabled = false;
303aa39239SChris Fallin         config.exceptions_enabled = false;
31543a4879SAlex Crichton 
32543a4879SAlex Crichton         Self
335ec92d59SAndrew Brown     }
345ec92d59SAndrew Brown }
355ec92d59SAndrew Brown 
365ec92d59SAndrew Brown impl DiffEngine for SpecInterpreter {
name(&self) -> &'static str375ec92d59SAndrew Brown     fn name(&self) -> &'static str {
385ec92d59SAndrew Brown         "spec"
395ec92d59SAndrew Brown     }
405ec92d59SAndrew Brown 
instantiate(&mut self, wasm: &[u8]) -> Result<Box<dyn DiffInstance>>41fd98814bSAlex Crichton     fn instantiate(&mut self, wasm: &[u8]) -> Result<Box<dyn DiffInstance>> {
42c3f8415aSAndrew Brown         let instance = wasm_spec_interpreter::instantiate(wasm)
43*93d22fcdSNick Fitzgerald             .map_err(|e| format_err!("failed to instantiate in spec interpreter: {e}"))?;
44c3f8415aSAndrew Brown         Ok(Box::new(SpecInstance { instance }))
455ec92d59SAndrew Brown     }
46fd98814bSAlex Crichton 
assert_error_match(&self, err: &Error, trap: &Trap)47b3b50943SAlex Crichton     fn assert_error_match(&self, err: &Error, trap: &Trap) {
48fd98814bSAlex Crichton         // TODO: implement this for the spec interpreter
497f0228c9SAlex Crichton         let _ = (trap, err);
50fd98814bSAlex Crichton     }
5110dbb199SAlex Crichton 
is_non_deterministic_error(&self, err: &Error) -> bool525b9e8765SNick Fitzgerald     fn is_non_deterministic_error(&self, err: &Error) -> bool {
53c3f8415aSAndrew Brown         err.to_string().contains("(Isabelle) call stack exhausted")
5410dbb199SAlex Crichton     }
555ec92d59SAndrew Brown }
565ec92d59SAndrew Brown 
575ec92d59SAndrew Brown struct SpecInstance {
58c3f8415aSAndrew Brown     instance: wasm_spec_interpreter::SpecInstance,
595ec92d59SAndrew Brown }
605ec92d59SAndrew Brown 
615ec92d59SAndrew Brown impl DiffInstance for SpecInstance {
name(&self) -> &'static str625ec92d59SAndrew Brown     fn name(&self) -> &'static str {
635ec92d59SAndrew Brown         "spec"
645ec92d59SAndrew Brown     }
655ec92d59SAndrew Brown 
evaluate( &mut self, function_name: &str, arguments: &[DiffValue], _results: &[DiffValueType], ) -> Result<Option<Vec<DiffValue>>>665ec92d59SAndrew Brown     fn evaluate(
675ec92d59SAndrew Brown         &mut self,
68c3f8415aSAndrew Brown         function_name: &str,
695ec92d59SAndrew Brown         arguments: &[DiffValue],
70fd98814bSAlex Crichton         _results: &[DiffValueType],
71fd98814bSAlex Crichton     ) -> Result<Option<Vec<DiffValue>>> {
72c3f8415aSAndrew Brown         let arguments = arguments.iter().map(SpecValue::from).collect();
73c3f8415aSAndrew Brown         match wasm_spec_interpreter::interpret(&self.instance, function_name, Some(arguments)) {
74c3f8415aSAndrew Brown             Ok(results) => Ok(Some(results.into_iter().map(SpecValue::into).collect())),
75*93d22fcdSNick Fitzgerald             Err(err) => Err(format_err!(err)),
765ec92d59SAndrew Brown         }
775ec92d59SAndrew Brown     }
785ec92d59SAndrew Brown 
get_global(&mut self, name: &str, _ty: DiffValueType) -> Option<DiffValue>79c3f8415aSAndrew Brown     fn get_global(&mut self, name: &str, _ty: DiffValueType) -> Option<DiffValue> {
8090ac295eSAlex Crichton         use wasm_spec_interpreter::{SpecExport::Global, export};
81c3f8415aSAndrew Brown         if let Ok(Global(g)) = export(&self.instance, name) {
82c3f8415aSAndrew Brown             Some(g.into())
83c3f8415aSAndrew Brown         } else {
84a0442ea0SHamir Mahal             panic!("expected an exported global value at name `{name}`")
855ec92d59SAndrew Brown         }
865ec92d59SAndrew Brown     }
875ec92d59SAndrew Brown 
get_memory(&mut self, name: &str, _shared: bool) -> Option<Vec<u8>>88c3f8415aSAndrew Brown     fn get_memory(&mut self, name: &str, _shared: bool) -> Option<Vec<u8>> {
8990ac295eSAlex Crichton         use wasm_spec_interpreter::{SpecExport::Memory, export};
90c3f8415aSAndrew Brown         if let Ok(Memory(m)) = export(&self.instance, name) {
91c3f8415aSAndrew Brown             Some(m)
92c3f8415aSAndrew Brown         } else {
93a0442ea0SHamir Mahal             panic!("expected an exported memory at name `{name}`")
94c3f8415aSAndrew Brown         }
95c3f8415aSAndrew Brown     }
96c3f8415aSAndrew Brown }
97c3f8415aSAndrew Brown 
98c3f8415aSAndrew Brown impl From<&DiffValue> for SpecValue {
from(v: &DiffValue) -> Self995ec92d59SAndrew Brown     fn from(v: &DiffValue) -> Self {
1005ec92d59SAndrew Brown         match *v {
101c3f8415aSAndrew Brown             DiffValue::I32(n) => SpecValue::I32(n),
102c3f8415aSAndrew Brown             DiffValue::I64(n) => SpecValue::I64(n),
103c3f8415aSAndrew Brown             DiffValue::F32(n) => SpecValue::F32(n as i32),
104c3f8415aSAndrew Brown             DiffValue::F64(n) => SpecValue::F64(n as i64),
105c3f8415aSAndrew Brown             DiffValue::V128(n) => SpecValue::V128(n.to_le_bytes().to_vec()),
106eaa4632eSChris Fallin             DiffValue::FuncRef { .. }
107eaa4632eSChris Fallin             | DiffValue::ExternRef { .. }
108eaa4632eSChris Fallin             | DiffValue::AnyRef { .. }
109a631d20aSPaul Osborne             | DiffValue::ExnRef { .. }
110a631d20aSPaul Osborne             | DiffValue::ContRef { .. } => {
1110fa13013SNick Fitzgerald                 unimplemented!()
1120fa13013SNick Fitzgerald             }
1135ec92d59SAndrew Brown         }
1145ec92d59SAndrew Brown     }
1155ec92d59SAndrew Brown }
1165ec92d59SAndrew Brown 
117d3e7548eSAlex Crichton impl From<SpecValue> for DiffValue {
from(spec: SpecValue) -> DiffValue118d3e7548eSAlex Crichton     fn from(spec: SpecValue) -> DiffValue {
119d3e7548eSAlex Crichton         match spec {
120c3f8415aSAndrew Brown             SpecValue::I32(n) => DiffValue::I32(n),
121c3f8415aSAndrew Brown             SpecValue::I64(n) => DiffValue::I64(n),
122c3f8415aSAndrew Brown             SpecValue::F32(n) => DiffValue::F32(n as u32),
123c3f8415aSAndrew Brown             SpecValue::F64(n) => DiffValue::F64(n as u64),
124c3f8415aSAndrew Brown             SpecValue::V128(n) => {
1255ec92d59SAndrew Brown                 assert_eq!(n.len(), 16);
1265ec92d59SAndrew Brown                 DiffValue::V128(u128::from_le_bytes(n.as_slice().try_into().unwrap()))
1275ec92d59SAndrew Brown             }
1285ec92d59SAndrew Brown         }
1295ec92d59SAndrew Brown     }
1305ec92d59SAndrew Brown }
1315ec92d59SAndrew Brown 
1325ec92d59SAndrew Brown /// Set up the OCaml runtime for triggering its signal handler configuration.
1335ec92d59SAndrew Brown ///
1345ec92d59SAndrew Brown /// Because both the OCaml runtime and Wasmtime set up signal handlers, we must
1355ec92d59SAndrew Brown /// carefully decide when to instantiate them; this function allows us to
1365ec92d59SAndrew Brown /// control when. Wasmtime uses these signal handlers for catching various
1375ec92d59SAndrew Brown /// WebAssembly failures. On certain OSes (e.g. Linux `x86_64`), the signal
1385ec92d59SAndrew Brown /// handlers interfere, observable as an uncaught `SIGSEGV`--not even caught by
1395ec92d59SAndrew Brown /// libFuzzer.
1405ec92d59SAndrew Brown ///
1415ec92d59SAndrew Brown /// This failure can be mitigated by always running Wasmtime second in
1425ec92d59SAndrew Brown /// differential fuzzing. In some cases, however, this is not possible because
1435ec92d59SAndrew Brown /// which engine will execute first is unknown. This function can be explicitly
1445ec92d59SAndrew Brown /// executed first, e.g., during global initialization, to avoid this issue.
setup_ocaml_runtime()1455ec92d59SAndrew Brown pub fn setup_ocaml_runtime() {
1465ec92d59SAndrew Brown     wasm_spec_interpreter::setup_ocaml_runtime();
1475ec92d59SAndrew Brown }
148fd98814bSAlex Crichton 
149ec3b2d22SNick Fitzgerald #[cfg(test)]
150ec3b2d22SNick Fitzgerald mod tests {
151ec3b2d22SNick Fitzgerald     use super::*;
152ec3b2d22SNick Fitzgerald 
153fd98814bSAlex Crichton     #[test]
smoke()154fd98814bSAlex Crichton     fn smoke() {
155fd98814bSAlex Crichton         if !wasm_spec_interpreter::support_compiled_in() {
156fd98814bSAlex Crichton             return;
157fd98814bSAlex Crichton         }
158543a4879SAlex Crichton         crate::oracles::engine::smoke_test_engine(|_, config| Ok(SpecInterpreter::new(config)))
159fd98814bSAlex Crichton     }
160ec3b2d22SNick Fitzgerald }
161