Stream: git-wasmtime

Topic: wasmtime / issue #11753 GC-related panic and hangs


view this post on Zulip Wasmtime GitHub notifications bot (Sep 29 2025 at 11:51):

id-ilych opened issue #11753:

Test Case

The form does not allow WASM attachments, so here is the link
https://github.com/id-ilych/wasmtime-bugreport/raw/3eddc3cab6fa/host/guest.wasm

The host code

use std::error::Error;
use wasmtime::*;

fn main() -> Result<(), Box<dyn Error>> {
    let arg_a = std::env::args().nth(1).unwrap().parse()?;
    let arg_b = std::env::args().nth(2).unwrap().parse()?;
    let arg_x = std::env::args().nth(3).unwrap().parse()?;
    let arg_y = std::env::args().nth(4).unwrap().parse()?;
    let arg_z = std::env::args().nth(5).unwrap().parse()?;

    let engine = Engine::new(Config::default()
        .gc_support(true)
        .wasm_gc(true)
        .wasm_exceptions(true)
        .wasm_reference_types(true)
        .wasm_function_references(true)
        .allocation_strategy(PoolingAllocationConfig::new()
            .max_memory_size(1_000_000)
            .to_owned()
        )
    )?;

    let module = Module::from_file(&engine, "guest.wasm")?;
    let mut linker = Linker::new(&engine);
    linker.func_wrap("wasi_snapshot_preview1", "random_get", |_: i32, _: i32| -> i32 { return 5 })?; // Errno::Io

    let instantiate = || -> Result<(Store<()>, TypedFunc<(i32, i32, i32, i32), i32>)> {
        let mut store = Store::new(&engine, ());
        let instance = linker.instantiate(&mut store, &module)?;

        let initialize = instance.get_typed_func::<(), ()>(&mut store, "_initialize")?;
        initialize.call(&mut store, ())?;

        let func = instance.get_typed_func(&mut store, "memtest")?;

        Ok((store, func))
    };

    let (mut store_a, func_a) = instantiate()?;
    let (mut store_b, func_b) = instantiate()?;

    for i in 0..100 {
        println!("{}", i);
        if arg_a > 0 {
            let _:i32 = func_a.call(&mut store_a, (arg_a, arg_x, arg_y, arg_z))?;
        }
        if arg_b > 0 {
            let _: i32 = func_b.call(&mut store_b, (arg_b, arg_x, arg_y, arg_z))?;
        }
    }

    Ok(())
}

You can find the whole project (including original Kotlin code for the guest) here:
https://github.com/id-ilych/wasmtime-bugreport/tree/3eddc3cab6fa

Steps to Reproduce

:warning: Each command listed here fails (or hangs), particular panics for each case are listed in Actual Results section

  1. RUST_BACKTRACE=1 cargo run --release 10000 7500 1 1 1
  2. RUST_BACKTRACE=1 cargo run --release 10000 11000 1 1 1
  3. RUST_BACKTRACE=1 cargo run 10000 7500 1 1 1
  4. RUST_BACKTRACE=1 cargo run 10000 11000 1 1 1
  5. RUST_BACKTRACE=1 cargo run --release 10000 7500 3 2 1
  6. RUST_BACKTRACE=1 cargo run --release 22000 0 1 2 3
  7. RUST_BACKTRACE=1 cargo run --release 12025 17812 5 5 5
  8. RUST_BACKTRACE=1 cargo run --release 15202 17813 2 1 1

Expected Results

Program finishes successfully (prints numbers from 0 to 99 (incl))

Actual Results

Command 1 produces "Option::unwrap() on a None value" panic in wasmtime-37.0.1/src/runtime/vm/gc/gc_runtime.rs:463:44

Command 2 produces "range start index 6553700 out of range for slice of length 524288" panic in wasmtime-37.0.1/src/runtime/vm/gc/gc_runtime.rs:466:47

Commands 3 and 4 each cause self.is_in_over_approximated_stack_roots() assertion failure in wasmtime-37.0.1/src/runtime/vm/gc/enabled/drc.rs:596:9

Command 5 hands after printing "5" (meaning that first 5 iterations completed successfully, but on i=5 it hanged)

Command 6 gives zsh: bus error RUST_BACKTRACE=1 cargo run --release 22000 0 1 2 3 (might be un-aligned memory access)

Command 7 produces "Option::unwrap() on a None value" panic in wasmtime-environ-37.0.1/src/types.rs:1160:25

Command 8 produces ""should have inserted trace info for every GC type allocated in this heap" panic in wasmtime-37.0.1/src/runtime/vm/gc/enabled/drc.rs:317:14

Versions and Environment

Wasmtime version or commit: 37.0.1

Operating system: macOS 15.6.1 (build 24G90)

Architecture: arm64e (Apple M2 Max)

Extra Info

Anything else you'd like to add?

view this post on Zulip Wasmtime GitHub notifications bot (Sep 29 2025 at 11:51):

id-ilych added the bug label to Issue #11753.

view this post on Zulip Wasmtime GitHub notifications bot (Sep 29 2025 at 12:28):

tschneidereit commented on issue #11753:

@fitzgen relevant to your interests :)

view this post on Zulip Wasmtime GitHub notifications bot (Sep 29 2025 at 18:22):

fitzgen commented on issue #11753:

Thanks for filing an issue!

The form does not allow WASM attachments, so here is the link https://github.com/id-ilych/wasmtime-bugreport/raw/3eddc3cab6fa/host/guest.wasm

This link 404s for me. FYI, github will allow you to attach gzip'd files, so you can attach testcase.wasm.gz here.

In general, I recommend filing separate issues with separate test cases for each bug you are hitting. Lumping multiple things together only makes it harder for maintainers to figure out what is or is not relevant to a particular bug, which slows down the whole process of diagnosing and fixing the bug.

See also our documentation on shrinking test cases

view this post on Zulip Wasmtime GitHub notifications bot (Sep 29 2025 at 18:53):

alexcrichton added the wasm-proposal:gc label to Issue #11753.

view this post on Zulip Wasmtime GitHub notifications bot (Sep 29 2025 at 19:21):

id-ilych commented on issue #11753:

Hello @fitzgen :wave: My bad, forgot to make the repo public. Please try again now.

In general, I recommend filing separate issues with separate test cases for each bug you are hitting

In general I would agree, but in that case the code for all the cases is exactly the same, it's only the size of allocations it does that differ (passed as argument), so I thought they might be manifestations of the same root cause. For example, 3 and 4 is just a debug build of 1 and 2, and even though 1 and 2 cause different panics, in debug mode they both trigger the same assertion failure. Also, if the developer would dive into GC code and change something there, the other cases are unlikely to be triggered by exactly the same values as now, so I would have to do fuzzy testing again and thus it looks counterproductive for both parties.

Anyway, if you still think it would be helpful to file each case separately - I could do that.

See also our documentation on shrinking test cases

I will check that out tomorrow, thanks.

view this post on Zulip Wasmtime GitHub notifications bot (Sep 30 2025 at 16:49):

fitzgen commented on issue #11753:

In general I would agree, but in that case the code for all the cases is exactly the same, it's only the size of allocations it does that differ (passed as argument), so I thought they might be manifestations of the same root cause.

If the test case is literally identical, yeah that makes sense. Thanks.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 01 2025 at 11:07):

id-ilych edited issue #11753:

Test Case

The form does not allow WASM attachments, so here is the link
https://github.com/id-ilych/wasmtime-bugreport/raw/3eddc3cab6fa/host/guest.wasm

UPD
Reduced WASM (see binaryen's wasm-reduce)
https://github.com/id-ilych/wasmtime-bugreport/raw/c93f146/host/guest.reduced.wasm

The host code

use std::error::Error;
use wasmtime::*;

fn main() -> Result<(), Box<dyn Error>> {
    let arg_a = std::env::args().nth(1).unwrap().parse()?;
    let arg_b = std::env::args().nth(2).unwrap().parse()?;
    let arg_x = std::env::args().nth(3).unwrap().parse()?;
    let arg_y = std::env::args().nth(4).unwrap().parse()?;
    let arg_z = std::env::args().nth(5).unwrap().parse()?;

    let engine = Engine::new(Config::default()
        .gc_support(true)
        .wasm_gc(true)
        .wasm_exceptions(true)
        .wasm_reference_types(true)
        .wasm_function_references(true)
        .allocation_strategy(PoolingAllocationConfig::new()
            .max_memory_size(1_000_000)
            .to_owned()
        )
    )?;

    let module = Module::from_file(&engine, "guest.wasm")?;
    let mut linker = Linker::new(&engine);
    linker.func_wrap("wasi_snapshot_preview1", "random_get", |_: i32, _: i32| -> i32 { return 5 })?; // Errno::Io

    let instantiate = || -> Result<(Store<()>, TypedFunc<(i32, i32, i32, i32), i32>)> {
        let mut store = Store::new(&engine, ());
        let instance = linker.instantiate(&mut store, &module)?;

        let initialize = instance.get_typed_func::<(), ()>(&mut store, "_initialize")?;
        initialize.call(&mut store, ())?;

        let func = instance.get_typed_func(&mut store, "memtest")?;

        Ok((store, func))
    };

    let (mut store_a, func_a) = instantiate()?;
    let (mut store_b, func_b) = instantiate()?;

    for i in 0..100 {
        println!("{}", i);
        if arg_a > 0 {
            let _:i32 = func_a.call(&mut store_a, (arg_a, arg_x, arg_y, arg_z))?;
        }
        if arg_b > 0 {
            let _: i32 = func_b.call(&mut store_b, (arg_b, arg_x, arg_y, arg_z))?;
        }
    }

    Ok(())
}

You can find the whole project (including original Kotlin code for the guest) here:
https://github.com/id-ilych/wasmtime-bugreport/tree/3eddc3cab6fa

Steps to Reproduce

:warning: Each command listed here fails (or hangs), particular panics for each case are listed in Actual Results section

  1. RUST_BACKTRACE=1 cargo run --release 10000 7500 1 1 1
  2. RUST_BACKTRACE=1 cargo run --release 10000 11000 1 1 1
  3. RUST_BACKTRACE=1 cargo run 10000 7500 1 1 1
  4. RUST_BACKTRACE=1 cargo run 10000 11000 1 1 1
  5. RUST_BACKTRACE=1 cargo run --release 10000 7500 3 2 1
  6. RUST_BACKTRACE=1 cargo run --release 22000 0 1 2 3
  7. RUST_BACKTRACE=1 cargo run --release 12025 17812 5 5 5
  8. RUST_BACKTRACE=1 cargo run --release 15202 17813 2 1 1

Expected Results

Program finishes successfully (prints numbers from 0 to 99 (incl))

Actual Results

Command 1 produces "Option::unwrap() on a None value" panic in wasmtime-37.0.1/src/runtime/vm/gc/gc_runtime.rs:463:44

Command 2 produces "range start index 6553700 out of range for slice of length 524288" panic in wasmtime-37.0.1/src/runtime/vm/gc/gc_runtime.rs:466:47

Commands 3 and 4 each cause self.is_in_over_approximated_stack_roots() assertion failure in wasmtime-37.0.1/src/runtime/vm/gc/enabled/drc.rs:596:9

Command 5 hands after printing "5" (meaning that first 5 iterations completed successfully, but on i=5 it hanged)

Command 6 gives zsh: bus error RUST_BACKTRACE=1 cargo run --release 22000 0 1 2 3 (might be un-aligned memory access)

Command 7 produces "Option::unwrap() on a None value" panic in wasmtime-environ-37.0.1/src/types.rs:1160:25

Command 8 produces ""should have inserted trace info for every GC type allocated in this heap" panic in wasmtime-37.0.1/src/runtime/vm/gc/enabled/drc.rs:317:14

Versions and Environment

Wasmtime version or commit: 37.0.1

Operating system: macOS 15.6.1 (build 24G90)

Architecture: arm64e (Apple M2 Max)

Extra Info

Anything else you'd like to add?

view this post on Zulip Wasmtime GitHub notifications bot (Oct 01 2025 at 11:11):

id-ilych commented on issue #11753:

Hello @fitzgen :wave:

See also our documentation on shrinking test cases

I had no luck with wasm-shrink, so I used binaryen's wasm-reduce instead.

12802 -> 2275

Reduced WASM is available here https://github.com/id-ilych/wasmtime-bugreport/raw/c93f146/host/guest.reduced.wasm
(Description is updated too)


Last updated: Dec 06 2025 at 07:03 UTC