Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit 35c403c

Browse files
committed
trap if sync->async call fails to produce a result
If the callee returns `CallbackCode.WAIT` and the event loop runs out of futures without producing a ready waitable, we should trap. We were doing that in other contexts, but not for sync->async calls. Fixes #73 Signed-off-by: Joel Dice <joel.dice@fermyon.com>
1 parent b1fb18e commit 35c403c

3 files changed

Lines changed: 69 additions & 24 deletions

File tree

crates/wasmtime/src/runtime/component/concurrent.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ impl ComponentInstance {
890890
Ok(())
891891
} else {
892892
// In this case, the fiber suspended while holding on to its
893-
// `*mut dyn VMStoret` instead of returning it to us. That
893+
// `*mut dyn VMStore` instead of returning it to us. That
894894
// means we can't do anything else with the store (or self)
895895
// for now; the only thing we can do is suspend _our_ fiber
896896
// back up to the top level executor, which will resume us
@@ -1542,13 +1542,11 @@ impl ComponentInstance {
15421542
}
15431543
let task = instance.guest_task().unwrap();
15441544
if let ResultInfo::Stack { result_count } = &result_info {
1545-
match result_count {
1546-
0 => {}
1547-
1 => {
1548-
instance.get_mut(task)?.sync_result = Some(my_src[0]);
1549-
}
1545+
instance.get_mut(task)?.sync_result = Some(match result_count {
1546+
0 => None,
1547+
1 => Some(my_src[0]),
15501548
_ => unreachable!(),
1551-
}
1549+
})
15521550
}
15531551
if old_task_rep.is_some() {
15541552
let waitable = Waitable::Guest(task);
@@ -1576,11 +1574,6 @@ impl ComponentInstance {
15761574

15771575
if let Some(old_task) = old_task {
15781576
self.get_mut(old_task)?.subtasks.insert(guest_task);
1579-
log::trace!(
1580-
"new guest task child of {}: {}",
1581-
old_task.rep(),
1582-
guest_task.rep()
1583-
);
15841577
};
15851578

15861579
*self.guest_task() = Some(guest_task);
@@ -1714,7 +1707,11 @@ impl ComponentInstance {
17141707

17151708
if let Some(storage) = storage {
17161709
if let Some(result) = self.get_mut(guest_task)?.sync_result.take() {
1717-
storage[0] = MaybeUninit::new(result);
1710+
if let Some(result) = result {
1711+
storage[0] = MaybeUninit::new(result);
1712+
}
1713+
} else {
1714+
return Err(anyhow!(crate::Trap::NoAsyncResult));
17181715
}
17191716
Ok(0)
17201717
} else {
@@ -2892,7 +2889,7 @@ struct GuestTask {
28922889
deferred: Deferred,
28932890
should_yield: bool,
28942891
call_context: Option<CallContext>,
2895-
sync_result: Option<ValRaw>,
2892+
sync_result: Option<Option<ValRaw>>,
28962893
has_suspended: bool,
28972894
context: [u32; 2],
28982895
subtasks: HashSet<TableId<GuestTask>>,

tests/misc_testsuite/component-model-async/fused.wast

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@
5151
(func (export "run") (alias export $lowerer "run"))
5252
)
5353

54-
;; TODO: this requires async support in `wasmtime-wast`:
55-
;;(assert_return (invoke "run"))
54+
(assert_return (invoke "run"))
5655

5756
;; async lower -> async lift with callback
5857
(component
@@ -105,8 +104,7 @@
105104
(func (export "run") (alias export $lowerer "run"))
106105
)
107106

108-
;; TODO: this requires async support in `wasmtime-wast`:
109-
;;(assert_return (invoke "run"))
107+
(assert_return (invoke "run"))
110108

111109
;; async lower -> sync lift
112110
(component
@@ -152,8 +150,7 @@
152150
(func (export "run") (alias export $lowerer "run"))
153151
)
154152

155-
;; TODO: this requires async support in `wasmtime-wast`:
156-
;;(assert_return (invoke "run"))
153+
(assert_return (invoke "run"))
157154

158155
;; sync lower -> async lift without callback
159156
(component
@@ -196,8 +193,7 @@
196193
(func (export "run") (alias export $lowerer "run"))
197194
)
198195

199-
;; TODO: this requires async support in `wasmtime-wast`:
200-
;;(assert_return (invoke "run"))
196+
(assert_return (invoke "run"))
201197

202198
;; sync lower -> async lift with callback
203199
(component
@@ -244,5 +240,4 @@
244240
(func (export "run") (alias export $lowerer "run"))
245241
)
246242

247-
;; TODO: this requires async support in `wasmtime-wast`:
248-
;;(assert_return (invoke "run"))
243+
(assert_return (invoke "run"))
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
;;! cm_async = true
2+
3+
(component
4+
(component $child
5+
(core module $libc (memory (export "memory") 1))
6+
(core instance $libc (instantiate $libc))
7+
8+
(core module $m
9+
(import "" "waitable-set-new" (func $waitable-set-new (result i32)))
10+
(func (export "run") (result i32)
11+
call $waitable-set-new
12+
i32.const 4
13+
i32.shl
14+
i32.const 2 ;; CallbackCode.WAIT
15+
i32.or
16+
)
17+
18+
(func (export "cb") (param i32 i32 i32) (result i32)
19+
unreachable)
20+
)
21+
22+
(core func $waitable-set-new (canon waitable-set.new))
23+
24+
(core instance $i (instantiate $m
25+
(with "" (instance
26+
(export "waitable-set-new" (func $waitable-set-new))
27+
))
28+
))
29+
30+
(func (export "run")
31+
(canon lift (core func $i "run") async (callback (func $i "cb"))))
32+
)
33+
(instance $child (instantiate $child))
34+
35+
(core func $child-run (canon lower (func $child "run")))
36+
37+
(core module $m
38+
(import "" "child-run" (func $child-run))
39+
40+
(func (export "run")
41+
(call $child-run))
42+
)
43+
(core instance $i (instantiate $m
44+
(with "" (instance
45+
(export "child-run" (func $child-run))
46+
))
47+
))
48+
49+
(func (export "run")
50+
(canon lift (core func $i "run")))
51+
)
52+
53+
(assert_trap (invoke "run") "async-lifted export failed to produce a result")

0 commit comments

Comments
 (0)