You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
9.7 KiB

#![no_main]
Refactor fuzzing configuration and sometimes disable debug verifier. (#3664) * fuzz: Refactor Wasmtime's fuzz targets A recent fuzz bug found is related to timing out when compiling a module. This timeout, however, is predominately because Cranelift's debug verifier is enabled and taking up over half the compilation time. I wanted to fix this by disabling the verifier when input modules might have a lot of functions, but this was pretty difficult to implement. Over time we've grown a number of various fuzzers. Most are `wasm-smith`-based at this point but there's various entry points for configuring the wasm-smith module, the wasmtime configuration, etc. I've historically gotten quite lost in trying to change defaults and feeling like I have to touch a lot of different places. This is the motivation for this commit, simplifying fuzzer default configuration. This commit removes the ability to create a default `Config` for fuzzing, instead only supporting generating a configuration via `Arbitrary`. This then involved refactoring all targets and fuzzers to ensure that configuration is generated through `Arbitrary`. This should actually expand the coverage of some existing fuzz targets since `Arbitrary for Config` will tweak options that don't affect runtime, such as memory configuration or jump veneers. All existing fuzz targets are refactored to use this new method of configuration. Some fuzz targets were also shuffled around or reimplemented: * `compile` - this now directly calls `Module::new` to skip all the fuzzing infrastructure. This is mostly done because this fuzz target isn't too interesting and is largely just seeing what happens when things are thrown at the wall for Wasmtime. * `instantiate-maybe-invalid` - this fuzz target now skips instantiation and instead simply goes into `Module::new` like the `compile` target. The rationale behind this is that most modules won't instantiate anyway and this fuzz target is primarily fuzzing the compiler. This skips having to generate arbitrary configuration since wasm-smith-generated-modules (or valid ones at least) aren't used here. * `instantiate` - this fuzz target was removed. In general this fuzz target isn't too interesting in isolation. Almost everything it deals with likely won't pass compilation and is covered by the `compile` fuzz target, and otherwise interesting modules being instantiated can all theoretically be created by `wasm-smith` anyway. * `instantiate-wasm-smith` and `instantiate-swarm` - these were both merged into a new `instantiate` target (replacing the old one from above). There wasn't really much need to keep these separate since they really only differed at this point in methods of timeout. Otherwise we much more heavily use `SwarmConfig` than wasm-smith's built-in options. The intention is that we should still have basically the same coverage of fuzzing as before, if not better because configuration is now possible on some targets. Additionally there is one centralized point of configuration for fuzzing for wasmtime, `Arbitrary for ModuleConfig`. This internally creates an arbitrary `SwarmConfig` from `wasm-smith` and then further tweaks it for Wasmtime's needs, such as enabling various wasm proposals by default. In the future enabling a wasm proposal on fuzzing should largely just be modifying this one trait implementation. * fuzz: Sometimes disable the cranelift debug verifier This commit disables the cranelift debug verifier if the input wasm module might be "large" for the definition of "more than 10 functions". While fuzzing we disable threads (set them to 1) and enable the cranelift debug verifier. Coupled with a 20-30x slowdown this means that a module with the maximum number of functions, 100, gives: 60x / 100 functions / 30x slowdown = 20ms With only 20 milliseconds per function this is even further halved by the `differential` fuzz target compiling a module twice, which means that, when compiling with a normal release mode Wasmtime, if any function takes more than 10ms to compile then it's a candidate for timing out while fuzzing. Given that the cranelift debug verifier can more than double compilation time in fuzzing mode this actually means that the real time budget for function compilation is more like 4ms. The `wasm-smith` crate can pretty easily generate a large function that takes 4ms to compile, and then when that function is multiplied 100x in the `differential` fuzz target we trivially time out the fuzz target. The hope of this commit is to buy back half our budget by disabling the debug verifier for modules that may have many functions. Further refinements can be implemented in the future such as limiting functions for just the differential target as well. * Fix the single-function-module fuzz configuration * Tweak how features work in differential fuzzing * Disable everything for baseline differential fuzzing * Enable selectively for each engine afterwards * Also forcibly enable reference types and bulk memory for spec tests * Log wasms when compiling * Add reference types support to v8 fuzzer * Fix timeouts via fuel The default store has "infinite" fuel so that needs to be consumed before fuel is added back in. * Remove fuzzing-specific tests These no longer compile and also haven't been added to in a long time. Most of the time a reduced form of original the fuzz test case is added when a fuzz bug is fixed.
3 years ago
use libfuzzer_sys::arbitrary::{Result, Unstructured};
use libfuzzer_sys::fuzz_target;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::Once;
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new "meta" differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can't communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows "successful failure" for cases where engines can't support that particular invocation, for example v8 can't support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There's also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
use wasmtime::Trap;
use wasmtime_fuzzing::generators::{Config, DiffValue, DiffValueType, SingleInstModule};
use wasmtime_fuzzing::oracles::diff_wasmtime::WasmtimeInstance;
use wasmtime_fuzzing::oracles::engine::{build_allowed_env_list, parse_env_list};
use wasmtime_fuzzing::oracles::{differential, engine, log_wasm};
// Upper limit on the number of invocations for each WebAssembly function
// executed by this fuzz target.
const NUM_INVOCATIONS: usize = 5;
// Only run once when the fuzz target loads.
static SETUP: Once = Once::new();
// Environment-specified configuration for controlling the kinds of engines and
// modules used by this fuzz target. E.g.:
// - ALLOWED_ENGINES=wasmi,spec cargo +nightly fuzz run ...
// - ALLOWED_ENGINES=-v8 cargo +nightly fuzz run ...
// - ALLOWED_MODULES=single-inst cargo +nightly fuzz run ...
static mut ALLOWED_ENGINES: Vec<&str> = vec![];
static mut ALLOWED_MODULES: Vec<&str> = vec![];
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
// Statistics about what's actually getting executed during fuzzing
static STATS: RuntimeStats = RuntimeStats::new();
Refactor fuzzing configuration and sometimes disable debug verifier. (#3664) * fuzz: Refactor Wasmtime&#39;s fuzz targets A recent fuzz bug found is related to timing out when compiling a module. This timeout, however, is predominately because Cranelift&#39;s debug verifier is enabled and taking up over half the compilation time. I wanted to fix this by disabling the verifier when input modules might have a lot of functions, but this was pretty difficult to implement. Over time we&#39;ve grown a number of various fuzzers. Most are `wasm-smith`-based at this point but there&#39;s various entry points for configuring the wasm-smith module, the wasmtime configuration, etc. I&#39;ve historically gotten quite lost in trying to change defaults and feeling like I have to touch a lot of different places. This is the motivation for this commit, simplifying fuzzer default configuration. This commit removes the ability to create a default `Config` for fuzzing, instead only supporting generating a configuration via `Arbitrary`. This then involved refactoring all targets and fuzzers to ensure that configuration is generated through `Arbitrary`. This should actually expand the coverage of some existing fuzz targets since `Arbitrary for Config` will tweak options that don&#39;t affect runtime, such as memory configuration or jump veneers. All existing fuzz targets are refactored to use this new method of configuration. Some fuzz targets were also shuffled around or reimplemented: * `compile` - this now directly calls `Module::new` to skip all the fuzzing infrastructure. This is mostly done because this fuzz target isn&#39;t too interesting and is largely just seeing what happens when things are thrown at the wall for Wasmtime. * `instantiate-maybe-invalid` - this fuzz target now skips instantiation and instead simply goes into `Module::new` like the `compile` target. The rationale behind this is that most modules won&#39;t instantiate anyway and this fuzz target is primarily fuzzing the compiler. This skips having to generate arbitrary configuration since wasm-smith-generated-modules (or valid ones at least) aren&#39;t used here. * `instantiate` - this fuzz target was removed. In general this fuzz target isn&#39;t too interesting in isolation. Almost everything it deals with likely won&#39;t pass compilation and is covered by the `compile` fuzz target, and otherwise interesting modules being instantiated can all theoretically be created by `wasm-smith` anyway. * `instantiate-wasm-smith` and `instantiate-swarm` - these were both merged into a new `instantiate` target (replacing the old one from above). There wasn&#39;t really much need to keep these separate since they really only differed at this point in methods of timeout. Otherwise we much more heavily use `SwarmConfig` than wasm-smith&#39;s built-in options. The intention is that we should still have basically the same coverage of fuzzing as before, if not better because configuration is now possible on some targets. Additionally there is one centralized point of configuration for fuzzing for wasmtime, `Arbitrary for ModuleConfig`. This internally creates an arbitrary `SwarmConfig` from `wasm-smith` and then further tweaks it for Wasmtime&#39;s needs, such as enabling various wasm proposals by default. In the future enabling a wasm proposal on fuzzing should largely just be modifying this one trait implementation. * fuzz: Sometimes disable the cranelift debug verifier This commit disables the cranelift debug verifier if the input wasm module might be &#34;large&#34; for the definition of &#34;more than 10 functions&#34;. While fuzzing we disable threads (set them to 1) and enable the cranelift debug verifier. Coupled with a 20-30x slowdown this means that a module with the maximum number of functions, 100, gives: 60x / 100 functions / 30x slowdown = 20ms With only 20 milliseconds per function this is even further halved by the `differential` fuzz target compiling a module twice, which means that, when compiling with a normal release mode Wasmtime, if any function takes more than 10ms to compile then it&#39;s a candidate for timing out while fuzzing. Given that the cranelift debug verifier can more than double compilation time in fuzzing mode this actually means that the real time budget for function compilation is more like 4ms. The `wasm-smith` crate can pretty easily generate a large function that takes 4ms to compile, and then when that function is multiplied 100x in the `differential` fuzz target we trivially time out the fuzz target. The hope of this commit is to buy back half our budget by disabling the debug verifier for modules that may have many functions. Further refinements can be implemented in the future such as limiting functions for just the differential target as well. * Fix the single-function-module fuzz configuration * Tweak how features work in differential fuzzing * Disable everything for baseline differential fuzzing * Enable selectively for each engine afterwards * Also forcibly enable reference types and bulk memory for spec tests * Log wasms when compiling * Add reference types support to v8 fuzzer * Fix timeouts via fuel The default store has &#34;infinite&#34; fuel so that needs to be consumed before fuel is added back in. * Remove fuzzing-specific tests These no longer compile and also haven&#39;t been added to in a long time. Most of the time a reduced form of original the fuzz test case is added when a fuzz bug is fixed.
3 years ago
fuzz_target!(|data: &[u8]| {
SETUP.call_once(|| {
// To avoid a uncaught `SIGSEGV` due to signal handlers; see comments on
// `setup_ocaml_runtime`.
engine::setup_engine_runtimes();
// Retrieve the configuration for this fuzz target from `ALLOWED_*`
// environment variables.
let allowed_engines = build_allowed_env_list(
parse_env_list("ALLOWED_ENGINES"),
&["wasmtime", "wasmi", "spec", "v8"],
);
let allowed_modules = build_allowed_env_list(
parse_env_list("ALLOWED_MODULES"),
&["wasm-smith", "single-inst"],
);
unsafe {
ALLOWED_ENGINES = allowed_engines;
ALLOWED_MODULES = allowed_modules;
}
});
// Errors in `run` have to do with not enough input in `data`, which we
Refactor fuzzing configuration and sometimes disable debug verifier. (#3664) * fuzz: Refactor Wasmtime&#39;s fuzz targets A recent fuzz bug found is related to timing out when compiling a module. This timeout, however, is predominately because Cranelift&#39;s debug verifier is enabled and taking up over half the compilation time. I wanted to fix this by disabling the verifier when input modules might have a lot of functions, but this was pretty difficult to implement. Over time we&#39;ve grown a number of various fuzzers. Most are `wasm-smith`-based at this point but there&#39;s various entry points for configuring the wasm-smith module, the wasmtime configuration, etc. I&#39;ve historically gotten quite lost in trying to change defaults and feeling like I have to touch a lot of different places. This is the motivation for this commit, simplifying fuzzer default configuration. This commit removes the ability to create a default `Config` for fuzzing, instead only supporting generating a configuration via `Arbitrary`. This then involved refactoring all targets and fuzzers to ensure that configuration is generated through `Arbitrary`. This should actually expand the coverage of some existing fuzz targets since `Arbitrary for Config` will tweak options that don&#39;t affect runtime, such as memory configuration or jump veneers. All existing fuzz targets are refactored to use this new method of configuration. Some fuzz targets were also shuffled around or reimplemented: * `compile` - this now directly calls `Module::new` to skip all the fuzzing infrastructure. This is mostly done because this fuzz target isn&#39;t too interesting and is largely just seeing what happens when things are thrown at the wall for Wasmtime. * `instantiate-maybe-invalid` - this fuzz target now skips instantiation and instead simply goes into `Module::new` like the `compile` target. The rationale behind this is that most modules won&#39;t instantiate anyway and this fuzz target is primarily fuzzing the compiler. This skips having to generate arbitrary configuration since wasm-smith-generated-modules (or valid ones at least) aren&#39;t used here. * `instantiate` - this fuzz target was removed. In general this fuzz target isn&#39;t too interesting in isolation. Almost everything it deals with likely won&#39;t pass compilation and is covered by the `compile` fuzz target, and otherwise interesting modules being instantiated can all theoretically be created by `wasm-smith` anyway. * `instantiate-wasm-smith` and `instantiate-swarm` - these were both merged into a new `instantiate` target (replacing the old one from above). There wasn&#39;t really much need to keep these separate since they really only differed at this point in methods of timeout. Otherwise we much more heavily use `SwarmConfig` than wasm-smith&#39;s built-in options. The intention is that we should still have basically the same coverage of fuzzing as before, if not better because configuration is now possible on some targets. Additionally there is one centralized point of configuration for fuzzing for wasmtime, `Arbitrary for ModuleConfig`. This internally creates an arbitrary `SwarmConfig` from `wasm-smith` and then further tweaks it for Wasmtime&#39;s needs, such as enabling various wasm proposals by default. In the future enabling a wasm proposal on fuzzing should largely just be modifying this one trait implementation. * fuzz: Sometimes disable the cranelift debug verifier This commit disables the cranelift debug verifier if the input wasm module might be &#34;large&#34; for the definition of &#34;more than 10 functions&#34;. While fuzzing we disable threads (set them to 1) and enable the cranelift debug verifier. Coupled with a 20-30x slowdown this means that a module with the maximum number of functions, 100, gives: 60x / 100 functions / 30x slowdown = 20ms With only 20 milliseconds per function this is even further halved by the `differential` fuzz target compiling a module twice, which means that, when compiling with a normal release mode Wasmtime, if any function takes more than 10ms to compile then it&#39;s a candidate for timing out while fuzzing. Given that the cranelift debug verifier can more than double compilation time in fuzzing mode this actually means that the real time budget for function compilation is more like 4ms. The `wasm-smith` crate can pretty easily generate a large function that takes 4ms to compile, and then when that function is multiplied 100x in the `differential` fuzz target we trivially time out the fuzz target. The hope of this commit is to buy back half our budget by disabling the debug verifier for modules that may have many functions. Further refinements can be implemented in the future such as limiting functions for just the differential target as well. * Fix the single-function-module fuzz configuration * Tweak how features work in differential fuzzing * Disable everything for baseline differential fuzzing * Enable selectively for each engine afterwards * Also forcibly enable reference types and bulk memory for spec tests * Log wasms when compiling * Add reference types support to v8 fuzzer * Fix timeouts via fuel The default store has &#34;infinite&#34; fuel so that needs to be consumed before fuel is added back in. * Remove fuzzing-specific tests These no longer compile and also haven&#39;t been added to in a long time. Most of the time a reduced form of original the fuzz test case is added when a fuzz bug is fixed.
3 years ago
// ignore here since it doesn't affect how we'd like to fuzz.
drop(execute_one(&data));
});
Refactor fuzzing configuration and sometimes disable debug verifier. (#3664) * fuzz: Refactor Wasmtime&#39;s fuzz targets A recent fuzz bug found is related to timing out when compiling a module. This timeout, however, is predominately because Cranelift&#39;s debug verifier is enabled and taking up over half the compilation time. I wanted to fix this by disabling the verifier when input modules might have a lot of functions, but this was pretty difficult to implement. Over time we&#39;ve grown a number of various fuzzers. Most are `wasm-smith`-based at this point but there&#39;s various entry points for configuring the wasm-smith module, the wasmtime configuration, etc. I&#39;ve historically gotten quite lost in trying to change defaults and feeling like I have to touch a lot of different places. This is the motivation for this commit, simplifying fuzzer default configuration. This commit removes the ability to create a default `Config` for fuzzing, instead only supporting generating a configuration via `Arbitrary`. This then involved refactoring all targets and fuzzers to ensure that configuration is generated through `Arbitrary`. This should actually expand the coverage of some existing fuzz targets since `Arbitrary for Config` will tweak options that don&#39;t affect runtime, such as memory configuration or jump veneers. All existing fuzz targets are refactored to use this new method of configuration. Some fuzz targets were also shuffled around or reimplemented: * `compile` - this now directly calls `Module::new` to skip all the fuzzing infrastructure. This is mostly done because this fuzz target isn&#39;t too interesting and is largely just seeing what happens when things are thrown at the wall for Wasmtime. * `instantiate-maybe-invalid` - this fuzz target now skips instantiation and instead simply goes into `Module::new` like the `compile` target. The rationale behind this is that most modules won&#39;t instantiate anyway and this fuzz target is primarily fuzzing the compiler. This skips having to generate arbitrary configuration since wasm-smith-generated-modules (or valid ones at least) aren&#39;t used here. * `instantiate` - this fuzz target was removed. In general this fuzz target isn&#39;t too interesting in isolation. Almost everything it deals with likely won&#39;t pass compilation and is covered by the `compile` fuzz target, and otherwise interesting modules being instantiated can all theoretically be created by `wasm-smith` anyway. * `instantiate-wasm-smith` and `instantiate-swarm` - these were both merged into a new `instantiate` target (replacing the old one from above). There wasn&#39;t really much need to keep these separate since they really only differed at this point in methods of timeout. Otherwise we much more heavily use `SwarmConfig` than wasm-smith&#39;s built-in options. The intention is that we should still have basically the same coverage of fuzzing as before, if not better because configuration is now possible on some targets. Additionally there is one centralized point of configuration for fuzzing for wasmtime, `Arbitrary for ModuleConfig`. This internally creates an arbitrary `SwarmConfig` from `wasm-smith` and then further tweaks it for Wasmtime&#39;s needs, such as enabling various wasm proposals by default. In the future enabling a wasm proposal on fuzzing should largely just be modifying this one trait implementation. * fuzz: Sometimes disable the cranelift debug verifier This commit disables the cranelift debug verifier if the input wasm module might be &#34;large&#34; for the definition of &#34;more than 10 functions&#34;. While fuzzing we disable threads (set them to 1) and enable the cranelift debug verifier. Coupled with a 20-30x slowdown this means that a module with the maximum number of functions, 100, gives: 60x / 100 functions / 30x slowdown = 20ms With only 20 milliseconds per function this is even further halved by the `differential` fuzz target compiling a module twice, which means that, when compiling with a normal release mode Wasmtime, if any function takes more than 10ms to compile then it&#39;s a candidate for timing out while fuzzing. Given that the cranelift debug verifier can more than double compilation time in fuzzing mode this actually means that the real time budget for function compilation is more like 4ms. The `wasm-smith` crate can pretty easily generate a large function that takes 4ms to compile, and then when that function is multiplied 100x in the `differential` fuzz target we trivially time out the fuzz target. The hope of this commit is to buy back half our budget by disabling the debug verifier for modules that may have many functions. Further refinements can be implemented in the future such as limiting functions for just the differential target as well. * Fix the single-function-module fuzz configuration * Tweak how features work in differential fuzzing * Disable everything for baseline differential fuzzing * Enable selectively for each engine afterwards * Also forcibly enable reference types and bulk memory for spec tests * Log wasms when compiling * Add reference types support to v8 fuzzer * Fix timeouts via fuel The default store has &#34;infinite&#34; fuel so that needs to be consumed before fuel is added back in. * Remove fuzzing-specific tests These no longer compile and also haven&#39;t been added to in a long time. Most of the time a reduced form of original the fuzz test case is added when a fuzz bug is fixed.
3 years ago
fn execute_one(data: &[u8]) -> Result<()> {
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
STATS.bump_attempts();
Refactor fuzzing configuration and sometimes disable debug verifier. (#3664) * fuzz: Refactor Wasmtime&#39;s fuzz targets A recent fuzz bug found is related to timing out when compiling a module. This timeout, however, is predominately because Cranelift&#39;s debug verifier is enabled and taking up over half the compilation time. I wanted to fix this by disabling the verifier when input modules might have a lot of functions, but this was pretty difficult to implement. Over time we&#39;ve grown a number of various fuzzers. Most are `wasm-smith`-based at this point but there&#39;s various entry points for configuring the wasm-smith module, the wasmtime configuration, etc. I&#39;ve historically gotten quite lost in trying to change defaults and feeling like I have to touch a lot of different places. This is the motivation for this commit, simplifying fuzzer default configuration. This commit removes the ability to create a default `Config` for fuzzing, instead only supporting generating a configuration via `Arbitrary`. This then involved refactoring all targets and fuzzers to ensure that configuration is generated through `Arbitrary`. This should actually expand the coverage of some existing fuzz targets since `Arbitrary for Config` will tweak options that don&#39;t affect runtime, such as memory configuration or jump veneers. All existing fuzz targets are refactored to use this new method of configuration. Some fuzz targets were also shuffled around or reimplemented: * `compile` - this now directly calls `Module::new` to skip all the fuzzing infrastructure. This is mostly done because this fuzz target isn&#39;t too interesting and is largely just seeing what happens when things are thrown at the wall for Wasmtime. * `instantiate-maybe-invalid` - this fuzz target now skips instantiation and instead simply goes into `Module::new` like the `compile` target. The rationale behind this is that most modules won&#39;t instantiate anyway and this fuzz target is primarily fuzzing the compiler. This skips having to generate arbitrary configuration since wasm-smith-generated-modules (or valid ones at least) aren&#39;t used here. * `instantiate` - this fuzz target was removed. In general this fuzz target isn&#39;t too interesting in isolation. Almost everything it deals with likely won&#39;t pass compilation and is covered by the `compile` fuzz target, and otherwise interesting modules being instantiated can all theoretically be created by `wasm-smith` anyway. * `instantiate-wasm-smith` and `instantiate-swarm` - these were both merged into a new `instantiate` target (replacing the old one from above). There wasn&#39;t really much need to keep these separate since they really only differed at this point in methods of timeout. Otherwise we much more heavily use `SwarmConfig` than wasm-smith&#39;s built-in options. The intention is that we should still have basically the same coverage of fuzzing as before, if not better because configuration is now possible on some targets. Additionally there is one centralized point of configuration for fuzzing for wasmtime, `Arbitrary for ModuleConfig`. This internally creates an arbitrary `SwarmConfig` from `wasm-smith` and then further tweaks it for Wasmtime&#39;s needs, such as enabling various wasm proposals by default. In the future enabling a wasm proposal on fuzzing should largely just be modifying this one trait implementation. * fuzz: Sometimes disable the cranelift debug verifier This commit disables the cranelift debug verifier if the input wasm module might be &#34;large&#34; for the definition of &#34;more than 10 functions&#34;. While fuzzing we disable threads (set them to 1) and enable the cranelift debug verifier. Coupled with a 20-30x slowdown this means that a module with the maximum number of functions, 100, gives: 60x / 100 functions / 30x slowdown = 20ms With only 20 milliseconds per function this is even further halved by the `differential` fuzz target compiling a module twice, which means that, when compiling with a normal release mode Wasmtime, if any function takes more than 10ms to compile then it&#39;s a candidate for timing out while fuzzing. Given that the cranelift debug verifier can more than double compilation time in fuzzing mode this actually means that the real time budget for function compilation is more like 4ms. The `wasm-smith` crate can pretty easily generate a large function that takes 4ms to compile, and then when that function is multiplied 100x in the `differential` fuzz target we trivially time out the fuzz target. The hope of this commit is to buy back half our budget by disabling the debug verifier for modules that may have many functions. Further refinements can be implemented in the future such as limiting functions for just the differential target as well. * Fix the single-function-module fuzz configuration * Tweak how features work in differential fuzzing * Disable everything for baseline differential fuzzing * Enable selectively for each engine afterwards * Also forcibly enable reference types and bulk memory for spec tests * Log wasms when compiling * Add reference types support to v8 fuzzer * Fix timeouts via fuel The default store has &#34;infinite&#34; fuel so that needs to be consumed before fuel is added back in. * Remove fuzzing-specific tests These no longer compile and also haven&#39;t been added to in a long time. Most of the time a reduced form of original the fuzz test case is added when a fuzz bug is fixed.
3 years ago
let mut u = Unstructured::new(data);
// Generate a Wasmtime and module configuration and update its settings
// initially to be suitable for differential execution where the generated
// wasm will behave the same in two different engines. This will get further
// refined below.
let mut config: Config = u.arbitrary()?;
config.set_differential_config();
// Choose an engine that Wasmtime will be differentially executed against.
// The chosen engine is then created, which might update `config`, and
// returned as a trait object.
let lhs = u.choose(unsafe { &ALLOWED_ENGINES })?;
let mut lhs = match engine::build(&mut u, lhs, &mut config)? {
Some(engine) => engine,
// The chosen engine does not have support compiled into the fuzzer,
// discard this test case.
None => return Ok(()),
};
// Using the now-legalized module configuration generate the Wasm module;
// this is specified by either the ALLOWED_MODULES environment variable or a
// random selection between wasm-smith and single-inst.
let build_wasm_smith_module = |u: &mut Unstructured, config: &Config| -> Result<_> {
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
STATS.wasm_smith_modules.fetch_add(1, SeqCst);
let module = config.generate(u, Some(1000))?;
Ok(module.to_bytes())
};
let build_single_inst_module = |u: &mut Unstructured, config: &Config| -> Result<_> {
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
STATS.single_instruction_modules.fetch_add(1, SeqCst);
let module = SingleInstModule::new(u, &config.module_config)?;
Ok(module.to_bytes())
};
if unsafe { ALLOWED_MODULES.is_empty() } {
panic!("unable to generate a module to fuzz against; check `ALLOWED_MODULES`")
}
let wasm = match *u.choose(unsafe { ALLOWED_MODULES.as_slice() })? {
"wasm-smith" => build_wasm_smith_module(&mut u, &config)?,
"single-inst" => build_single_inst_module(&mut u, &config)?,
_ => unreachable!(),
};
log_wasm(&wasm);
// Instantiate the generated wasm file in the chosen differential engine.
let lhs_instance = lhs.instantiate(&wasm);
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
STATS.bump_engine(lhs.name());
// Always use Wasmtime as the second engine to instantiate within.
let rhs_store = config.to_store();
let rhs_module = wasmtime::Module::new(rhs_store.engine(), &wasm).unwrap();
let rhs_instance = WasmtimeInstance::new(rhs_store, rhs_module);
let (mut lhs_instance, mut rhs_instance) = match (lhs_instance, rhs_instance) {
// Both sides successful, continue below to invoking exports.
(Ok(l), Ok(r)) => (l, r),
// Both sides failed, make sure they failed for the same reason but then
// we're done with this fuzz test case.
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
(Err(l), Err(r)) => {
let err = r.downcast::<Trap>().expect("not a trap");
Various improvements to differential fuzzing (#4845) * Improve wasmi differential fuzzer * Support modules with a `start` function * Implement trap-matching to ensure that wasmi and Wasmtime both report the same flavor of trap. * Support differential fuzzing where no engines match Locally I was attempting to run against just one wasm engine with `ALLOWED_ENGINES=wasmi` but the fuzzer quickly panicked because the generated test case didn&#39;t match wasmi&#39;s configuration. This commit updates engine-selection in the differential fuzzer to return `None` if no engine is applicable, throwing out the test case. This won&#39;t be hit at all with oss-fuzz-based runs but for local runs it&#39;ll be useful to have. * Improve proposal support in differential fuzzer * De-prioritize unstable wasm proposals such as multi-memory and memory64 by making them more unlikely with `Unstructured::ratio`. * Allow fuzzing multi-table (reference types) and multi-memory by avoiding setting their maximums to 1 in `set_differential_config`. * Update selection of the pooling strategy to unconditionally support the selected module config rather than the other way around. * Improve handling of traps in differential fuzzing This commit fixes an issue found via local fuzzing where engines were reporting different results but the underlying reason for this was that one engine was hitting stack overflow before the other. To fix the underlying issue I updated the execution to check for stack overflow and, if hit, it discards the entire fuzz test case from then on. The rationale behind this is that each engine can have unique limits for stack overflow. One test case I was looking at for example would stack overflow at less than 1000 frames with epoch interruption enabled but would stack overflow at more than 1000 frames with it disabled. This means that the state after the trap started to diverge and it looked like the engines produced different results. While I was at it I also improved the &#34;function call returned a trap&#34; case to compare traps to make sure the same trap reason popped out. * Fix fuzzer tests
2 years ago
lhs.assert_error_match(&err, &l);
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
return Ok(());
}
// One side succeeded and one side failed, that means a bug happened!
(l, r) => {
panic!(
"failed to instantiate only one side: {:?} != {:?}",
l.err(),
r.err()
)
}
};
// Call each exported function with different sets of arguments.
Various improvements to differential fuzzing (#4845) * Improve wasmi differential fuzzer * Support modules with a `start` function * Implement trap-matching to ensure that wasmi and Wasmtime both report the same flavor of trap. * Support differential fuzzing where no engines match Locally I was attempting to run against just one wasm engine with `ALLOWED_ENGINES=wasmi` but the fuzzer quickly panicked because the generated test case didn&#39;t match wasmi&#39;s configuration. This commit updates engine-selection in the differential fuzzer to return `None` if no engine is applicable, throwing out the test case. This won&#39;t be hit at all with oss-fuzz-based runs but for local runs it&#39;ll be useful to have. * Improve proposal support in differential fuzzer * De-prioritize unstable wasm proposals such as multi-memory and memory64 by making them more unlikely with `Unstructured::ratio`. * Allow fuzzing multi-table (reference types) and multi-memory by avoiding setting their maximums to 1 in `set_differential_config`. * Update selection of the pooling strategy to unconditionally support the selected module config rather than the other way around. * Improve handling of traps in differential fuzzing This commit fixes an issue found via local fuzzing where engines were reporting different results but the underlying reason for this was that one engine was hitting stack overflow before the other. To fix the underlying issue I updated the execution to check for stack overflow and, if hit, it discards the entire fuzz test case from then on. The rationale behind this is that each engine can have unique limits for stack overflow. One test case I was looking at for example would stack overflow at less than 1000 frames with epoch interruption enabled but would stack overflow at more than 1000 frames with it disabled. This means that the state after the trap started to diverge and it looked like the engines produced different results. While I was at it I also improved the &#34;function call returned a trap&#34; case to compare traps to make sure the same trap reason popped out. * Fix fuzzer tests
2 years ago
'outer: for (name, signature) in rhs_instance.exported_functions() {
let mut invocations = 0;
loop {
let arguments = signature
.params()
.map(|t| DiffValue::arbitrary_of_type(&mut u, t.try_into().unwrap()))
.collect::<Result<Vec<_>>>()?;
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
let result_tys = signature
.results()
.map(|t| DiffValueType::try_from(t).unwrap())
.collect::<Vec<_>>();
Various improvements to differential fuzzing (#4845) * Improve wasmi differential fuzzer * Support modules with a `start` function * Implement trap-matching to ensure that wasmi and Wasmtime both report the same flavor of trap. * Support differential fuzzing where no engines match Locally I was attempting to run against just one wasm engine with `ALLOWED_ENGINES=wasmi` but the fuzzer quickly panicked because the generated test case didn&#39;t match wasmi&#39;s configuration. This commit updates engine-selection in the differential fuzzer to return `None` if no engine is applicable, throwing out the test case. This won&#39;t be hit at all with oss-fuzz-based runs but for local runs it&#39;ll be useful to have. * Improve proposal support in differential fuzzer * De-prioritize unstable wasm proposals such as multi-memory and memory64 by making them more unlikely with `Unstructured::ratio`. * Allow fuzzing multi-table (reference types) and multi-memory by avoiding setting their maximums to 1 in `set_differential_config`. * Update selection of the pooling strategy to unconditionally support the selected module config rather than the other way around. * Improve handling of traps in differential fuzzing This commit fixes an issue found via local fuzzing where engines were reporting different results but the underlying reason for this was that one engine was hitting stack overflow before the other. To fix the underlying issue I updated the execution to check for stack overflow and, if hit, it discards the entire fuzz test case from then on. The rationale behind this is that each engine can have unique limits for stack overflow. One test case I was looking at for example would stack overflow at less than 1000 frames with epoch interruption enabled but would stack overflow at more than 1000 frames with it disabled. This means that the state after the trap started to diverge and it looked like the engines produced different results. While I was at it I also improved the &#34;function call returned a trap&#34; case to compare traps to make sure the same trap reason popped out. * Fix fuzzer tests
2 years ago
let ok = differential(
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
lhs_instance.as_mut(),
Various improvements to differential fuzzing (#4845) * Improve wasmi differential fuzzer * Support modules with a `start` function * Implement trap-matching to ensure that wasmi and Wasmtime both report the same flavor of trap. * Support differential fuzzing where no engines match Locally I was attempting to run against just one wasm engine with `ALLOWED_ENGINES=wasmi` but the fuzzer quickly panicked because the generated test case didn&#39;t match wasmi&#39;s configuration. This commit updates engine-selection in the differential fuzzer to return `None` if no engine is applicable, throwing out the test case. This won&#39;t be hit at all with oss-fuzz-based runs but for local runs it&#39;ll be useful to have. * Improve proposal support in differential fuzzer * De-prioritize unstable wasm proposals such as multi-memory and memory64 by making them more unlikely with `Unstructured::ratio`. * Allow fuzzing multi-table (reference types) and multi-memory by avoiding setting their maximums to 1 in `set_differential_config`. * Update selection of the pooling strategy to unconditionally support the selected module config rather than the other way around. * Improve handling of traps in differential fuzzing This commit fixes an issue found via local fuzzing where engines were reporting different results but the underlying reason for this was that one engine was hitting stack overflow before the other. To fix the underlying issue I updated the execution to check for stack overflow and, if hit, it discards the entire fuzz test case from then on. The rationale behind this is that each engine can have unique limits for stack overflow. One test case I was looking at for example would stack overflow at less than 1000 frames with epoch interruption enabled but would stack overflow at more than 1000 frames with it disabled. This means that the state after the trap started to diverge and it looked like the engines produced different results. While I was at it I also improved the &#34;function call returned a trap&#34; case to compare traps to make sure the same trap reason popped out. * Fix fuzzer tests
2 years ago
lhs.as_ref(),
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
&mut rhs_instance,
&name,
&arguments,
&result_tys,
)
.expect("failed to run differential evaluation");
Refactor fuzzing configuration and sometimes disable debug verifier. (#3664) * fuzz: Refactor Wasmtime&#39;s fuzz targets A recent fuzz bug found is related to timing out when compiling a module. This timeout, however, is predominately because Cranelift&#39;s debug verifier is enabled and taking up over half the compilation time. I wanted to fix this by disabling the verifier when input modules might have a lot of functions, but this was pretty difficult to implement. Over time we&#39;ve grown a number of various fuzzers. Most are `wasm-smith`-based at this point but there&#39;s various entry points for configuring the wasm-smith module, the wasmtime configuration, etc. I&#39;ve historically gotten quite lost in trying to change defaults and feeling like I have to touch a lot of different places. This is the motivation for this commit, simplifying fuzzer default configuration. This commit removes the ability to create a default `Config` for fuzzing, instead only supporting generating a configuration via `Arbitrary`. This then involved refactoring all targets and fuzzers to ensure that configuration is generated through `Arbitrary`. This should actually expand the coverage of some existing fuzz targets since `Arbitrary for Config` will tweak options that don&#39;t affect runtime, such as memory configuration or jump veneers. All existing fuzz targets are refactored to use this new method of configuration. Some fuzz targets were also shuffled around or reimplemented: * `compile` - this now directly calls `Module::new` to skip all the fuzzing infrastructure. This is mostly done because this fuzz target isn&#39;t too interesting and is largely just seeing what happens when things are thrown at the wall for Wasmtime. * `instantiate-maybe-invalid` - this fuzz target now skips instantiation and instead simply goes into `Module::new` like the `compile` target. The rationale behind this is that most modules won&#39;t instantiate anyway and this fuzz target is primarily fuzzing the compiler. This skips having to generate arbitrary configuration since wasm-smith-generated-modules (or valid ones at least) aren&#39;t used here. * `instantiate` - this fuzz target was removed. In general this fuzz target isn&#39;t too interesting in isolation. Almost everything it deals with likely won&#39;t pass compilation and is covered by the `compile` fuzz target, and otherwise interesting modules being instantiated can all theoretically be created by `wasm-smith` anyway. * `instantiate-wasm-smith` and `instantiate-swarm` - these were both merged into a new `instantiate` target (replacing the old one from above). There wasn&#39;t really much need to keep these separate since they really only differed at this point in methods of timeout. Otherwise we much more heavily use `SwarmConfig` than wasm-smith&#39;s built-in options. The intention is that we should still have basically the same coverage of fuzzing as before, if not better because configuration is now possible on some targets. Additionally there is one centralized point of configuration for fuzzing for wasmtime, `Arbitrary for ModuleConfig`. This internally creates an arbitrary `SwarmConfig` from `wasm-smith` and then further tweaks it for Wasmtime&#39;s needs, such as enabling various wasm proposals by default. In the future enabling a wasm proposal on fuzzing should largely just be modifying this one trait implementation. * fuzz: Sometimes disable the cranelift debug verifier This commit disables the cranelift debug verifier if the input wasm module might be &#34;large&#34; for the definition of &#34;more than 10 functions&#34;. While fuzzing we disable threads (set them to 1) and enable the cranelift debug verifier. Coupled with a 20-30x slowdown this means that a module with the maximum number of functions, 100, gives: 60x / 100 functions / 30x slowdown = 20ms With only 20 milliseconds per function this is even further halved by the `differential` fuzz target compiling a module twice, which means that, when compiling with a normal release mode Wasmtime, if any function takes more than 10ms to compile then it&#39;s a candidate for timing out while fuzzing. Given that the cranelift debug verifier can more than double compilation time in fuzzing mode this actually means that the real time budget for function compilation is more like 4ms. The `wasm-smith` crate can pretty easily generate a large function that takes 4ms to compile, and then when that function is multiplied 100x in the `differential` fuzz target we trivially time out the fuzz target. The hope of this commit is to buy back half our budget by disabling the debug verifier for modules that may have many functions. Further refinements can be implemented in the future such as limiting functions for just the differential target as well. * Fix the single-function-module fuzz configuration * Tweak how features work in differential fuzzing * Disable everything for baseline differential fuzzing * Enable selectively for each engine afterwards * Also forcibly enable reference types and bulk memory for spec tests * Log wasms when compiling * Add reference types support to v8 fuzzer * Fix timeouts via fuel The default store has &#34;infinite&#34; fuel so that needs to be consumed before fuel is added back in. * Remove fuzzing-specific tests These no longer compile and also haven&#39;t been added to in a long time. Most of the time a reduced form of original the fuzz test case is added when a fuzz bug is fixed.
3 years ago
Various improvements to differential fuzzing (#4845) * Improve wasmi differential fuzzer * Support modules with a `start` function * Implement trap-matching to ensure that wasmi and Wasmtime both report the same flavor of trap. * Support differential fuzzing where no engines match Locally I was attempting to run against just one wasm engine with `ALLOWED_ENGINES=wasmi` but the fuzzer quickly panicked because the generated test case didn&#39;t match wasmi&#39;s configuration. This commit updates engine-selection in the differential fuzzer to return `None` if no engine is applicable, throwing out the test case. This won&#39;t be hit at all with oss-fuzz-based runs but for local runs it&#39;ll be useful to have. * Improve proposal support in differential fuzzer * De-prioritize unstable wasm proposals such as multi-memory and memory64 by making them more unlikely with `Unstructured::ratio`. * Allow fuzzing multi-table (reference types) and multi-memory by avoiding setting their maximums to 1 in `set_differential_config`. * Update selection of the pooling strategy to unconditionally support the selected module config rather than the other way around. * Improve handling of traps in differential fuzzing This commit fixes an issue found via local fuzzing where engines were reporting different results but the underlying reason for this was that one engine was hitting stack overflow before the other. To fix the underlying issue I updated the execution to check for stack overflow and, if hit, it discards the entire fuzz test case from then on. The rationale behind this is that each engine can have unique limits for stack overflow. One test case I was looking at for example would stack overflow at less than 1000 frames with epoch interruption enabled but would stack overflow at more than 1000 frames with it disabled. This means that the state after the trap started to diverge and it looked like the engines produced different results. While I was at it I also improved the &#34;function call returned a trap&#34; case to compare traps to make sure the same trap reason popped out. * Fix fuzzer tests
2 years ago
invocations += 1;
STATS.total_invocations.fetch_add(1, SeqCst);
// If this differential execution has resulted in the two instances
// diverging in state we can't keep executing so don't execute any
// more functions.
if !ok {
break 'outer;
}
// We evaluate the same function with different arguments until we
// Hit a predetermined limit or we run out of unstructured data--it
// does not make sense to re-evaluate the same arguments over and
// over.
if invocations > NUM_INVOCATIONS || u.is_empty() {
break;
}
}
}
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
STATS.successes.fetch_add(1, SeqCst);
Refactor fuzzing configuration and sometimes disable debug verifier. (#3664) * fuzz: Refactor Wasmtime&#39;s fuzz targets A recent fuzz bug found is related to timing out when compiling a module. This timeout, however, is predominately because Cranelift&#39;s debug verifier is enabled and taking up over half the compilation time. I wanted to fix this by disabling the verifier when input modules might have a lot of functions, but this was pretty difficult to implement. Over time we&#39;ve grown a number of various fuzzers. Most are `wasm-smith`-based at this point but there&#39;s various entry points for configuring the wasm-smith module, the wasmtime configuration, etc. I&#39;ve historically gotten quite lost in trying to change defaults and feeling like I have to touch a lot of different places. This is the motivation for this commit, simplifying fuzzer default configuration. This commit removes the ability to create a default `Config` for fuzzing, instead only supporting generating a configuration via `Arbitrary`. This then involved refactoring all targets and fuzzers to ensure that configuration is generated through `Arbitrary`. This should actually expand the coverage of some existing fuzz targets since `Arbitrary for Config` will tweak options that don&#39;t affect runtime, such as memory configuration or jump veneers. All existing fuzz targets are refactored to use this new method of configuration. Some fuzz targets were also shuffled around or reimplemented: * `compile` - this now directly calls `Module::new` to skip all the fuzzing infrastructure. This is mostly done because this fuzz target isn&#39;t too interesting and is largely just seeing what happens when things are thrown at the wall for Wasmtime. * `instantiate-maybe-invalid` - this fuzz target now skips instantiation and instead simply goes into `Module::new` like the `compile` target. The rationale behind this is that most modules won&#39;t instantiate anyway and this fuzz target is primarily fuzzing the compiler. This skips having to generate arbitrary configuration since wasm-smith-generated-modules (or valid ones at least) aren&#39;t used here. * `instantiate` - this fuzz target was removed. In general this fuzz target isn&#39;t too interesting in isolation. Almost everything it deals with likely won&#39;t pass compilation and is covered by the `compile` fuzz target, and otherwise interesting modules being instantiated can all theoretically be created by `wasm-smith` anyway. * `instantiate-wasm-smith` and `instantiate-swarm` - these were both merged into a new `instantiate` target (replacing the old one from above). There wasn&#39;t really much need to keep these separate since they really only differed at this point in methods of timeout. Otherwise we much more heavily use `SwarmConfig` than wasm-smith&#39;s built-in options. The intention is that we should still have basically the same coverage of fuzzing as before, if not better because configuration is now possible on some targets. Additionally there is one centralized point of configuration for fuzzing for wasmtime, `Arbitrary for ModuleConfig`. This internally creates an arbitrary `SwarmConfig` from `wasm-smith` and then further tweaks it for Wasmtime&#39;s needs, such as enabling various wasm proposals by default. In the future enabling a wasm proposal on fuzzing should largely just be modifying this one trait implementation. * fuzz: Sometimes disable the cranelift debug verifier This commit disables the cranelift debug verifier if the input wasm module might be &#34;large&#34; for the definition of &#34;more than 10 functions&#34;. While fuzzing we disable threads (set them to 1) and enable the cranelift debug verifier. Coupled with a 20-30x slowdown this means that a module with the maximum number of functions, 100, gives: 60x / 100 functions / 30x slowdown = 20ms With only 20 milliseconds per function this is even further halved by the `differential` fuzz target compiling a module twice, which means that, when compiling with a normal release mode Wasmtime, if any function takes more than 10ms to compile then it&#39;s a candidate for timing out while fuzzing. Given that the cranelift debug verifier can more than double compilation time in fuzzing mode this actually means that the real time budget for function compilation is more like 4ms. The `wasm-smith` crate can pretty easily generate a large function that takes 4ms to compile, and then when that function is multiplied 100x in the `differential` fuzz target we trivially time out the fuzz target. The hope of this commit is to buy back half our budget by disabling the debug verifier for modules that may have many functions. Further refinements can be implemented in the future such as limiting functions for just the differential target as well. * Fix the single-function-module fuzz configuration * Tweak how features work in differential fuzzing * Disable everything for baseline differential fuzzing * Enable selectively for each engine afterwards * Also forcibly enable reference types and bulk memory for spec tests * Log wasms when compiling * Add reference types support to v8 fuzzer * Fix timeouts via fuel The default store has &#34;infinite&#34; fuel so that needs to be consumed before fuel is added back in. * Remove fuzzing-specific tests These no longer compile and also haven&#39;t been added to in a long time. Most of the time a reduced form of original the fuzz test case is added when a fuzz bug is fixed.
3 years ago
Ok(())
}
Port v8 fuzzer to the new framework (#4739) * Port v8 fuzzer to the new framework This commit aims to improve the support for the new &#34;meta&#34; differential fuzzer added in #4515 by ensuring that all existing differential fuzzing is migrated to this new fuzzer. This PR includes features such as: * The V8 differential execution is migrated to the new framework. * `Config::set_differential_config` no longer force-disables wasm features, instead allowing them to be enabled as per the fuzz input. * `DiffInstance::{hash, hash}` was replaced with `DiffInstance::get_{memory,global}` to allow more fine-grained assertions. * Support for `FuncRef` and `ExternRef` have been added to `DiffValue` and `DiffValueType`. For now though generating an arbitrary `ExternRef` and `FuncRef` simply generates a null value. * Arbitrary `DiffValue::{F32,F64}` values are guaranteed to use canonical NaN representations to fix an issue with v8 where with the v8 engine we can&#39;t communicate non-canonical NaN values through JS. * `DiffEngine::evaluate` allows &#34;successful failure&#34; for cases where engines can&#39;t support that particular invocation, for example v8 can&#39;t support `v128` arguments or return values. * Smoke tests were added for each engine to ensure that a simple wasm module works at PR-time. * Statistics printed from the main fuzzer now include percentage-rates for chosen engines as well as percentage rates for styles-of-module. There&#39;s also a few small refactorings here and there but mostly just things I saw along the way. * Update the fuzzing README
2 years ago
#[derive(Default)]
struct RuntimeStats {
/// Total number of fuzz inputs processed
attempts: AtomicUsize,
/// Number of times we've invoked engines
total_invocations: AtomicUsize,
/// Number of times a fuzz input finished all the way to the end without any
/// sort of error (including `Arbitrary` errors)
successes: AtomicUsize,
// Counters for which engine was chosen
wasmi: AtomicUsize,
v8: AtomicUsize,
spec: AtomicUsize,
wasmtime: AtomicUsize,
// Counters for which style of module is chosen
wasm_smith_modules: AtomicUsize,
single_instruction_modules: AtomicUsize,
}
impl RuntimeStats {
const fn new() -> RuntimeStats {
RuntimeStats {
attempts: AtomicUsize::new(0),
total_invocations: AtomicUsize::new(0),
successes: AtomicUsize::new(0),
wasmi: AtomicUsize::new(0),
v8: AtomicUsize::new(0),
spec: AtomicUsize::new(0),
wasmtime: AtomicUsize::new(0),
wasm_smith_modules: AtomicUsize::new(0),
single_instruction_modules: AtomicUsize::new(0),
}
}
fn bump_attempts(&self) {
let attempts = self.attempts.fetch_add(1, SeqCst);
if attempts == 0 || attempts % 1_000 != 0 {
return;
}
let successes = self.successes.load(SeqCst);
println!(
"=== Execution rate ({} successes / {} attempted modules): {:.02}% ===",
successes,
attempts,
successes as f64 / attempts as f64 * 100f64,
);
let v8 = self.v8.load(SeqCst);
let spec = self.spec.load(SeqCst);
let wasmi = self.wasmi.load(SeqCst);
let wasmtime = self.wasmtime.load(SeqCst);
let total = v8 + spec + wasmi + wasmtime;
println!(
"\twasmi: {:.02}%, spec: {:.02}%, wasmtime: {:.02}%, v8: {:.02}%",
wasmi as f64 / total as f64 * 100f64,
spec as f64 / total as f64 * 100f64,
wasmtime as f64 / total as f64 * 100f64,
v8 as f64 / total as f64 * 100f64,
);
let wasm_smith = self.wasm_smith_modules.load(SeqCst);
let single_inst = self.single_instruction_modules.load(SeqCst);
let total = wasm_smith + single_inst;
println!(
"\twasm-smith: {:.02}%, single-inst: {:.02}%",
wasm_smith as f64 / total as f64 * 100f64,
single_inst as f64 / total as f64 * 100f64,
);
}
fn bump_engine(&self, name: &str) {
match name {
"wasmi" => self.wasmi.fetch_add(1, SeqCst),
"wasmtime" => self.wasmtime.fetch_add(1, SeqCst),
"spec" => self.spec.fetch_add(1, SeqCst),
"v8" => self.v8.fetch_add(1, SeqCst),
_ => return,
};
}
}