wasmtime_fuzzing/oracles/
diff_spec.rs1use crate::generators::{Config, DiffValue, DiffValueType};
5use crate::oracles::engine::{DiffEngine, DiffInstance};
6use anyhow::{Error, Result, anyhow};
7use wasm_spec_interpreter::SpecValue;
8use wasmtime::Trap;
9
10pub struct SpecInterpreter;
12
13impl SpecInterpreter {
14 pub(crate) fn new(config: &mut Config) -> Self {
15 let config = &mut config.module_config.config;
16
17 config.min_memories = config.min_memories.min(1);
18 config.max_memories = config.max_memories.min(1);
19 config.min_tables = config.min_tables.min(1);
20 config.max_tables = config.max_tables.min(1);
21
22 config.memory64_enabled = false;
23 config.threads_enabled = false;
24 config.bulk_memory_enabled = false;
25 config.reference_types_enabled = false;
26 config.tail_call_enabled = false;
27 config.relaxed_simd_enabled = false;
28 config.custom_page_sizes_enabled = false;
29 config.wide_arithmetic_enabled = false;
30 config.extended_const_enabled = false;
31 config.exceptions_enabled = false;
32
33 Self
34 }
35}
36
37impl DiffEngine for SpecInterpreter {
38 fn name(&self) -> &'static str {
39 "spec"
40 }
41
42 fn instantiate(&mut self, wasm: &[u8]) -> Result<Box<dyn DiffInstance>> {
43 let instance = wasm_spec_interpreter::instantiate(wasm)
44 .map_err(|e| anyhow!("failed to instantiate in spec interpreter: {}", e))?;
45 Ok(Box::new(SpecInstance { instance }))
46 }
47
48 fn assert_error_match(&self, err: &Error, trap: &Trap) {
49 let _ = (trap, err);
51 }
52
53 fn is_non_deterministic_error(&self, err: &Error) -> bool {
54 err.to_string().contains("(Isabelle) call stack exhausted")
55 }
56}
57
58struct SpecInstance {
59 instance: wasm_spec_interpreter::SpecInstance,
60}
61
62impl DiffInstance for SpecInstance {
63 fn name(&self) -> &'static str {
64 "spec"
65 }
66
67 fn evaluate(
68 &mut self,
69 function_name: &str,
70 arguments: &[DiffValue],
71 _results: &[DiffValueType],
72 ) -> Result<Option<Vec<DiffValue>>> {
73 let arguments = arguments.iter().map(SpecValue::from).collect();
74 match wasm_spec_interpreter::interpret(&self.instance, function_name, Some(arguments)) {
75 Ok(results) => Ok(Some(results.into_iter().map(SpecValue::into).collect())),
76 Err(err) => Err(anyhow!(err)),
77 }
78 }
79
80 fn get_global(&mut self, name: &str, _ty: DiffValueType) -> Option<DiffValue> {
81 use wasm_spec_interpreter::{SpecExport::Global, export};
82 if let Ok(Global(g)) = export(&self.instance, name) {
83 Some(g.into())
84 } else {
85 panic!("expected an exported global value at name `{name}`")
86 }
87 }
88
89 fn get_memory(&mut self, name: &str, _shared: bool) -> Option<Vec<u8>> {
90 use wasm_spec_interpreter::{SpecExport::Memory, export};
91 if let Ok(Memory(m)) = export(&self.instance, name) {
92 Some(m)
93 } else {
94 panic!("expected an exported memory at name `{name}`")
95 }
96 }
97}
98
99impl From<&DiffValue> for SpecValue {
100 fn from(v: &DiffValue) -> Self {
101 match *v {
102 DiffValue::I32(n) => SpecValue::I32(n),
103 DiffValue::I64(n) => SpecValue::I64(n),
104 DiffValue::F32(n) => SpecValue::F32(n as i32),
105 DiffValue::F64(n) => SpecValue::F64(n as i64),
106 DiffValue::V128(n) => SpecValue::V128(n.to_le_bytes().to_vec()),
107 DiffValue::FuncRef { .. }
108 | DiffValue::ExternRef { .. }
109 | DiffValue::AnyRef { .. }
110 | DiffValue::ExnRef { .. }
111 | DiffValue::ContRef { .. } => {
112 unimplemented!()
113 }
114 }
115 }
116}
117
118impl From<SpecValue> for DiffValue {
119 fn from(spec: SpecValue) -> DiffValue {
120 match spec {
121 SpecValue::I32(n) => DiffValue::I32(n),
122 SpecValue::I64(n) => DiffValue::I64(n),
123 SpecValue::F32(n) => DiffValue::F32(n as u32),
124 SpecValue::F64(n) => DiffValue::F64(n as u64),
125 SpecValue::V128(n) => {
126 assert_eq!(n.len(), 16);
127 DiffValue::V128(u128::from_le_bytes(n.as_slice().try_into().unwrap()))
128 }
129 }
130 }
131}
132
133pub fn setup_ocaml_runtime() {
147 wasm_spec_interpreter::setup_ocaml_runtime();
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn smoke() {
156 if !wasm_spec_interpreter::support_compiled_in() {
157 return;
158 }
159 crate::oracles::engine::smoke_test_engine(|_, config| Ok(SpecInterpreter::new(config)))
160 }
161}