Skip to content

component-model-error-context: Buggy (?) host can trigger incorrect reference counting #13652

@alexcrichton

Description

@alexcrichton

This program:

use wasmtime::component::{Component, Linker, Val};
use wasmtime::{Config, Engine, Store};

const WAT: &str = r#"
(component
  (core module $libc
    (memory (export "memory") 1)
  )
  (core instance $libc (instantiate $libc))

  (core module $m
    (import "" "mem" (memory 1))
    (import "" "error-context.new" (func $new (param i32 i32) (result i32)))
    (import "" "error-context.drop" (func $drop (param i32)))

    (func (export "make") (result i32)
      (call $new (i32.const 0) (i32.const 0)))
    (func (export "consume") (param i32)
      (call $drop (local.get 0)))
  )

  (core func $new (canon error-context.new (memory $libc "memory")))
  (core func $drop (canon error-context.drop))

  (core instance $i (instantiate $m
    (with "" (instance
      (export "mem" (memory $libc "memory"))
      (export "error-context.new" (func $new))
      (export "error-context.drop" (func $drop))
    ))
  ))

  (func (export "make") (result error-context)
    (canon lift (core func $i "make")))

  (func (export "consume") (param "e" error-context)
    (canon lift (core func $i "consume")))
)
"#;

fn main() -> wasmtime::Result<()> {
    let mut config = Config::new();
    config.wasm_component_model_error_context(true);

    let engine = Engine::new(&config)?;
    let component = Component::new(&engine, WAT)?;
    let mut store = Store::new(&engine, ());
    let instance = Linker::new(&engine).instantiate(&mut store, &component)?;

    let make = instance.get_func(&mut store, "make").unwrap();
    let consume = instance.get_func(&mut store, "consume").unwrap();

    let mut results = vec![Val::Bool(false)];
    make.call(&mut store, &[], &mut results)?;
    let ec = results[0].clone();
    consume.call(&mut store, &[ec.clone()], &mut [])?;
    consume.call(&mut store, &[ec.clone()], &mut [])?;
    Ok(())
}

currently crashes with:

$ cargo run
   Compiling ec-refcount v0.0.0 (...)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.40s
     Running `target/debug/ec-refcount`

thread 'main' (1132305) panicked at /home/alex/code/wasmtime/crates/wasmtime/src/runtime/bug.rs:63:13:
BUG: retrieve concurrent state for error context during drop
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

The reference count of lowering from the host to the guest isn't updated, but it's also not clear to me what the correct behavior here is. Should the second lower be an error during lowering since the reference was consumed? Or does lowering clone? The error-context feature itself is still gated and not fully fleshed out upstream, so I'm filing this for now.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions