Fuzz using precompiled modules on CI (#3788)
In working on #3787 I see now that our coverage of loading precompiled files specifically is somewhat lacking, so this adds a config option to the fuzzers where, if enabled, will round-trip all compiled modules through the filesystem to test out the mmapped-file case.
This commit is contained in:
20
Cargo.lock
generated
20
Cargo.lock
generated
@@ -1135,6 +1135,15 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ff"
|
name = "ff"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
@@ -2373,9 +2382,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.8"
|
version = "0.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
|
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
@@ -2816,13 +2825,13 @@ checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.2.0"
|
version = "3.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
|
"fastrand",
|
||||||
"libc",
|
"libc",
|
||||||
"rand 0.8.3",
|
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"remove_dir_all",
|
"remove_dir_all",
|
||||||
"winapi",
|
"winapi",
|
||||||
@@ -3584,6 +3593,7 @@ dependencies = [
|
|||||||
"env_logger 0.8.3",
|
"env_logger 0.8.3",
|
||||||
"log",
|
"log",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
"tempfile",
|
||||||
"v8",
|
"v8",
|
||||||
"wasm-encoder",
|
"wasm-encoder",
|
||||||
"wasm-smith",
|
"wasm-smith",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ arbitrary = { version = "1.0.0", features = ["derive"] }
|
|||||||
env_logger = "0.8.1"
|
env_logger = "0.8.1"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
rayon = "1.2.1"
|
rayon = "1.2.1"
|
||||||
|
tempfile = "3.3.0"
|
||||||
wasmparser = "0.82"
|
wasmparser = "0.82"
|
||||||
wasmprinter = "0.2.32"
|
wasmprinter = "0.2.32"
|
||||||
wasmtime = { path = "../wasmtime" }
|
wasmtime = { path = "../wasmtime" }
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use arbitrary::{Arbitrary, Unstructured};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use wasm_smith::SwarmConfig;
|
use wasm_smith::SwarmConfig;
|
||||||
use wasmtime::{Engine, LinearMemory, MemoryCreator, MemoryType, Store};
|
use wasmtime::{Engine, LinearMemory, MemoryCreator, MemoryType, Module, Store};
|
||||||
|
|
||||||
#[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
enum OptLevel {
|
enum OptLevel {
|
||||||
@@ -62,6 +62,7 @@ pub struct WasmtimeConfig {
|
|||||||
memory_config: MemoryConfig,
|
memory_config: MemoryConfig,
|
||||||
force_jump_veneers: bool,
|
force_jump_veneers: bool,
|
||||||
memfd: bool,
|
memfd: bool,
|
||||||
|
use_precompiled_cwasm: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Arbitrary, Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Arbitrary, Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
@@ -170,6 +171,26 @@ impl Config {
|
|||||||
Ok(Timeout::Fuel(100_000))
|
Ok(Timeout::Fuel(100_000))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compiles the `wasm` within the `engine` provided.
|
||||||
|
///
|
||||||
|
/// This notably will use `Module::{serialize,deserialize_file}` to
|
||||||
|
/// round-trip if configured in the fuzzer.
|
||||||
|
pub fn compile(&self, engine: &Engine, wasm: &[u8]) -> Result<Module> {
|
||||||
|
// Propagate this error in case the caller wants to handle
|
||||||
|
// valid-vs-invalid wasm.
|
||||||
|
let module = Module::new(engine, wasm)?;
|
||||||
|
if !self.wasmtime.use_precompiled_cwasm {
|
||||||
|
return Ok(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't propagate these errors to prevent them from accidentally being
|
||||||
|
// interpreted as invalid wasm, these should never fail on a
|
||||||
|
// well-behaved host system.
|
||||||
|
let file = tempfile::NamedTempFile::new().unwrap();
|
||||||
|
std::fs::write(file.path(), module.serialize().unwrap()).unwrap();
|
||||||
|
unsafe { Ok(Module::deserialize_file(engine, file.path()).unwrap()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UnalignedMemoryCreator;
|
struct UnalignedMemoryCreator;
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ pub fn instantiate(wasm: &[u8], known_valid: bool, config: &generators::Config,
|
|||||||
}
|
}
|
||||||
|
|
||||||
log_wasm(wasm);
|
log_wasm(wasm);
|
||||||
let module = match Module::new(store.engine(), wasm) {
|
let module = match config.compile(store.engine(), wasm) {
|
||||||
Ok(module) => module,
|
Ok(module) => module,
|
||||||
Err(_) if !known_valid => return,
|
Err(_) if !known_valid => return,
|
||||||
Err(e) => panic!("failed to compile module: {:?}", e),
|
Err(e) => panic!("failed to compile module: {:?}", e),
|
||||||
@@ -222,7 +222,7 @@ pub fn differential_execution(
|
|||||||
log::debug!("fuzz config: {:?}", fuzz_config);
|
log::debug!("fuzz config: {:?}", fuzz_config);
|
||||||
|
|
||||||
let mut store = fuzz_config.to_store();
|
let mut store = fuzz_config.to_store();
|
||||||
let module = Module::new(store.engine(), &wasm).unwrap();
|
let module = fuzz_config.compile(store.engine(), &wasm).unwrap();
|
||||||
|
|
||||||
// TODO: we should implement tracing versions of these dummy imports
|
// TODO: we should implement tracing versions of these dummy imports
|
||||||
// that record a trace of the order that imported functions were called
|
// that record a trace of the order that imported functions were called
|
||||||
@@ -432,7 +432,7 @@ pub fn table_ops(mut fuzz_config: generators::Config, ops: generators::table_ops
|
|||||||
|
|
||||||
let wasm = ops.to_wasm_binary();
|
let wasm = ops.to_wasm_binary();
|
||||||
log_wasm(&wasm);
|
log_wasm(&wasm);
|
||||||
let module = match Module::new(store.engine(), &wasm) {
|
let module = match fuzz_config.compile(store.engine(), &wasm) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
@@ -736,7 +736,9 @@ fn differential_store(
|
|||||||
fuzz_config: &generators::Config,
|
fuzz_config: &generators::Config,
|
||||||
) -> (Module, Store<StoreLimits>) {
|
) -> (Module, Store<StoreLimits>) {
|
||||||
let store = fuzz_config.to_store();
|
let store = fuzz_config.to_store();
|
||||||
let module = Module::new(store.engine(), &wasm).expect("Wasmtime can compile module");
|
let module = fuzz_config
|
||||||
|
.compile(store.engine(), wasm)
|
||||||
|
.expect("Wasmtime can compile module");
|
||||||
(module, store)
|
(module, store)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user