Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/fuzzing/src/oracles/diff_spec.rs
3063 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 wasm_spec_interpreter::SpecValue;
7
use wasmtime::{Error, Result, Trap, format_err};
8
9
/// A wrapper for `wasm-spec-interpreter` as a [`DiffEngine`].
10
pub struct SpecInterpreter;
11
12
impl SpecInterpreter {
13
pub(crate) fn new(config: &mut Config) -> Self {
14
let config = &mut config.module_config.config;
15
16
config.min_memories = config.min_memories.min(1);
17
config.max_memories = config.max_memories.min(1);
18
config.min_tables = config.min_tables.min(1);
19
config.max_tables = config.max_tables.min(1);
20
21
config.memory64_enabled = false;
22
config.threads_enabled = false;
23
config.bulk_memory_enabled = false;
24
config.reference_types_enabled = false;
25
config.tail_call_enabled = false;
26
config.relaxed_simd_enabled = false;
27
config.custom_page_sizes_enabled = false;
28
config.wide_arithmetic_enabled = false;
29
config.extended_const_enabled = false;
30
config.exceptions_enabled = false;
31
32
Self
33
}
34
}
35
36
impl DiffEngine for SpecInterpreter {
37
fn name(&self) -> &'static str {
38
"spec"
39
}
40
41
fn instantiate(&mut self, wasm: &[u8]) -> Result<Box<dyn DiffInstance>> {
42
let instance = wasm_spec_interpreter::instantiate(wasm)
43
.map_err(|e| format_err!("failed to instantiate in spec interpreter: {e}"))?;
44
Ok(Box::new(SpecInstance { instance }))
45
}
46
47
fn assert_error_match(&self, err: &Error, trap: &Trap) {
48
// TODO: implement this for the spec interpreter
49
let _ = (trap, err);
50
}
51
52
fn is_non_deterministic_error(&self, err: &Error) -> bool {
53
err.to_string().contains("(Isabelle) call stack exhausted")
54
}
55
}
56
57
struct SpecInstance {
58
instance: wasm_spec_interpreter::SpecInstance,
59
}
60
61
impl DiffInstance for SpecInstance {
62
fn name(&self) -> &'static str {
63
"spec"
64
}
65
66
fn evaluate(
67
&mut self,
68
function_name: &str,
69
arguments: &[DiffValue],
70
_results: &[DiffValueType],
71
) -> Result<Option<Vec<DiffValue>>> {
72
let arguments = arguments.iter().map(SpecValue::from).collect();
73
match wasm_spec_interpreter::interpret(&self.instance, function_name, Some(arguments)) {
74
Ok(results) => Ok(Some(results.into_iter().map(SpecValue::into).collect())),
75
Err(err) => Err(format_err!(err)),
76
}
77
}
78
79
fn get_global(&mut self, name: &str, _ty: DiffValueType) -> Option<DiffValue> {
80
use wasm_spec_interpreter::{SpecExport::Global, export};
81
if let Ok(Global(g)) = export(&self.instance, name) {
82
Some(g.into())
83
} else {
84
panic!("expected an exported global value at name `{name}`")
85
}
86
}
87
88
fn get_memory(&mut self, name: &str, _shared: bool) -> Option<Vec<u8>> {
89
use wasm_spec_interpreter::{SpecExport::Memory, export};
90
if let Ok(Memory(m)) = export(&self.instance, name) {
91
Some(m)
92
} else {
93
panic!("expected an exported memory at name `{name}`")
94
}
95
}
96
}
97
98
impl From<&DiffValue> for SpecValue {
99
fn from(v: &DiffValue) -> Self {
100
match *v {
101
DiffValue::I32(n) => SpecValue::I32(n),
102
DiffValue::I64(n) => SpecValue::I64(n),
103
DiffValue::F32(n) => SpecValue::F32(n as i32),
104
DiffValue::F64(n) => SpecValue::F64(n as i64),
105
DiffValue::V128(n) => SpecValue::V128(n.to_le_bytes().to_vec()),
106
DiffValue::FuncRef { .. }
107
| DiffValue::ExternRef { .. }
108
| DiffValue::AnyRef { .. }
109
| DiffValue::ExnRef { .. }
110
| DiffValue::ContRef { .. } => {
111
unimplemented!()
112
}
113
}
114
}
115
}
116
117
impl From<SpecValue> for DiffValue {
118
fn from(spec: SpecValue) -> DiffValue {
119
match spec {
120
SpecValue::I32(n) => DiffValue::I32(n),
121
SpecValue::I64(n) => DiffValue::I64(n),
122
SpecValue::F32(n) => DiffValue::F32(n as u32),
123
SpecValue::F64(n) => DiffValue::F64(n as u64),
124
SpecValue::V128(n) => {
125
assert_eq!(n.len(), 16);
126
DiffValue::V128(u128::from_le_bytes(n.as_slice().try_into().unwrap()))
127
}
128
}
129
}
130
}
131
132
/// Set up the OCaml runtime for triggering its signal handler configuration.
133
///
134
/// Because both the OCaml runtime and Wasmtime set up signal handlers, we must
135
/// carefully decide when to instantiate them; this function allows us to
136
/// control when. Wasmtime uses these signal handlers for catching various
137
/// WebAssembly failures. On certain OSes (e.g. Linux `x86_64`), the signal
138
/// handlers interfere, observable as an uncaught `SIGSEGV`--not even caught by
139
/// libFuzzer.
140
///
141
/// This failure can be mitigated by always running Wasmtime second in
142
/// differential fuzzing. In some cases, however, this is not possible because
143
/// which engine will execute first is unknown. This function can be explicitly
144
/// executed first, e.g., during global initialization, to avoid this issue.
145
pub fn setup_ocaml_runtime() {
146
wasm_spec_interpreter::setup_ocaml_runtime();
147
}
148
149
#[cfg(test)]
150
mod tests {
151
use super::*;
152
153
#[test]
154
fn smoke() {
155
if !wasm_spec_interpreter::support_compiled_in() {
156
return;
157
}
158
crate::oracles::engine::smoke_test_engine(|_, config| Ok(SpecInterpreter::new(config)))
159
}
160
}
161
162