Merge pull request #1343 from alexcrichton/no-binaryen

Turn off binaryen in fuzzing by default
This commit is contained in:
Nick Fitzgerald
2020-03-17 13:04:52 -07:00
committed by GitHub
5 changed files with 85 additions and 72 deletions

View File

@@ -79,7 +79,7 @@ jobs:
- run: cargo install cargo-fuzz --vers "^0.7" - run: cargo install cargo-fuzz --vers "^0.7"
- run: cargo fetch - run: cargo fetch
working-directory: ./fuzz working-directory: ./fuzz
- run: cargo fuzz build --release --debug-assertions - run: cargo fuzz build --release --debug-assertions --features binaryen
# Our corpora are too large to run in full on every pull request, they just # Our corpora are too large to run in full on every pull request, they just
# take too long. Instead, we sample some of them and make sure that running # take too long. Instead, we sample some of them and make sure that running
# our fuzzers over the sampled inputs still works OK. # our fuzzers over the sampled inputs still works OK.
@@ -87,35 +87,35 @@ jobs:
find fuzz/corpus/compile -type f \ find fuzz/corpus/compile -type f \
| shuf \ | shuf \
| head -n 3000 \ | head -n 3000 \
| xargs cargo fuzz run compile --release --debug-assertions | xargs cargo fuzz run compile --release --debug-assertions --features binaryen
env: env:
RUST_BACKTRACE: 1 RUST_BACKTRACE: 1
- run: | - run: |
find fuzz/corpus/instantiate -type f \ find fuzz/corpus/instantiate -type f \
| shuf \ | shuf \
| head -n 2000 \ | head -n 2000 \
| xargs cargo fuzz run instantiate --release --debug-assertions | xargs cargo fuzz run instantiate --release --debug-assertions --features binaryen
env: env:
RUST_BACKTRACE: 1 RUST_BACKTRACE: 1
- run: | - run: |
find fuzz/corpus/instantiate_translated -type f \ find fuzz/corpus/instantiate_translated -type f \
| shuf \ | shuf \
| head -n 1000 \ | head -n 1000 \
| xargs cargo fuzz run instantiate_translated --release --debug-assertions | xargs cargo fuzz run instantiate_translated --release --debug-assertions --features binaryen
env: env:
RUST_BACKTRACE: 1 RUST_BACKTRACE: 1
- run: | - run: |
find fuzz/corpus/api_calls -type f \ find fuzz/corpus/api_calls -type f \
| shuf \ | shuf \
| head -n 100 \ | head -n 100 \
| xargs cargo fuzz run api_calls --release --debug-assertions | xargs cargo fuzz run api_calls --release --debug-assertions --features binaryen
env: env:
RUST_BACKTRACE: 1 RUST_BACKTRACE: 1
- run: | - run: |
find fuzz/corpus/differential -type f \ find fuzz/corpus/differential -type f \
| shuf \ | shuf \
| head -n 100 \ | head -n 100 \
| xargs cargo fuzz run differential --release --debug-assertions | xargs cargo fuzz run differential --release --debug-assertions --features binaryen
env: env:
RUST_BACKTRACE: 1 RUST_BACKTRACE: 1

View File

@@ -9,7 +9,7 @@ version = "0.12.0"
[dependencies] [dependencies]
anyhow = "1.0.22" anyhow = "1.0.22"
arbitrary = { version = "0.4.0", features = ["derive"] } arbitrary = { version = "0.4.0", features = ["derive"] }
binaryen = "0.10.0" binaryen = { version = "0.10.0", optional = true }
env_logger = "0.7.1" env_logger = "0.7.1"
log = "0.4.8" log = "0.4.8"
rayon = "1.2.1" rayon = "1.2.1"

View File

@@ -8,20 +8,22 @@
//! wrapper over an external tool, such that the wrapper implements the //! wrapper over an external tool, such that the wrapper implements the
//! `Arbitrary` trait for the wrapped external tool. //! `Arbitrary` trait for the wrapped external tool.
#[cfg(feature = "binaryen")]
pub mod api; pub mod api;
use arbitrary::{Arbitrary, Unstructured}; use arbitrary::Arbitrary;
use std::fmt;
/// A Wasm test case generator that is powered by Binaryen's `wasm-opt -ttf`. /// A Wasm test case generator that is powered by Binaryen's `wasm-opt -ttf`.
#[derive(Clone)] #[derive(Clone)]
#[cfg(feature = "binaryen")]
pub struct WasmOptTtf { pub struct WasmOptTtf {
/// The raw, encoded Wasm bytes. /// The raw, encoded Wasm bytes.
pub wasm: Vec<u8>, pub wasm: Vec<u8>,
} }
impl fmt::Debug for WasmOptTtf { #[cfg(feature = "binaryen")]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { impl std::fmt::Debug for WasmOptTtf {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!( write!(
f, f,
"WasmOptTtf {{ wasm: wat::parse_str(r###\"\n{}\n\"###).unwrap() }}", "WasmOptTtf {{ wasm: wat::parse_str(r###\"\n{}\n\"###).unwrap() }}",
@@ -30,8 +32,9 @@ impl fmt::Debug for WasmOptTtf {
} }
} }
#[cfg(feature = "binaryen")]
impl Arbitrary for WasmOptTtf { impl Arbitrary for WasmOptTtf {
fn arbitrary(input: &mut Unstructured) -> arbitrary::Result<Self> { fn arbitrary(input: &mut arbitrary::Unstructured) -> arbitrary::Result<Self> {
crate::init_fuzzing(); crate::init_fuzzing();
let seed: Vec<u8> = Arbitrary::arbitrary(input)?; let seed: Vec<u8> = Arbitrary::arbitrary(input)?;
let module = binaryen::tools::translate_to_fuzz_mvp(&seed); let module = binaryen::tools::translate_to_fuzz_mvp(&seed);
@@ -39,7 +42,7 @@ impl Arbitrary for WasmOptTtf {
Ok(WasmOptTtf { wasm }) Ok(WasmOptTtf { wasm })
} }
fn arbitrary_take_rest(input: Unstructured) -> arbitrary::Result<Self> { fn arbitrary_take_rest(input: arbitrary::Unstructured) -> arbitrary::Result<Self> {
crate::init_fuzzing(); crate::init_fuzzing();
let seed: Vec<u8> = Arbitrary::arbitrary_take_rest(input)?; let seed: Vec<u8> = Arbitrary::arbitrary_take_rest(input)?;
let module = binaryen::tools::translate_to_fuzz_mvp(&seed); let module = binaryen::tools::translate_to_fuzz_mvp(&seed);

View File

@@ -12,8 +12,7 @@
pub mod dummy; pub mod dummy;
use dummy::{dummy_imports, dummy_values}; use dummy::dummy_imports;
use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use wasmtime::*; use wasmtime::*;
@@ -109,10 +108,13 @@ pub fn compile(wasm: &[u8], strategy: Strategy) {
/// exports. Modulo OOM, non-canonical NaNs, and usage of Wasm features that are /// exports. Modulo OOM, non-canonical NaNs, and usage of Wasm features that are
/// or aren't enabled for different configs, we should get the same results when /// or aren't enabled for different configs, we should get the same results when
/// we call the exported functions for all of our different configs. /// we call the exported functions for all of our different configs.
#[cfg(feature = "binaryen")]
pub fn differential_execution( pub fn differential_execution(
ttf: &crate::generators::WasmOptTtf, ttf: &crate::generators::WasmOptTtf,
configs: &[crate::generators::DifferentialConfig], configs: &[crate::generators::DifferentialConfig],
) { ) {
use std::collections::{HashMap, HashSet};
crate::init_fuzzing(); crate::init_fuzzing();
// We need at least two configs. // We need at least two configs.
@@ -204,7 +206,7 @@ pub fn differential_execution(
}; };
let ty = f.ty(); let ty = f.ty();
let params = match dummy_values(ty.params()) { let params = match dummy::dummy_values(ty.params()) {
Ok(p) => p, Ok(p) => p,
Err(_) => continue, Err(_) => continue,
}; };
@@ -216,75 +218,77 @@ pub fn differential_execution(
assert_same_export_func_result(&existing_result, &this_result, name); assert_same_export_func_result(&existing_result, &this_result, name);
} }
} }
}
fn init_hang_limit(instance: &Instance) { fn init_hang_limit(instance: &Instance) {
match instance.get_export("hangLimitInitializer") { match instance.get_export("hangLimitInitializer") {
None => return, None => return,
Some(Extern::Func(f)) => { Some(Extern::Func(f)) => {
f.call(&[]) f.call(&[])
.expect("initializing the hang limit should not fail"); .expect("initializing the hang limit should not fail");
}
Some(_) => panic!("unexpected hangLimitInitializer export"),
}
}
fn assert_same_export_func_result(
lhs: &Result<Box<[Val]>, Trap>,
rhs: &Result<Box<[Val]>, Trap>,
func_name: &str,
) {
let fail = || {
panic!(
"differential fuzzing failed: exported func {} returned two \
different results: {:?} != {:?}",
func_name, lhs, rhs
)
};
match (lhs, rhs) {
(Err(_), Err(_)) => {}
(Ok(lhs), Ok(rhs)) => {
if lhs.len() != rhs.len() {
fail();
} }
for (lhs, rhs) in lhs.iter().zip(rhs.iter()) { Some(_) => panic!("unexpected hangLimitInitializer export"),
match (lhs, rhs) { }
(Val::I32(lhs), Val::I32(rhs)) if lhs == rhs => continue, }
(Val::I64(lhs), Val::I64(rhs)) if lhs == rhs => continue,
(Val::V128(lhs), Val::V128(rhs)) if lhs == rhs => continue, fn assert_same_export_func_result(
(Val::F32(lhs), Val::F32(rhs)) => { lhs: &Result<Box<[Val]>, Trap>,
let lhs = f32::from_bits(*lhs); rhs: &Result<Box<[Val]>, Trap>,
let rhs = f32::from_bits(*rhs); func_name: &str,
if lhs == rhs || (lhs.is_nan() && rhs.is_nan()) { ) {
continue; let fail = || {
} else { panic!(
fail() "differential fuzzing failed: exported func {} returned two \
different results: {:?} != {:?}",
func_name, lhs, rhs
)
};
match (lhs, rhs) {
(Err(_), Err(_)) => {}
(Ok(lhs), Ok(rhs)) => {
if lhs.len() != rhs.len() {
fail();
}
for (lhs, rhs) in lhs.iter().zip(rhs.iter()) {
match (lhs, rhs) {
(Val::I32(lhs), Val::I32(rhs)) if lhs == rhs => continue,
(Val::I64(lhs), Val::I64(rhs)) if lhs == rhs => continue,
(Val::V128(lhs), Val::V128(rhs)) if lhs == rhs => continue,
(Val::F32(lhs), Val::F32(rhs)) => {
let lhs = f32::from_bits(*lhs);
let rhs = f32::from_bits(*rhs);
if lhs == rhs || (lhs.is_nan() && rhs.is_nan()) {
continue;
} else {
fail()
}
} }
} (Val::F64(lhs), Val::F64(rhs)) => {
(Val::F64(lhs), Val::F64(rhs)) => { let lhs = f64::from_bits(*lhs);
let lhs = f64::from_bits(*lhs); let rhs = f64::from_bits(*rhs);
let rhs = f64::from_bits(*rhs); if lhs == rhs || (lhs.is_nan() && rhs.is_nan()) {
if lhs == rhs || (lhs.is_nan() && rhs.is_nan()) { continue;
continue; } else {
} else { fail()
fail() }
} }
(Val::AnyRef(_), Val::AnyRef(_)) | (Val::FuncRef(_), Val::FuncRef(_)) => {
continue
}
_ => fail(),
} }
(Val::AnyRef(_), Val::AnyRef(_)) | (Val::FuncRef(_), Val::FuncRef(_)) => {
continue
}
_ => fail(),
} }
} }
_ => fail(),
} }
_ => fail(),
} }
} }
/// Invoke the given API calls. /// Invoke the given API calls.
#[cfg(feature = "binaryen")]
pub fn make_api_calls(api: crate::generators::api::ApiCalls) { pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
use crate::generators::api::ApiCall; use crate::generators::api::ApiCall;
use std::collections::HashMap;
crate::init_fuzzing(); crate::init_fuzzing();
@@ -399,7 +403,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
let nth = nth % funcs.len(); let nth = nth % funcs.len();
let f = &funcs[nth]; let f = &funcs[nth];
let ty = f.ty(); let ty = f.ty();
let params = match dummy_values(ty.params()) { let params = match dummy::dummy_values(ty.params()) {
Ok(p) => p, Ok(p) => p,
Err(_) => continue, Err(_) => continue,
}; };

View File

@@ -34,15 +34,21 @@ name = "instantiate_translated"
path = "fuzz_targets/instantiate_translated.rs" path = "fuzz_targets/instantiate_translated.rs"
test = false test = false
doc = false doc = false
required-features = ['binaryen']
[[bin]] [[bin]]
name = "api_calls" name = "api_calls"
path = "fuzz_targets/api_calls.rs" path = "fuzz_targets/api_calls.rs"
test = false test = false
doc = false doc = false
required-features = ['binaryen']
[[bin]] [[bin]]
name = "differential" name = "differential"
path = "fuzz_targets/differential.rs" path = "fuzz_targets/differential.rs"
test = false test = false
doc = false doc = false
required-features = ['binaryen']
[features]
binaryen = ['wasmtime-fuzzing/binaryen']