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

Commit fa551c4

Browse files
dicejlukewagner
andcommitted
trap in waitable-set.drop if set has waiters
Fixes #167 Co-authored-by: Luke Wagner <mail@lukewagner.name> Signed-off-by: Joel Dice <joel.dice@fermyon.com>
1 parent 28f15ac commit fa551c4

2 files changed

Lines changed: 93 additions & 1 deletion

File tree

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2944,7 +2944,11 @@ impl ComponentInstance {
29442944

29452945
log::trace!("drop waitable set {rep} (handle {set})");
29462946

2947-
self.delete(TableId::<WaitableSet>::new(rep))?;
2947+
let set = self.delete(TableId::<WaitableSet>::new(rep))?;
2948+
2949+
if !set.waiting.is_empty() {
2950+
bail!("cannot drop waitable set with waiters");
2951+
}
29482952

29492953
Ok(())
29502954
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
;;! component_model_async = true
2+
3+
;; This test contains two components $C and $D
4+
;; $D.run drives the test and first calls $C.wait-on-set, which waits on
5+
;; a waitable-set. Then $D.run calls $C.drop-while-waiting which attempts
6+
;; to drop the same waitable-set, which should trap.
7+
;;
8+
;; (Copied from
9+
;; https://github.com/WebAssembly/component-model/blob/add-tests/test/concurrency/drop-waitable-set.wast)
10+
(component
11+
(component $C
12+
(core module $Core
13+
(import "" "waitable-set.new" (func $waitable-set.new (result i32)))
14+
(import "" "waitable-set.drop" (func $waitable-set.drop (param i32)))
15+
16+
(global $ws (mut i32) (i32.const 0))
17+
(func $start (global.set $ws (call $waitable-set.new)))
18+
(start $start)
19+
20+
(func $wait-on-set (export "wait-on-set") (result i32)
21+
;; wait on $ws
22+
(i32.or (i32.const 2 (; WAIT ;)) (i32.shl (global.get $ws) (i32.const 4)))
23+
)
24+
(func $drop-while-waiting (export "drop-while-waiting") (result i32)
25+
(call $waitable-set.drop (global.get $ws))
26+
unreachable
27+
)
28+
(func $unreachable-cb (export "unreachable-cb") (param i32 i32 i32) (result i32)
29+
unreachable
30+
)
31+
)
32+
(canon waitable-set.new (core func $waitable-set.new))
33+
(canon waitable-set.drop (core func $waitable-set.drop))
34+
(core instance $core (instantiate $Core (with "" (instance
35+
(export "waitable-set.new" (func $waitable-set.new))
36+
(export "waitable-set.drop" (func $waitable-set.drop))
37+
))))
38+
(func (export "wait-on-set") (canon lift
39+
(core func $core "wait-on-set")
40+
async (callback (func $core "unreachable-cb"))
41+
))
42+
(func (export "drop-while-waiting") (canon lift
43+
(core func $core "drop-while-waiting")
44+
async (callback (func $core "unreachable-cb"))
45+
))
46+
)
47+
48+
(component $D
49+
(import "c" (instance $c
50+
(export "wait-on-set" (func))
51+
(export "drop-while-waiting" (func))
52+
))
53+
54+
(core module $Memory (memory (export "mem") 1))
55+
(core instance $memory (instantiate $Memory))
56+
(core module $Core
57+
(import "" "mem" (memory 1))
58+
(import "" "wait-on-set" (func $wait-on-set (param i32 i32) (result i32)))
59+
(import "" "drop-while-waiting" (func $drop-while-waiting))
60+
(func $run (export "run") (result i32)
61+
(local $ret i32)
62+
63+
;; start an async call to 'wait-on-set' which blocks, waiting on a
64+
;; waitable-set.
65+
(local.set $ret (call $wait-on-set (i32.const 0xdeadbeef) (i32.const 0xdeadbeef)))
66+
(if (i32.ne (i32.const 0x11) (local.get $ret))
67+
(then unreachable))
68+
69+
;; this call will try to drop the same waitable-set, which should trap.
70+
(call $drop-while-waiting)
71+
unreachable
72+
)
73+
)
74+
(canon lower (func $c "wait-on-set") async (memory $memory "mem") (core func $wait-on-set'))
75+
(canon lower (func $c "drop-while-waiting") (core func $drop-while-waiting'))
76+
(core instance $core (instantiate $Core (with "" (instance
77+
(export "mem" (memory $memory "mem"))
78+
(export "wait-on-set" (func $wait-on-set'))
79+
(export "drop-while-waiting" (func $drop-while-waiting'))
80+
))))
81+
(func (export "run") (result u32) (canon lift (core func $core "run")))
82+
)
83+
84+
(instance $c (instantiate $C))
85+
(instance $d (instantiate $D (with "c" (instance $c))))
86+
(func (export "run") (alias export $d "run"))
87+
)
88+
(assert_trap (invoke "run") "cannot drop waitable set with waiters")

0 commit comments

Comments
 (0)