Skip to content

Wasmtime fuzzbug: i32.shr_u with shift amount 32 produces divergent result under OptLevel::None #12318

@louismerlin

Description

@louismerlin

Description

When running with cranelift_opt_level(OptLevel::None), Wasmtime returns a different value than the WebAssembly spec and other engines for i32.shr_u where the shift amount is 32. In this mode, Wasmtime yields the same result as if the shift amount were taken verbatim, rather than masked to 5 bits.

This bug was found during differential fuzzing of wasmi 1.0.7 against wasmtime 40.0.1 using ziggy (which uses AFL++ and honggfuzz under the hood) instead of libfuzzer.

Expected behavior

The provided example should execute in the same way with wasmi and wasmtime.

Instead we get:

wasmi says Ok(25), but wasmtime says Ok(1)

Cargo.toml

[package]
name = "reproducing_the_bug"
version = "0.1.0"
edition = "2024"

[dependencies]
wasmi = "1.0.7"
wasmtime = "40.0.1"
wat = "1.228.0"

src/main.rs

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let wat = r#"
(module
  (func (export "") (result i32)
    i32.const 24
    i32.const 32
    i32.shr_u
    i32.const 1
    i32.const 0
    i32.shl
    i32.or)
)
    "#;
    let wasm = wat::parse_str(wat)?;

    let wasmi_config = wasmi::Config::default();
    let wasmi_engine = wasmi::Engine::new(&wasmi_config);
    let wasmi_module = wasmi::Module::new(&wasmi_engine, &wasm)?;
    let mut wasmtime_config = wasmtime::Config::new();

    wasmtime_config.cranelift_opt_level(wasmtime::OptLevel::None);

    let wasmtime_engine = wasmtime::Engine::new(&wasmtime_config)?;
    let wasmtime_module = wasmtime::Module::new(&wasmtime_engine, &wasm)?;

    let mut wasmi_store = wasmi::Store::new(&wasmi_engine, ());
    let wasmi_instance = wasmi::Instance::new(&mut wasmi_store, &wasmi_module, &[])?;
    let mut wasmtime_store = wasmtime::Store::new(&wasmtime_engine, ());
    let wasmtime_instance = wasmtime::Instance::new(&mut wasmtime_store, &wasmtime_module, &[])?;

    let wasmi_func = wasmi_instance.get_typed_func::<(), i32>(&wasmi_store, "")?;
    let wasmtime_func = wasmtime_instance.get_typed_func::<(), i32>(&mut wasmtime_store, "")?;
    let args = ();
    println!(
        "wasmi says {:?}, but wasmtime says {:?}",
        wasmi_func.call(&mut wasmi_store, args),
        wasmtime_func.call(&mut wasmtime_store, args),
    );
    Ok(())
}

This example was also tested against wasmer, which agrees with wasmi (result is 25).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIncorrect behavior in the current implementation that needs fixingfuzz-bugBugs found by a fuzzer

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions