Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/fuzzing/src/oracles/diff_spec.rs
1693 views
1
//! Evaluate an exported Wasm function using the WebAssembly specification
2
//! reference interpreter.
3
4
use crate::generators::{Config, DiffValue, DiffValueType};
5
use crate::oracles::engine::{DiffEngine, DiffInstance};
6
use anyhow::{Error, Result, anyhow};
7
use wasm_spec_interpreter::SpecValue;
8
use wasmtime::Trap;
9
10
/// A wrapper for `wasm-spec-interpreter` as a [`DiffEngine`].
11
pub struct SpecInterpreter;
12
13
impl 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
37
impl 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
// TODO: implement this for the spec interpreter
50
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
58
struct SpecInstance {
59
instance: wasm_spec_interpreter::SpecInstance,
60
}
61
62
impl 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
99
impl 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
118
impl 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
133
/// Set up the OCaml runtime for triggering its signal handler configuration.
134
///
135
/// Because both the OCaml runtime and Wasmtime set up signal handlers, we must
136
/// carefully decide when to instantiate them; this function allows us to
137
/// control when. Wasmtime uses these signal handlers for catching various
138
/// WebAssembly failures. On certain OSes (e.g. Linux `x86_64`), the signal
139
/// handlers interfere, observable as an uncaught `SIGSEGV`--not even caught by
140
/// libFuzzer.
141
///
142
/// This failure can be mitigated by always running Wasmtime second in
143
/// differential fuzzing. In some cases, however, this is not possible because
144
/// which engine will execute first is unknown. This function can be explicitly
145
/// executed first, e.g., during global initialization, to avoid this issue.
146
pub fn setup_ocaml_runtime() {
147
wasm_spec_interpreter::setup_ocaml_runtime();
148
}
149
150
#[cfg(test)]
151
mod 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
}
162
163