Add differential fuzzing against V8 (#3264)

* Add differential fuzzing against V8

This commit adds a differential fuzzing target to Wasmtime along the
lines of the wasmi and spec interpreters we already have, but with V8
instead. The intention here is that wasmi is unlikely to receive updates
over time (e.g. for SIMD), and the spec interpreter is not suitable for
fuzzing against in general due to its performance characteristics. The
hope is that V8 is indeed appropriate to fuzz against because it's
naturally receiving updates and it also is expected to have good
performance.

Here the `rusty_v8` crate is used which provides bindings to V8 as well
as precompiled binaries by default. This matches exactly the use case we
need and at least for now I think the `rusty_v8` crate will be
maintained by the Deno folks as they continue to develop it. If it
becomes an issue though maintaining we can evaluate other options to
have differential fuzzing against.

For now this commit enables the SIMD and bulk-memory feature of
fuzz-target-generation which should enable them to get
differentially-fuzzed with V8 in addition to the compilation fuzzing
we're already getting.

* Use weak linkage for GDB jit helpers

This should help us deduplicate our symbol with other JIT runtimes, if
any. For now this leans on some C helpers to define the weak linkage
since Rust doesn't support that on stable yet.

* Don't use rusty_v8 on MinGW

They don't have precompiled libraries there.

* Fix msvc build

* Comment about execution
This commit is contained in:
Alex Crichton
2021-08-31 09:34:55 -05:00
committed by GitHub
parent ef3ec594ce
commit 4376cf2609
10 changed files with 432 additions and 38 deletions

35
Cargo.lock generated
View File

@@ -1274,6 +1274,16 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "fslock"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbc585f4fe7227b37ef0216444c87ca8ab6051622e4e2bc75d4bed4ea5106148"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "fst" name = "fst"
version = "0.4.6" version = "0.4.6"
@@ -2649,6 +2659,19 @@ dependencies = [
"wait-timeout", "wait-timeout",
] ]
[[package]]
name = "rusty_v8"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fc062fb861b82fa7ac4e1a009da873279a10180d2133574e4219d870038c1c"
dependencies = [
"bitflags",
"fslock",
"lazy_static",
"libc",
"which",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.5" version = "1.0.5"
@@ -3739,6 +3762,7 @@ dependencies = [
"env_logger 0.8.3", "env_logger 0.8.3",
"log", "log",
"rayon", "rayon",
"rusty_v8",
"wasm-encoder", "wasm-encoder",
"wasm-smith", "wasm-smith",
"wasm-spec-interpreter", "wasm-spec-interpreter",
@@ -3905,6 +3929,17 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "which"
version = "4.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9"
dependencies = [
"either",
"lazy_static",
"libc",
]
[[package]] [[package]]
name = "wiggle" name = "wiggle"
version = "0.29.0" version = "0.29.0"

View File

@@ -22,6 +22,13 @@ wasm-smith = "0.7.0"
wasm-spec-interpreter = { path = "./wasm-spec-interpreter" } wasm-spec-interpreter = { path = "./wasm-spec-interpreter" }
wasmi = "0.7.0" wasmi = "0.7.0"
# We rely on precompiled v8 binaries, but rusty-v8 doesn't have a precompiled
# binary for MinGW which is built on our CI. It does have one for Windows-msvc,
# though, so we could use that if we wanted. For now though just simplify a bit
# and don't depend on this on Windows.
[target.'cfg(not(windows))'.dependencies]
rusty_v8 = "0.27"
[dev-dependencies] [dev-dependencies]
wat = "1.0.37" wat = "1.0.37"

View File

@@ -21,6 +21,11 @@ use std::time::{Duration, Instant};
use wasmtime::*; use wasmtime::*;
use wasmtime_wast::WastContext; use wasmtime_wast::WastContext;
#[cfg(not(windows))]
pub use v8::*;
#[cfg(not(windows))]
mod v8;
static CNT: AtomicUsize = AtomicUsize::new(0); static CNT: AtomicUsize = AtomicUsize::new(0);
fn log_wasm(wasm: &[u8]) { fn log_wasm(wasm: &[u8]) {
@@ -563,9 +568,11 @@ pub fn table_ops(
/// conform to certain specifications: one exported function, one exported /// conform to certain specifications: one exported function, one exported
/// memory. /// memory.
#[derive(Default, Debug, Arbitrary, Clone)] #[derive(Default, Debug, Arbitrary, Clone)]
pub struct SingleFunctionModuleConfig; pub struct SingleFunctionModuleConfig<const SIMD: bool, const BULK: bool>;
impl wasm_smith::Config for SingleFunctionModuleConfig { impl<const SIMD: bool, const BULK: bool> wasm_smith::Config
for SingleFunctionModuleConfig<SIMD, BULK>
{
fn allow_start_export(&self) -> bool { fn allow_start_export(&self) -> bool {
false false
} }
@@ -611,6 +618,14 @@ impl wasm_smith::Config for SingleFunctionModuleConfig {
fn canonicalize_nans(&self) -> bool { fn canonicalize_nans(&self) -> bool {
true true
} }
fn simd_enabled(&self) -> bool {
SIMD
}
fn bulk_memory_enabled(&self) -> bool {
BULK
}
} }
/// Perform differential execution between Cranelift and wasmi, diffing the /// Perform differential execution between Cranelift and wasmi, diffing the
@@ -638,7 +653,7 @@ pub fn differential_wasmi_execution(wasm: &[u8], config: &crate::generators::Con
// Introspect wasmtime module to find name of an exported function and of an // Introspect wasmtime module to find name of an exported function and of an
// exported memory. // exported memory.
let func_name = first_exported_function(&wasmtime_module)?; let (func_name, _ty) = first_exported_function(&wasmtime_module)?;
let memory_name = first_exported_memory(&wasmtime_module)?; let memory_name = first_exported_memory(&wasmtime_module)?;
let wasmi_mem_export = wasmi_instance.export_by_name(memory_name).unwrap(); let wasmi_mem_export = wasmi_instance.export_by_name(memory_name).unwrap();
@@ -816,7 +831,7 @@ fn run_in_wasmtime(
.context("Wasmtime cannot instantiate module")?; .context("Wasmtime cannot instantiate module")?;
// Find the first exported function. // Find the first exported function.
let func_name = let (func_name, _ty) =
first_exported_function(&wasmtime_module).context("Cannot find exported function")?; first_exported_function(&wasmtime_module).context("Cannot find exported function")?;
let wasmtime_main = wasmtime_instance let wasmtime_main = wasmtime_instance
.get_func(&mut wasmtime_store, &func_name[..]) .get_func(&mut wasmtime_store, &func_name[..])
@@ -828,10 +843,10 @@ fn run_in_wasmtime(
} }
// Introspect wasmtime module to find the name of the first exported function. // Introspect wasmtime module to find the name of the first exported function.
fn first_exported_function(module: &wasmtime::Module) -> Option<&str> { fn first_exported_function(module: &wasmtime::Module) -> Option<(&str, FuncType)> {
for e in module.exports() { for e in module.exports() {
match e.ty() { match e.ty() {
wasmtime::ExternType::Func(..) => return Some(e.name()), wasmtime::ExternType::Func(ty) => return Some((e.name(), ty)),
_ => {} _ => {}
} }
} }

View File

@@ -0,0 +1,293 @@
use super::{first_exported_function, first_exported_memory, log_wasm};
use rusty_v8 as v8;
use std::convert::TryFrom;
use std::sync::Once;
use wasmtime::*;
/// Performs differential execution between Wasmtime and V8.
///
/// This will instantiate the `wasm` provided, which should have no host
/// imports, and then run it in Wasmtime with the `config` specified and V8 with
/// default settings. The first export is executed and if memory is exported
/// it's compared as well.
///
/// Note that it's the caller's responsibility to ensure that the `wasm`
/// doesn't infinitely loop as no protections are done in v8 to prevent this
/// from happening.
pub fn differential_v8_execution(wasm: &[u8], config: &crate::generators::Config) -> Option<()> {
// Wasmtime setup
crate::init_fuzzing();
log_wasm(wasm);
let (wasmtime_module, mut wasmtime_store) = super::differential_store(wasm, config);
log::trace!("compiled module with wasmtime");
// V8 setup
let mut isolate = isolate();
let mut scope = v8::HandleScope::new(&mut *isolate);
let context = v8::Context::new(&mut scope);
let global = context.global(&mut scope);
let mut scope = v8::ContextScope::new(&mut scope, context);
// V8: compile module
let buf = v8::ArrayBuffer::new_backing_store_from_boxed_slice(wasm.into());
let buf = v8::SharedRef::from(buf);
let name = v8::String::new(&mut scope, "WASM_BINARY").unwrap();
let buf = v8::ArrayBuffer::with_backing_store(&mut scope, &buf);
global.set(&mut scope, name.into(), buf.into());
let v8_module = eval(&mut scope, "new WebAssembly.Module(WASM_BINARY)").unwrap();
let name = v8::String::new(&mut scope, "WASM_MODULE").unwrap();
global.set(&mut scope, name.into(), v8_module);
log::trace!("compiled module with v8");
// Wasmtime: instantiate
let wasmtime_instance = wasmtime::Instance::new(&mut wasmtime_store, &wasmtime_module, &[]);
log::trace!("instantiated with wasmtime");
// V8: instantiate
let v8_instance = eval(&mut scope, "new WebAssembly.Instance(WASM_MODULE)");
log::trace!("instantiated with v8");
// Verify V8 and wasmtime match
let (wasmtime_instance, v8_instance) = match (wasmtime_instance, v8_instance) {
(Ok(i1), Ok(i2)) => (i1, i2),
(Ok(_), Err(msg)) => {
panic!("wasmtime succeeded at instantiation, v8 failed: {}", msg)
}
(Err(err), Ok(_)) => {
panic!("v8 succeeded at instantiation, wasmtime failed: {:?}", err)
}
(Err(err), Err(msg)) => {
log::trace!("instantiations failed");
assert_error_matches(&err, &msg);
return None;
}
};
log::trace!("instantiations were successful");
let (func, ty) = first_exported_function(&wasmtime_module)?;
// not supported yet in V8
if ty.params().chain(ty.results()).any(|t| t == ValType::V128) {
log::trace!("exported function uses v128, skipping");
return None;
}
let mut wasmtime_params = Vec::new();
let mut v8_params = Vec::new();
for param in ty.params() {
wasmtime_params.push(match param {
ValType::I32 => Val::I32(0),
ValType::I64 => Val::I64(0),
ValType::F32 => Val::F32(0),
ValType::F64 => Val::F64(0),
_ => unimplemented!(),
});
v8_params.push(match param {
ValType::I32 | ValType::F32 | ValType::F64 => v8::Number::new(&mut scope, 0.0).into(),
ValType::I64 => v8::BigInt::new_from_i64(&mut scope, 0).into(),
_ => unimplemented!(),
});
}
// Wasmtime: call the first exported func
let wasmtime_main = wasmtime_instance
.get_func(&mut wasmtime_store, func)
.expect("function export is present");
let wasmtime_vals = wasmtime_main.call(&mut wasmtime_store, &wasmtime_params);
log::trace!("finished wasmtime invocation");
// V8: call the first exported func
let name = v8::String::new(&mut scope, "WASM_INSTANCE").unwrap();
global.set(&mut scope, name.into(), v8_instance);
let name = v8::String::new(&mut scope, "EXPORT_NAME").unwrap();
let func_name = v8::String::new(&mut scope, func).unwrap();
global.set(&mut scope, name.into(), func_name.into());
let name = v8::String::new(&mut scope, "ARGS").unwrap();
let v8_params = v8::Array::new_with_elements(&mut scope, &v8_params);
global.set(&mut scope, name.into(), v8_params.into());
let v8_vals = eval(
&mut scope,
&format!("WASM_INSTANCE.exports[EXPORT_NAME](...ARGS)"),
);
log::trace!("finished v8 invocation");
// Verify V8 and wasmtime match
match (wasmtime_vals, v8_vals) {
(Ok(wasmtime), Ok(v8)) => {
log::trace!("both executed successfully");
match wasmtime.len() {
0 => assert!(v8.is_undefined()),
1 => assert_val_match(&wasmtime[0], &v8, &mut scope),
_ => {
let array = v8::Local::<'_, v8::Array>::try_from(v8).unwrap();
for (i, wasmtime) in wasmtime.iter().enumerate() {
let v8 = array.get_index(&mut scope, i as u32).unwrap();
assert_val_match(wasmtime, &v8, &mut scope);
// ..
}
}
}
}
(Ok(_), Err(msg)) => {
panic!("wasmtime succeeded at invocation, v8 failed: {}", msg)
}
(Err(err), Ok(_)) => {
panic!("v8 succeeded at invocation, wasmtime failed: {:?}", err)
}
(Err(err), Err(msg)) => {
log::trace!("got two traps");
assert_error_matches(&err, &msg);
return Some(());
}
};
// Verify V8 and wasmtime match memories
if let Some(mem) = first_exported_memory(&wasmtime_module) {
log::trace!("comparing memories");
let wasmtime = wasmtime_instance
.get_memory(&mut wasmtime_store, mem)
.unwrap();
let name = v8::String::new(&mut scope, "MEMORY_NAME").unwrap();
let func_name = v8::String::new(&mut scope, mem).unwrap();
global.set(&mut scope, name.into(), func_name.into());
let v8 = eval(
&mut scope,
&format!("WASM_INSTANCE.exports[MEMORY_NAME].buffer"),
)
.unwrap();
let v8 = v8::Local::<'_, v8::ArrayBuffer>::try_from(v8).unwrap();
let v8_data = v8.get_backing_store();
let wasmtime_data = wasmtime.data(&wasmtime_store);
assert_eq!(wasmtime_data.len(), v8_data.len());
for i in 0..v8_data.len() {
if wasmtime_data[i] != v8_data[i].get() {
panic!("memories differ");
}
}
}
Some(())
}
/// Manufactures a new V8 Isolate to run within.
fn isolate() -> v8::OwnedIsolate {
static INIT: Once = Once::new();
INIT.call_once(|| {
let platform = v8::new_default_platform(0, false).make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();
});
v8::Isolate::new(Default::default())
}
/// Evaluates the JS `code` within `scope`, returning either the result of the
/// computation or the stringified exception if one happened.
fn eval<'s>(
scope: &mut v8::HandleScope<'s>,
code: &str,
) -> Result<v8::Local<'s, v8::Value>, String> {
let mut tc = v8::TryCatch::new(scope);
let mut scope = v8::EscapableHandleScope::new(&mut tc);
let source = v8::String::new(&mut scope, code).unwrap();
let script = v8::Script::compile(&mut scope, source, None).unwrap();
match script.run(&mut scope) {
Some(val) => Ok(scope.escape(val)),
None => {
drop(scope);
assert!(tc.has_caught());
Err(tc
.message()
.unwrap()
.get(&mut tc)
.to_rust_string_lossy(&mut tc))
}
}
}
/// Asserts that the wasmtime value `a` matches the v8 value `b`.
///
/// For NaN values simply just asserts that they're both NaN.
fn assert_val_match(a: &Val, b: &v8::Local<'_, v8::Value>, scope: &mut v8::HandleScope<'_>) {
match *a {
Val::I32(wasmtime) => {
assert_eq!(i64::from(wasmtime), b.to_int32(scope).unwrap().value());
}
Val::I64(wasmtime) => {
assert_eq!((wasmtime, true), b.to_big_int(scope).unwrap().i64_value());
}
Val::F32(wasmtime) => {
same_float(
f64::from(f32::from_bits(wasmtime)),
b.to_number(scope).unwrap().value(),
);
}
Val::F64(wasmtime) => {
same_float(
f64::from_bits(wasmtime),
b.to_number(scope).unwrap().value(),
);
}
_ => panic!("unsupported match {:?}", a),
}
fn same_float(a: f64, b: f64) {
assert!(a == b || (a.is_nan() && b.is_nan()), "{} != {}", a, b);
}
}
/// Attempts to assert that the `wasmtime` error matches the `v8` error string.
///
/// This is not a precise function. This will likely need updates over time as
/// v8 and/or wasmtime changes. The goal here is to generally make sure that
/// both engines fail for basically the same reason.
fn assert_error_matches(wasmtime: &anyhow::Error, v8: &str) {
let wasmtime_msg = match wasmtime.downcast_ref::<Trap>() {
Some(trap) => trap.display_reason().to_string(),
None => format!("{:?}", wasmtime),
};
let verify_wasmtime = |msg: &str| {
assert!(wasmtime_msg.contains(msg), "{}\n!=\n{}", wasmtime_msg, v8);
};
let verify_v8 = |msg: &[&str]| {
assert!(
msg.iter().any(|msg| v8.contains(msg)),
"{:?}\n\t!=\n{}",
wasmtime_msg,
v8
);
};
if let Some(code) = wasmtime.downcast_ref::<Trap>().and_then(|t| t.trap_code()) {
match code {
TrapCode::MemoryOutOfBounds => {
return verify_v8(&[
"memory access out of bounds",
"data segment is out of bounds",
])
}
TrapCode::UnreachableCodeReached => return verify_v8(&["unreachable"]),
TrapCode::IntegerDivisionByZero => {
return verify_v8(&["divide by zero", "remainder by zero"])
}
TrapCode::StackOverflow => return verify_v8(&["call stack size exceeded"]),
TrapCode::IndirectCallToNull => return verify_v8(&["null function"]),
TrapCode::TableOutOfBounds => {
return verify_v8(&[
"table initializer is out of bounds",
"table index is out of bounds",
])
}
TrapCode::BadSignature => return verify_v8(&["function signature mismatch"]),
TrapCode::IntegerOverflow | TrapCode::BadConversionToInteger => {
return verify_v8(&[
"float unrepresentable in integer range",
"divide result unrepresentable",
])
}
other => log::debug!("unknown code {:?}", other),
}
}
verify_wasmtime("not possibly present in an error, just panic please");
}

View File

@@ -1,4 +1,6 @@
#include <setjmp.h> #include <setjmp.h>
#include <stdint.h>
#include <stdlib.h>
// Note that `sigsetjmp` and `siglongjmp` are used here where possible to // Note that `sigsetjmp` and `siglongjmp` are used here where possible to
// explicitly pass a 0 argument to `sigsetjmp` that we don't need to preserve // explicitly pass a 0 argument to `sigsetjmp` that we don't need to preserve
@@ -32,3 +34,38 @@ void wasmtime_longjmp(void *JmpBuf) {
platform_jmp_buf *buf = (platform_jmp_buf*) JmpBuf; platform_jmp_buf *buf = (platform_jmp_buf*) JmpBuf;
platform_longjmp(*buf, 1); platform_longjmp(*buf, 1);
} }
// Just in case cross-language LTO is enabled we set the `noinline` attribute
// and also try to have some sort of side effect in this function with a dummy
// `asm` statement.
//
// Note the `weak` linkage here, though, which is intended to let other code
// override this symbol if it's defined elsewhere, since this definition doesn't
// matter.
#ifndef CFG_TARGET_OS_windows
__attribute__((weak, noinline))
#endif
void __jit_debug_register_code() {
#ifndef CFG_TARGET_OS_windows
asm("");
#endif
}
struct JITDescriptor {
uint32_t version_;
uint32_t action_flag_;
void* relevant_entry_;
void* first_entry_;
};
// Note the `weak` linkage here which is the same purpose as above. We want to
// let other runtimes be able to override this since our own definition isn't
// important.
#ifndef CFG_TARGET_OS_windows
__attribute__((weak))
#endif
struct JITDescriptor __jit_debug_descriptor = {1, 0, NULL, NULL};
struct JITDescriptor* wasmtime_jit_debug_descriptor() {
return &__jit_debug_descriptor;
}

View File

@@ -27,23 +27,9 @@ struct JITDescriptor {
first_entry: *mut JITCodeEntry, first_entry: *mut JITCodeEntry,
} }
#[no_mangle] extern "C" {
#[used] fn wasmtime_jit_debug_descriptor() -> *mut JITDescriptor;
static mut __jit_debug_descriptor: JITDescriptor = JITDescriptor { fn __jit_debug_register_code();
version: 1,
action_flag: JIT_NOACTION,
relevant_entry: ptr::null_mut(),
first_entry: ptr::null_mut(),
};
#[no_mangle]
#[inline(never)]
extern "C" fn __jit_debug_register_code() {
// Hack to not allow inlining even when Rust wants to do it in release mode.
let x = 3;
unsafe {
std::ptr::read_volatile(&x);
}
} }
lazy_static! { lazy_static! {
@@ -102,41 +88,43 @@ unsafe impl Sync for GdbJitImageRegistration {}
unsafe fn register_gdb_jit_image(entry: *mut JITCodeEntry) { unsafe fn register_gdb_jit_image(entry: *mut JITCodeEntry) {
let _lock = GDB_REGISTRATION.lock().unwrap(); let _lock = GDB_REGISTRATION.lock().unwrap();
let desc = &mut *wasmtime_jit_debug_descriptor();
// Add it to the linked list in the JIT descriptor. // Add it to the linked list in the JIT descriptor.
(*entry).next_entry = __jit_debug_descriptor.first_entry; (*entry).next_entry = desc.first_entry;
if !__jit_debug_descriptor.first_entry.is_null() { if !desc.first_entry.is_null() {
(*__jit_debug_descriptor.first_entry).prev_entry = entry; (*desc.first_entry).prev_entry = entry;
} }
__jit_debug_descriptor.first_entry = entry; desc.first_entry = entry;
// Point the relevant_entry field of the descriptor at the entry. // Point the relevant_entry field of the descriptor at the entry.
__jit_debug_descriptor.relevant_entry = entry; desc.relevant_entry = entry;
// Set action_flag to JIT_REGISTER and call __jit_debug_register_code. // Set action_flag to JIT_REGISTER and call __jit_debug_register_code.
__jit_debug_descriptor.action_flag = JIT_REGISTER_FN; desc.action_flag = JIT_REGISTER_FN;
__jit_debug_register_code(); __jit_debug_register_code();
__jit_debug_descriptor.action_flag = JIT_NOACTION; desc.action_flag = JIT_NOACTION;
__jit_debug_descriptor.relevant_entry = ptr::null_mut(); desc.relevant_entry = ptr::null_mut();
} }
unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) { unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
let _lock = GDB_REGISTRATION.lock().unwrap(); let _lock = GDB_REGISTRATION.lock().unwrap();
let desc = &mut *wasmtime_jit_debug_descriptor();
// Remove the code entry corresponding to the code from the linked list. // Remove the code entry corresponding to the code from the linked list.
if !(*entry).prev_entry.is_null() { if !(*entry).prev_entry.is_null() {
(*(*entry).prev_entry).next_entry = (*entry).next_entry; (*(*entry).prev_entry).next_entry = (*entry).next_entry;
} else { } else {
__jit_debug_descriptor.first_entry = (*entry).next_entry; desc.first_entry = (*entry).next_entry;
} }
if !(*entry).next_entry.is_null() { if !(*entry).next_entry.is_null() {
(*(*entry).next_entry).prev_entry = (*entry).prev_entry; (*(*entry).next_entry).prev_entry = (*entry).prev_entry;
} }
// Point the relevant_entry field of the descriptor at the code entry. // Point the relevant_entry field of the descriptor at the code entry.
__jit_debug_descriptor.relevant_entry = entry; desc.relevant_entry = entry;
// Set action_flag to JIT_UNREGISTER and call __jit_debug_register_code. // Set action_flag to JIT_UNREGISTER and call __jit_debug_register_code.
__jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN; desc.action_flag = JIT_UNREGISTER_FN;
__jit_debug_register_code(); __jit_debug_register_code();
__jit_debug_descriptor.action_flag = JIT_NOACTION; desc.action_flag = JIT_NOACTION;
__jit_debug_descriptor.relevant_entry = ptr::null_mut(); desc.relevant_entry = ptr::null_mut();
} }

View File

@@ -64,6 +64,12 @@ path = "fuzz_targets/differential_wasmi.rs"
test = false test = false
doc = false doc = false
[[bin]]
name = "differential_v8"
path = "fuzz_targets/differential_v8.rs"
test = false
doc = false
[[bin]] [[bin]]
name = "spectests" name = "spectests"
path = "fuzz_targets/spectests.rs" path = "fuzz_targets/spectests.rs"

View File

@@ -11,7 +11,7 @@ static EXECUTED: AtomicUsize = AtomicUsize::new(0);
fuzz_target!(|data: ( fuzz_target!(|data: (
generators::Config, generators::Config,
wasm_smith::ConfiguredModule<oracles::SingleFunctionModuleConfig> wasm_smith::ConfiguredModule<oracles::SingleFunctionModuleConfig<false, false>>
)| { )| {
let (config, mut wasm) = data; let (config, mut wasm) = data;
wasm.module.ensure_termination(1000); wasm.module.ensure_termination(1000);

View File

@@ -0,0 +1,13 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use wasmtime_fuzzing::{generators, oracles};
fuzz_target!(|data: (
generators::Config,
wasm_smith::ConfiguredModule<oracles::SingleFunctionModuleConfig<true, true>>
)| {
let (config, mut wasm) = data;
wasm.module.ensure_termination(1000);
oracles::differential_v8_execution(&wasm.module.to_bytes(), &config);
});

View File

@@ -5,7 +5,7 @@ use wasmtime_fuzzing::{generators, oracles};
fuzz_target!(|data: ( fuzz_target!(|data: (
generators::Config, generators::Config,
wasm_smith::ConfiguredModule<oracles::SingleFunctionModuleConfig> wasm_smith::ConfiguredModule<oracles::SingleFunctionModuleConfig<false, false>>
)| { )| {
let (config, mut wasm) = data; let (config, mut wasm) = data;
wasm.module.ensure_termination(1000); wasm.module.ensure_termination(1000);