Stream: git-wasmtime

Topic: wasmtime / issue #12092 Cannot restart read of host-produ...


view this post on Zulip Wasmtime GitHub notifications bot (Nov 26 2025 at 05:52):

alexcrichton assigned dicej to issue #12092.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 26 2025 at 05:52):

alexcrichton opened issue #12092:

Applying this diff:

<details>

diff --git a/tests/all/component_model/async.rs b/tests/all/component_model/async.rs
index b3e816c758..b1e3bf8d55 100644
--- a/tests/all/component_model/async.rs
+++ b/tests/all/component_model/async.rs
@@ -1,5 +1,7 @@
 use crate::async_functions::{PollOnce, execute_across_threads};
 use anyhow::Result;
+use std::pin::Pin;
+use std::task::{Context, Poll};
 use wasmtime::{AsContextMut, Config, component::*};
 use wasmtime::{Engine, Store, StoreContextMut, Trap};
 use wasmtime_component_util::REALLOC_AND_FREE;
@@ -670,3 +672,98 @@ async fn task_deletion() -> Result<()> {

     Ok(())
 }
+
+#[tokio::test]
+#[cfg_attr(miri, ignore)]
+async fn cancel_host_future() -> Result<()> {
+    let mut config = Config::new();
+    config.async_support(true);
+    config.wasm_component_model_async(true);
+    let engine = Engine::new(&config)?;
+
+    let component = Component::new(
+        &engine,
+        r#"
+(component
+  (core module $libc (memory (export "memory") 1))
+  (core instance $libc (instantiate $libc))
+  (core module $m
+    (import "" "future.read" (func $future.read (param i32 i32) (result i32)))
+    (import "" "future.cancel-read" (func $future.cancel-read (param i32) (result i32)))
+    (memory (export "memory") 1)
+
+    (func (export "run") (param i32)
+      ;; read/cancel attempt 1
+      (call $future.read (local.get 0) (i32.const 100))
+      i32.const -1 ;; BLOCKED
+      i32.ne
+      if unreachable end
+
+      (call $future.cancel-read (local.get 0))
+      i32.const 2 ;; CANCELLED
+      i32.ne
+      if unreachable end
+
+      ;; read/cancel attempt 2
+      (call $future.read (local.get 0) (i32.const 100))
+      i32.const -1 ;; BLOCKED
+      i32.ne
+      if unreachable end
+
+      (call $future.cancel-read (local.get 0))
+      i32.const 2 ;; CANCELLED
+      i32.ne
+      if unreachable end
+    )
+  )
+
+  (type $f (future u32))
+  (core func $future.read (canon future.read $f async (memory $libc "memory")))
+  (core func $future.cancel-read (canon future.cancel-read $f))
+
+  (core instance $i (instantiate $m
+    (with "" (instance
+      (export "future.read" (func $future.read))
+      (export "future.cancel-read" (func $future.cancel-read))
+    ))
+  ))
+
+  (func (export "run") (param "f" $f)
+    (canon lift
+      (core func $i "run")
+      (memory $libc "memory")
+    )
+  )
+)
+        "#,
+    )?;
+
+    let mut store = Store::new(&engine, ());
+    let instance = Linker::new(&engine)
+        .instantiate_async(&mut store, &component)
+        .await?;
+    let func = instance.get_typed_func::<(FutureReader<u32>,), ()>(&mut store, "run")?;
+    let reader = FutureReader::new(&mut store, MyFutureReader);
+    func.call_async(&mut store, (reader,)).await?;
+
+    return Ok(());
+
+    struct MyFutureReader;
+
+    impl FutureProducer<()> for MyFutureReader {
+        type Item = u32;
+
+        fn poll_produce(
+            self: Pin<&mut Self>,
+            _cx: &mut Context<'_>,
+            _store: StoreContextMut<()>,
+            finish: bool,
+        ) -> Poll<Result<Option<Self::Item>>> {
+            if finish {
+                Poll::Ready(Ok(None))
+            } else {
+                Poll::Pending
+            }
+        }
+    }
+}

</details>

currently fails with:

$ cargo test --test all cancel_host_future
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.10s
     Running tests/all/main.rs (target/x86_64-unknown-linux-gnu/debug/deps/all-e79d98f84418a5e1)

running 1 test
test component_model::r#async::cancel_host_future ... FAILED

failures:

---- component_model::r#async::cancel_host_future stdout ----
Error: error while executing at wasm backtrace:
    0:     0xba - m!<wasm function 2>

Caused by:
    cannot read from future after previous read succeeded


failures:
    component_model::r#async::cancel_host_future

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 982 filtered out; finished in 0.01s

error: test failed, to rerun pass `--test all`

where the second future.read call is what's failing here

view this post on Zulip Wasmtime GitHub notifications bot (Nov 26 2025 at 05:52):

alexcrichton added the wasm-proposal:component-model-async label to Issue #12092.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 26 2025 at 05:52):

alexcrichton added the fuzz-bug label to Issue #12092.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 26 2025 at 16:34):

alexcrichton closed issue #12092:

Applying this diff:

<details>

diff --git a/tests/all/component_model/async.rs b/tests/all/component_model/async.rs
index b3e816c758..b1e3bf8d55 100644
--- a/tests/all/component_model/async.rs
+++ b/tests/all/component_model/async.rs
@@ -1,5 +1,7 @@
 use crate::async_functions::{PollOnce, execute_across_threads};
 use anyhow::Result;
+use std::pin::Pin;
+use std::task::{Context, Poll};
 use wasmtime::{AsContextMut, Config, component::*};
 use wasmtime::{Engine, Store, StoreContextMut, Trap};
 use wasmtime_component_util::REALLOC_AND_FREE;
@@ -670,3 +672,98 @@ async fn task_deletion() -> Result<()> {

     Ok(())
 }
+
+#[tokio::test]
+#[cfg_attr(miri, ignore)]
+async fn cancel_host_future() -> Result<()> {
+    let mut config = Config::new();
+    config.async_support(true);
+    config.wasm_component_model_async(true);
+    let engine = Engine::new(&config)?;
+
+    let component = Component::new(
+        &engine,
+        r#"
+(component
+  (core module $libc (memory (export "memory") 1))
+  (core instance $libc (instantiate $libc))
+  (core module $m
+    (import "" "future.read" (func $future.read (param i32 i32) (result i32)))
+    (import "" "future.cancel-read" (func $future.cancel-read (param i32) (result i32)))
+    (memory (export "memory") 1)
+
+    (func (export "run") (param i32)
+      ;; read/cancel attempt 1
+      (call $future.read (local.get 0) (i32.const 100))
+      i32.const -1 ;; BLOCKED
+      i32.ne
+      if unreachable end
+
+      (call $future.cancel-read (local.get 0))
+      i32.const 2 ;; CANCELLED
+      i32.ne
+      if unreachable end
+
+      ;; read/cancel attempt 2
+      (call $future.read (local.get 0) (i32.const 100))
+      i32.const -1 ;; BLOCKED
+      i32.ne
+      if unreachable end
+
+      (call $future.cancel-read (local.get 0))
+      i32.const 2 ;; CANCELLED
+      i32.ne
+      if unreachable end
+    )
+  )
+
+  (type $f (future u32))
+  (core func $future.read (canon future.read $f async (memory $libc "memory")))
+  (core func $future.cancel-read (canon future.cancel-read $f))
+
+  (core instance $i (instantiate $m
+    (with "" (instance
+      (export "future.read" (func $future.read))
+      (export "future.cancel-read" (func $future.cancel-read))
+    ))
+  ))
+
+  (func (export "run") (param "f" $f)
+    (canon lift
+      (core func $i "run")
+      (memory $libc "memory")
+    )
+  )
+)
+        "#,
+    )?;
+
+    let mut store = Store::new(&engine, ());
+    let instance = Linker::new(&engine)
+        .instantiate_async(&mut store, &component)
+        .await?;
+    let func = instance.get_typed_func::<(FutureReader<u32>,), ()>(&mut store, "run")?;
+    let reader = FutureReader::new(&mut store, MyFutureReader);
+    func.call_async(&mut store, (reader,)).await?;
+
+    return Ok(());
+
+    struct MyFutureReader;
+
+    impl FutureProducer<()> for MyFutureReader {
+        type Item = u32;
+
+        fn poll_produce(
+            self: Pin<&mut Self>,
+            _cx: &mut Context<'_>,
+            _store: StoreContextMut<()>,
+            finish: bool,
+        ) -> Poll<Result<Option<Self::Item>>> {
+            if finish {
+                Poll::Ready(Ok(None))
+            } else {
+                Poll::Pending
+            }
+        }
+    }
+}

</details>

currently fails with:

$ cargo test --test all cancel_host_future
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.10s
     Running tests/all/main.rs (target/x86_64-unknown-linux-gnu/debug/deps/all-e79d98f84418a5e1)

running 1 test
test component_model::r#async::cancel_host_future ... FAILED

failures:

---- component_model::r#async::cancel_host_future stdout ----
Error: error while executing at wasm backtrace:
    0:     0xba - m!<wasm function 2>

Caused by:
    cannot read from future after previous read succeeded


failures:
    component_model::r#async::cancel_host_future

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 982 filtered out; finished in 0.01s

error: test failed, to rerun pass `--test all`

where the second future.read call is what's failing here


Last updated: Dec 06 2025 at 06:05 UTC