Skip to content

Commit

Permalink
review: refactor where configurations are made compatible
Browse files Browse the repository at this point in the history
  • Loading branch information
abrown committed Aug 11, 2022
1 parent 2902c24 commit 833a621
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 53 deletions.
28 changes: 28 additions & 0 deletions crates/fuzzing/src/generators/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,34 @@ impl Config {
self.module_config.config.reference_types_enabled = features.reference_types;
}

/// Force `self` to be a configuration compatible with `other`. This is
/// useful for differential execution to avoid unhelpful fuzz crashes when
/// one engine has a feature enabled and the other does not.
pub fn make_compatible_with(&mut self, other: &Self) {
// Use the same `wasm-smith` configuration as `other` because this is
// used for determining what Wasm features are enabled in the engine
// (see `to_wasmtime`).
self.module_config = other.module_config.clone();

// Use the same allocation strategy between the two configs.
//
// Ideally this wouldn't be necessary, but, during differential
// evaluation, if the `lhs` is using ondemand and the `rhs` is using the
// pooling allocator (or vice versa), then the module may have been
// generated in such a way that is incompatible with the other
// allocation strategy.
//
// We can remove this in the future when it's possible to access the
// fields of `wasm_smith::Module` to constrain the pooling allocator
// based on what was actually generated.
self.wasmtime.strategy = other.wasmtime.strategy.clone();
if let InstanceAllocationStrategy::Pooling { .. } = &other.wasmtime.strategy {
// Also use the same memory configuration when using the pooling
// allocator.
self.wasmtime.memory_config = other.wasmtime.memory_config.clone();
}
}

/// Uses this configuration and the supplied source of data to generate
/// a wasm module.
///
Expand Down
51 changes: 2 additions & 49 deletions crates/fuzzing/src/oracles/diff_wasmtime.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
//! Evaluate an exported Wasm function using Wasmtime.
use super::engine::DiffIgnoreError;
use crate::generators::{self, DiffValue, InstanceAllocationStrategy, ModuleFeatures};
use crate::generators::{self, DiffValue};
use crate::oracles::engine::DiffInstance;
use crate::oracles::{compile_module, engine::DiffEngine, instantiate_with_dummy, StoreLimits};
use anyhow::{Context, Result};
use arbitrary::Unstructured;
use std::hash::Hash;
use std::slice;
use wasmtime::{AsContextMut, Extern, Instance, Store, Val};

/// A wrapper for using Wasmtime as a [`DiffEngine`].
pub struct WasmtimeEngine {
config: generators::Config,
pub(crate) config: generators::Config,
}

impl WasmtimeEngine {
Expand All @@ -25,52 +24,6 @@ impl WasmtimeEngine {
config: config.clone(),
}))
}

/// Create a new Wasmtime engine from a randomly-generated configuration
/// that matches the given Wasm `features`.
pub fn arbitrary_with_features(
u: &mut Unstructured<'_>,
features: &ModuleFeatures,
) -> arbitrary::Result<Box<Self>> {
let mut config: generators::Config = u.arbitrary()?;
config.set_differential_config();
config.set_features(features);
Ok(WasmtimeEngine::new(&config).unwrap())
}

/// Construct a new Wasmtime engine with a randomly-generated configuration
/// that is compatible with `original_engine`.
pub fn arbitrary_with_compatible_config(
u: &mut Unstructured<'_>,
original_engine: &WasmtimeEngine,
) -> Result<Box<Self>> {
let original_config = &original_engine.config;

// Generate a completely new Wasmtime configuration leaving the module
// configuration the same.
let mut new_config = generators::Config {
module_config: original_config.module_config.clone(),
wasmtime: u.arbitrary()?,
};

// Use the same allocation strategy between the two configs.
//
// Ideally this wouldn't be necessary, but if the lhs is using ondemand
// and the rhs is using the pooling allocator (or vice versa), then
// the module may have been generated in such a way that is incompatible
// with the other allocation strategy.
//
// We can remove this in the future when it's possible to access the
// fields of `wasm_smith::Module` to constrain the pooling allocator
// based on what was actually generated.
new_config.wasmtime.strategy = original_config.wasmtime.strategy.clone();
if let InstanceAllocationStrategy::Pooling { .. } = &new_config.wasmtime.strategy {
// Also use the same memory configuration when using the pooling allocator
new_config.wasmtime.memory_config = original_config.wasmtime.memory_config.clone();
}

WasmtimeEngine::new(&new_config)
}
}

impl DiffEngine for WasmtimeEngine {
Expand Down
6 changes: 4 additions & 2 deletions crates/fuzzing/src/oracles/engine.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Define the interface for differential evaluation of Wasm functions.
use crate::generators::{DiffValue, ModuleFeatures};
use crate::generators::{Config, DiffValue, ModuleFeatures};
use crate::oracles::{diff_wasmi::WasmiEngine, diff_wasmtime::WasmtimeEngine};
use arbitrary::Unstructured;
use std::collections::hash_map::DefaultHasher;
Expand All @@ -15,7 +15,9 @@ pub fn choose(
) -> arbitrary::Result<Box<dyn DiffEngine>> {
// Filter out any engines that cannot match the given configuration.
let mut engines: Vec<Box<dyn DiffEngine>> = vec![];
if let Result::Ok(e) = WasmtimeEngine::arbitrary_with_compatible_config(u, wasmtime_engine) {
let mut config: Config = u.arbitrary()?;
config.make_compatible_with(&wasmtime_engine.config);
if let Result::Ok(e) = WasmtimeEngine::new(&config) {
engines.push(e)
}
if let Result::Ok(e) = WasmiEngine::new(features) {
Expand Down
7 changes: 5 additions & 2 deletions fuzz/fuzz_targets/differential_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use libfuzzer_sys::arbitrary::{Result, Unstructured};
use libfuzzer_sys::fuzz_target;
use wasmtime_fuzzing::generators::{DiffValue, SingleInstModule};
use wasmtime_fuzzing::generators::{Config, DiffValue, SingleInstModule};
use wasmtime_fuzzing::oracles::engine::{
get_exported_function_signatures, DiffEngine, DiffIgnorable,
};
Expand Down Expand Up @@ -38,7 +38,10 @@ fn run(data: &[u8]) -> Result<()> {
// registered most recently and they catch failures appropriately. We create
// `rhs` first, however, so we have the option of creating a compatible
// Wasmtime engine (e.g., pooling allocator memory differences).
let rhs = diff_wasmtime::WasmtimeEngine::arbitrary_with_features(&mut u, &features)?;
let mut config: Config = u.arbitrary()?;
config.set_differential_config();
config.set_features(&features);
let rhs = diff_wasmtime::WasmtimeEngine::new(&config).unwrap();

// Choose a left-hand side Wasm engine.
let lhs = engine::choose(&mut u, &features, &rhs)?;
Expand Down

0 comments on commit 833a621

Please sign in to comment.