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:
@@ -1,4 +1,6 @@
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// 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
|
||||
@@ -32,3 +34,38 @@ void wasmtime_longjmp(void *JmpBuf) {
|
||||
platform_jmp_buf *buf = (platform_jmp_buf*) JmpBuf;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -27,23 +27,9 @@ struct JITDescriptor {
|
||||
first_entry: *mut JITCodeEntry,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[used]
|
||||
static mut __jit_debug_descriptor: JITDescriptor = JITDescriptor {
|
||||
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);
|
||||
}
|
||||
extern "C" {
|
||||
fn wasmtime_jit_debug_descriptor() -> *mut JITDescriptor;
|
||||
fn __jit_debug_register_code();
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
@@ -102,41 +88,43 @@ unsafe impl Sync for GdbJitImageRegistration {}
|
||||
|
||||
unsafe fn register_gdb_jit_image(entry: *mut JITCodeEntry) {
|
||||
let _lock = GDB_REGISTRATION.lock().unwrap();
|
||||
let desc = &mut *wasmtime_jit_debug_descriptor();
|
||||
|
||||
// Add it to the linked list in the JIT descriptor.
|
||||
(*entry).next_entry = __jit_debug_descriptor.first_entry;
|
||||
if !__jit_debug_descriptor.first_entry.is_null() {
|
||||
(*__jit_debug_descriptor.first_entry).prev_entry = entry;
|
||||
(*entry).next_entry = desc.first_entry;
|
||||
if !desc.first_entry.is_null() {
|
||||
(*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.
|
||||
__jit_debug_descriptor.relevant_entry = entry;
|
||||
desc.relevant_entry = entry;
|
||||
// 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_descriptor.action_flag = JIT_NOACTION;
|
||||
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
|
||||
desc.action_flag = JIT_NOACTION;
|
||||
desc.relevant_entry = ptr::null_mut();
|
||||
}
|
||||
|
||||
unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
|
||||
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.
|
||||
if !(*entry).prev_entry.is_null() {
|
||||
(*(*entry).prev_entry).next_entry = (*entry).next_entry;
|
||||
} else {
|
||||
__jit_debug_descriptor.first_entry = (*entry).next_entry;
|
||||
desc.first_entry = (*entry).next_entry;
|
||||
}
|
||||
if !(*entry).next_entry.is_null() {
|
||||
(*(*entry).next_entry).prev_entry = (*entry).prev_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.
|
||||
__jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
|
||||
desc.action_flag = JIT_UNREGISTER_FN;
|
||||
__jit_debug_register_code();
|
||||
|
||||
__jit_debug_descriptor.action_flag = JIT_NOACTION;
|
||||
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
|
||||
desc.action_flag = JIT_NOACTION;
|
||||
desc.relevant_entry = ptr::null_mut();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user