Skip to content

Commit

Permalink
Update the Wasmi fuzzing oracle to version 0.31.0 (#7791)
Browse files Browse the repository at this point in the history
* update Wasmi fuzzing oracle to version 0.31.0

This allows us to enable the bulk-memory, reference-types and tail-call Wasm proposals for the Wasmi fuzzing oracle.

* apply rustfmt

* be more explicit about supported Wasm features

* align Wasmi config to input config

I am not sure if this is how it is intended to be used. Please review and provide feedback.

* remove duplicate threads_enabled

* remove min and max tables

We can do this since Wasmi supports reference-types Wasm proposal.

* add comment about config mutation

* use Wasmi v0.31.1

* be more explicit about supported Wasm features

* add comment about config mutation

* update wasmi_arena to v0.4.1
  • Loading branch information
Robbepop authored Jan 24, 2024
1 parent 5c5640f commit 5f6288f
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 37 deletions.
18 changes: 10 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/fuzzing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ wasm-encoder = { workspace = true }
wasm-smith = { workspace = true }
wasm-mutate = { workspace = true }
wasm-spec-interpreter = { path = "./wasm-spec-interpreter", optional = true }
wasmi = "0.20.0"
wasmi = "0.31.1"

# We rely on precompiled v8 binaries, but rusty-v8 doesn't have a precompiled
# binary for MinGW which is built on our CI. It does have one for Windows-msvc,
Expand Down
80 changes: 52 additions & 28 deletions crates/fuzzing/src/oracles/diff_wasmi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,29 @@ pub struct WasmiEngine {
impl WasmiEngine {
pub(crate) fn new(config: &mut Config) -> Self {
let config = &mut config.module_config.config;
config.reference_types_enabled = false;
// Force generated Wasm modules to never have features that Wasmi doesn't support.
config.simd_enabled = false;
config.relaxed_simd_enabled = false;
config.memory64_enabled = false;
config.bulk_memory_enabled = false;
config.threads_enabled = false;
config.exceptions_enabled = false;
config.max_memories = config.max_memories.min(1);
config.min_memories = config.min_memories.min(1);
config.max_tables = config.max_tables.min(1);
config.min_tables = config.min_tables.min(1);

let mut wasmi_config = wasmi::Config::default();
wasmi_config
.consume_fuel(false)
.floats(true)
.wasm_mutable_global(true)
.wasm_sign_extension(config.sign_extension_ops_enabled)
.wasm_saturating_float_to_int(config.saturating_float_to_int_enabled)
.wasm_multi_value(config.multi_value_enabled)
.wasm_bulk_memory(config.bulk_memory_enabled)
.wasm_reference_types(config.reference_types_enabled)
.wasm_tail_call(config.tail_call_enabled)
.wasm_extended_const(true);
Self {
engine: wasmi::Engine::default(),
engine: wasmi::Engine::new(&wasmi_config),
}
}
}
Expand All @@ -38,7 +49,7 @@ impl DiffEngine for WasmiEngine {
let module =
wasmi::Module::new(&self.engine, wasm).context("unable to validate Wasm module")?;
let mut store = wasmi::Store::new(&self.engine, ());
let instance = wasmi::Linker::<()>::new()
let instance = wasmi::Linker::<()>::new(&self.engine)
.instantiate(&mut store, &module)
.and_then(|i| i.start(&mut store))
.context("unable to instantiate module in wasmi")?;
Expand Down Expand Up @@ -76,8 +87,11 @@ impl DiffEngine for WasmiEngine {
.downcast_ref::<wasmi::core::Trap>()
.expect(&format!("not a trap: {:?}", err)),
};
assert!(wasmi.as_code().is_some());
assert_eq!(wasmi_to_wasmtime_trap_code(wasmi.as_code().unwrap()), *trap);
assert!(wasmi.trap_code().is_some());
assert_eq!(
wasmi_to_wasmtime_trap_code(wasmi.trap_code().unwrap()),
*trap
);
}

fn is_stack_overflow(&self, err: &Error) -> bool {
Expand All @@ -89,23 +103,25 @@ impl DiffEngine for WasmiEngine {
None => return false,
},
};
matches!(trap.as_code(), Some(wasmi::core::TrapCode::StackOverflow))
matches!(trap.trap_code(), Some(wasmi::core::TrapCode::StackOverflow))
}
}

/// Converts `wasmi` trap code to `wasmtime` trap code.
fn wasmi_to_wasmtime_trap_code(trap: wasmi::core::TrapCode) -> Trap {
use wasmi::core::TrapCode;
match trap {
TrapCode::Unreachable => Trap::UnreachableCodeReached,
TrapCode::MemoryAccessOutOfBounds => Trap::MemoryOutOfBounds,
TrapCode::TableAccessOutOfBounds => Trap::TableOutOfBounds,
TrapCode::ElemUninitialized => Trap::IndirectCallToNull,
TrapCode::DivisionByZero => Trap::IntegerDivisionByZero,
TrapCode::UnreachableCodeReached => Trap::UnreachableCodeReached,
TrapCode::MemoryOutOfBounds => Trap::MemoryOutOfBounds,
TrapCode::TableOutOfBounds => Trap::TableOutOfBounds,
TrapCode::IndirectCallToNull => Trap::IndirectCallToNull,
TrapCode::IntegerDivisionByZero => Trap::IntegerDivisionByZero,
TrapCode::IntegerOverflow => Trap::IntegerOverflow,
TrapCode::InvalidConversionToInt => Trap::BadConversionToInteger,
TrapCode::BadConversionToInteger => Trap::BadConversionToInteger,
TrapCode::StackOverflow => Trap::StackOverflow,
TrapCode::UnexpectedSignature => Trap::BadSignature,
TrapCode::BadSignature => Trap::BadSignature,
TrapCode::OutOfFuel => unimplemented!("built-in fuel metering is unused"),
TrapCode::GrowthOperationLimited => unimplemented!("resource limiter is unused"),
}
}

Expand All @@ -132,7 +148,7 @@ impl DiffInstance for WasmiInstance {
.and_then(wasmi::Extern::into_func)
.unwrap();
let arguments: Vec<_> = arguments.iter().map(|x| x.into()).collect();
let mut results = vec![wasmi::core::Value::I32(0); result_tys.len()];
let mut results = vec![wasmi::Value::I32(0); result_tys.len()];
function
.call(&mut self.store, &arguments, &mut results)
.context("wasmi function trap")?;
Expand Down Expand Up @@ -165,29 +181,37 @@ impl DiffInstance for WasmiInstance {
}
}

impl From<&DiffValue> for wasmi::core::Value {
impl From<&DiffValue> for wasmi::Value {
fn from(v: &DiffValue) -> Self {
use wasmi::core::Value::*;
use wasmi::Value as WasmiValue;
match *v {
DiffValue::I32(n) => I32(n),
DiffValue::I64(n) => I64(n),
DiffValue::F32(n) => F32(wasmi::core::F32::from_bits(n)),
DiffValue::F64(n) => F64(wasmi::core::F64::from_bits(n)),
DiffValue::V128(_) | DiffValue::FuncRef { .. } | DiffValue::ExternRef { .. } => {
unimplemented!()
DiffValue::I32(n) => WasmiValue::I32(n),
DiffValue::I64(n) => WasmiValue::I64(n),
DiffValue::F32(n) => WasmiValue::F32(wasmi::core::F32::from_bits(n)),
DiffValue::F64(n) => WasmiValue::F64(wasmi::core::F64::from_bits(n)),
DiffValue::V128(_) => unimplemented!(),
DiffValue::FuncRef { null } => {
assert!(null);
WasmiValue::FuncRef(wasmi::FuncRef::null())
}
DiffValue::ExternRef { null } => {
assert!(null);
WasmiValue::ExternRef(wasmi::ExternRef::null())
}
}
}
}

impl From<wasmi::core::Value> for DiffValue {
fn from(value: wasmi::core::Value) -> Self {
use wasmi::core::Value as WasmiValue;
impl From<wasmi::Value> for DiffValue {
fn from(value: wasmi::Value) -> Self {
use wasmi::Value as WasmiValue;
match value {
WasmiValue::I32(n) => DiffValue::I32(n),
WasmiValue::I64(n) => DiffValue::I64(n),
WasmiValue::F32(n) => DiffValue::F32(n.to_bits()),
WasmiValue::F64(n) => DiffValue::F64(n.to_bits()),
WasmiValue::FuncRef(f) => DiffValue::FuncRef { null: f.is_null() },
WasmiValue::ExternRef(e) => DiffValue::ExternRef { null: e.is_null() },
}
}
}
Expand Down

0 comments on commit 5f6288f

Please sign in to comment.