Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panic when running Wasm gc program #9669

Open
Tracked by #5032
kritzcreek opened this issue Nov 24, 2024 · 7 comments
Open
Tracked by #5032

Panic when running Wasm gc program #9669

kritzcreek opened this issue Nov 24, 2024 · 7 comments
Assignees
Labels
bug Incorrect behavior in the current implementation that needs fixing wasm-proposal:gc Issues with the implementation of the gc wasm proposal

Comments

@kritzcreek
Copy link

Thanks so much for working on implementing the gc proposal! When I tested it on my own small language I ran into a panic and managed to minify the example down to:

Test Case

Minimal reproduction:

use std::error::Error;
use wasmtime::{Config, Engine, Instance, Module, Store};
fn main() -> Result<(), Box<dyn Error>> {
    let wat = "\
(module
  (rec
    (type (;0;) (func (result i32)))
    (type (;1;) (array (mut i32)))
    (type $Point (;2;) (struct (field $xs (mut (ref null 1)))))
  )
  (export \"main\" (func $main))
  (func $main (;0;) (type 0) (result i32)
    (local $p (ref null $Point))
    i32.const 0
    array.new_fixed 1 1
    struct.new $Point
    local.set $p
    local.get $p
    struct.get $Point $xs
    i32.const 0
    i32.const 1
    array.set 1
    local.get $p
    struct.get $Point $xs
    i32.const 0
    array.get 1
  )
)";
    let engine = Engine::new(Config::new().wasm_function_references(true).wasm_gc(true))?;
    let mut store = Store::new(&engine, ());
    let module = Module::new(&engine, wat)?;
    let instance = Instance::new(&mut store, &module, &[])?;
    let main_func = instance.get_typed_func::<(), i32>(&mut store, "main")?;
    let result = main_func.call(&mut store, ())?;
    println!("Result: {:?}", result);
    Ok(())
}

Panics with:

thread 'main' panicked at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\gc\enabled\drc.rs:238:13:
every on-stack gc_ref inside a Wasm frame should have an entry in the VMGcRefActivationsTable; 0x20 is not in the table
stack backtrace:
   0: std::panicking::begin_panic_handler
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library\std\src\panicking.rs:665
   1: core::panicking::panic_fmt
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library\core\src\panicking.rs:74
   2: wasmtime::runtime::vm::gc::enabled::drc::DrcHeap::trace
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\gc\enabled\drc.rs:238
   3: wasmtime::runtime::vm::gc::enabled::drc::impl$9::collect_increment
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\gc\enabled\drc.rs:719
   4: wasmtime::runtime::vm::gc::gc_runtime::GarbageCollection::collect<wasmtime::runtime::vm::gc::enabled::drc::DrcCollection>
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\gc\gc_runtime.rs:682
   5: wasmtime::runtime::vm::gc::GcStore::gc
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\gc.rs:68
   6: wasmtime::runtime::store::StoreOpaque::gc
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\store.rs:1629
   7: wasmtime::runtime::store::impl$17::gc<tuple$<> >
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\store.rs:2645
   8: wasmtime::runtime::vm::libcalls::gc
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\libcalls.rs:449
   9: wasmtime::runtime::vm::libcalls::raw::gc::closure$0::closure$0
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\libcalls.rs:115
  10: wasmtime::runtime::vm::instance::Instance::from_vmctx<enum2$<core::result::Result<u32,anyhow::Error> >,wasmtime::runtime::vm::libcalls::raw::gc::closure$0::closure_env$0>    
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\instance.rs:239
  11: wasmtime::runtime::vm::libcalls::raw::gc::closure$0
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\libcalls.rs:113
  12: core::panic::unwind_safe::impl$25::call_once<enum2$<core::result::Result<u32,anyhow::Error> >,wasmtime::runtime::vm::libcalls::raw::gc::closure_env$0>
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c\library\core\src\panic\unwind_safe.rs:272
  13: std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<wasmtime::runtime::vm::libcalls::raw::gc::closure_env$0>,enum2$<core::result::Result<u32,anyhow::Error> > >
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c\library\std\src\panicking.rs:557
  14: core::iter::sources::once::impl$0::size_hint<wasmtime_environ::types::WasmSubType>
  15: std::panicking::try
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c\library\std\src\panicking.rs:521
  16: std::panic::catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<wasmtime::runtime::vm::libcalls::raw::gc::closure_env$0>,enum2$<core::result::Result<u32,anyhow::Error> > >
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c\library\std\src\panic.rs:350
  17: wasmtime::runtime::vm::traphandlers::catch_unwind_and_longjmp<enum2$<core::result::Result<u32,anyhow::Error> >,wasmtime::runtime::vm::libcalls::raw::gc::closure_env$0>       
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\traphandlers.rs:136
  18: wasmtime::runtime::vm::libcalls::raw::gc
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\libcalls.rs:112
  19: <unknown>
  20: <unknown>
  21: <unknown>
  22: wasmtime::runtime::func::typed::impl$1::call_raw::closure$0<tuple$<>,i32,tuple$<> >
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\func\typed.rs:217
  23: wasmtime::runtime::vm::traphandlers::catch_traps::call_closure<wasmtime::runtime::func::typed::impl$1::call_raw::closure_env$0<tuple$<>,i32,tuple$<> > >
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\traphandlers.rs:290
  24: wasmtime_setjmp_27_0_0
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\helpers.c:72
  25: wasmtime::runtime::vm::traphandlers::catch_traps::closure$1<wasmtime::runtime::func::typed::impl$1::call_raw::closure_env$0<tuple$<>,i32,tuple$<> > >
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\traphandlers.rs:267
  26: wasmtime::runtime::vm::traphandlers::impl$3::with::closure$0<wasmtime::runtime::vm::traphandlers::catch_traps::closure_env$1<wasmtime::runtime::func::typed::impl$1::call_raw::closure_env$0<tuple$<>,i32,tuple$<> > > >
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\traphandlers.rs:414
  27: wasmtime::runtime::vm::traphandlers::tls::set<i32,wasmtime::runtime::vm::traphandlers::impl$3::with::closure_env$0<wasmtime::runtime::vm::traphandlers::catch_traps::closure_env$1<wasmtime::runtime::func::typed::impl$1::call_raw::closure_env$0<tuple$<>,i32,
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\traphandlers.rs:790
  28: wasmtime::runtime::vm::traphandlers::call_thread_state::CallThreadState::with<wasmtime::runtime::vm::traphandlers::catch_traps::closure_env$1<wasmtime::runtime::func::typed::impl$1::call_raw::closure_env$0<tuple$<>,i32,tuple$<> > > >
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\traphandlers.rs:414
  29: wasmtime::runtime::vm::traphandlers::catch_traps<wasmtime::runtime::func::typed::impl$1::call_raw::closure_env$0<tuple$<>,i32,tuple$<> > >
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\vm\traphandlers.rs:259
  30: wasmtime::runtime::func::invoke_wasm_and_catch_traps<tuple$<>,wasmtime::runtime::func::typed::impl$1::call_raw::closure_env$0<tuple$<>,i32,tuple$<> > >
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\func.rs:1613
  31: wasmtime::runtime::func::typed::TypedFunc<tuple$<>,i32>::call_raw<tuple$<>,i32,tuple$<> >
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\func\typed.rs:214
  32: wasmtime::runtime::func::typed::TypedFunc<tuple$<>,i32>::call<tuple$<>,i32,ref_mut$<wasmtime::runtime::store::Store<tuple$<> > > >
             at C:\Users\creek\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-27.0.0\src\runtime\func\typed.rs:107
  33: nemo::main
             at .\crates\cli\src\main.rs:34
  34: core::ops::function::FnOnce::call_once<enum2$<core::result::Result<tuple$<>,alloc::boxed::Box<dyn$<core::error::Error>,alloc::alloc::Global> > > (*)(),tuple$<> >
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c\library\core\src\ops\function.rs:250

Versions and Environment

Wasmtime version or commit: 27.0.0

Operating system: Verified on Windows and Mac

Architecture: x86_64 and arm64

@kritzcreek kritzcreek added the bug Incorrect behavior in the current implementation that needs fixing label Nov 24, 2024
@pchickey
Copy link
Contributor

Nick is on vacation right now so this may need to wait until he's back.

@alexcrichton alexcrichton added the wasm-proposal:gc Issues with the implementation of the gc wasm proposal label Dec 3, 2024
@fitzgen
Copy link
Member

fitzgen commented Dec 4, 2024

Thanks for filing an issue and providing a .wat test case! Back from vacation now and slowly catching up on things.

As I just mentioned in another issue, at this moment the default collector (DRC) does not yet transitively decrement reference counts, so many acyclic garbage objects will be leaked (in this case, the array objects referenced from $Point objects).

This acyclic leakage is not fundamental nor intended long term, it just reflects that this is a young, WIP implementation. (Cycles will always leak with this collector, on the other hand, since it is a simple reference-counting collector and does not include a cycle collector.)

@fitzgen
Copy link
Member

fitzgen commented Dec 4, 2024

Ah but I see that I didn't read closely enough, and that this is finding a stack map issue, which the panic is a symptom of. This is a separate issue, unrelated to the leakage.

@14427
Copy link

14427 commented Jan 28, 2025

I ran into what appears to be the same issue. It only seems to occur for the DeferredReferenceCounting collector, switching to the Null collector causes the test to pass. I'm using wasmtime 29.0.1 on OS X.

Minimized test case:

#[test]
fn test_bug() {
    let program = r#"
        (module
            (type $empty (struct))
            (type $thing (struct
                (field $field1 (ref $empty))
                (field $field2 (ref $empty))
            ))

            (func (export "run")
                (local $object (ref $thing))

                struct.new $empty
                struct.new $empty
                struct.new $thing

                local.tee $object
                struct.get $thing $field1
                drop

                local.get $object
                struct.get $thing $field2
                drop
            )
        )
    "#;

    let mut config = Config::new();
    config.wasm_gc(true);
    config.collector(Collector::DeferredReferenceCounting);  // Switch to Null here to make test pass

    let engine = Engine::new(&config).unwrap();
    let mut store = Store::new(&engine, ());
    let module = Module::new(&engine, program).unwrap();

    let instance = Instance::new(&mut store, &module, &[]).unwrap();
    let func = instance.get_typed_func::<(), ()>(&mut store, "run").unwrap();
    func.call(&mut store, ()).unwrap();
}

@fitzgen
Copy link
Member

fitzgen commented Jan 28, 2025

The minimized test case is super helpful, thanks! I've been running creduce on the original test case's .wat disassembly and after five days its still at ~900KiB.

@fitzgen
Copy link
Member

fitzgen commented Jan 28, 2025

Err whoops I've actually been trying to minimize #9714, not this issue's test case.

@vouillon
Copy link

vouillon commented Feb 5, 2025

I'm not completely sure this is the same issue, but this small module fails in the same way.

(module
 (type $0 (sub (struct)))
 (type $1 (func (result (ref eq))))
 (global $global$0 (ref eq) (struct.new_default $0))
 (export "" (func $0))
 (func $0 (result (ref eq))
  (local $0 (ref eq))
  (local.set $0
   (struct.new_default $0)
  )
  (drop
   (global.get $global$0)
  )
  (local.get $0)
 )
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Incorrect behavior in the current implementation that needs fixing wasm-proposal:gc Issues with the implementation of the gc wasm proposal
Projects
None yet
Development

No branches or pull requests

6 participants