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

Clash of the tags #25

Closed
dhil opened this issue Oct 16, 2023 · 2 comments · Fixed by #215
Closed

Clash of the tags #25

dhil opened this issue Oct 16, 2023 · 2 comments · Fixed by #215
Labels
bug Something isn't working

Comments

@dhil
Copy link
Member

dhil commented Oct 16, 2023

At the time of writing, Wasmtime represents tags as unsigned integers. Thus, tags are not guaranteed to have a instance-unique identity. This is unsound. Here is a small example program that fails on our wasmtime implementation, but passes on the reference interpreter.

(module $foo
  (tag $foo (export "foo"))
)
(register "foo")

(module $bar
  (type $ft (func))
  (type $ct (cont $ft))
  (tag $foo (import "foo" "foo"))
  (tag $bar)
  (func $do_foo
    (suspend $foo))

  (func $main (export "main")
    (block $on_bar (result (ref $ct))
      (resume $ct (tag $bar $on_bar) (cont.new $ct (ref.func $do_foo)))
      (unreachable)
    )
    (unreachable))
  (elem declare func $do_foo)
)
(register "bar")
(assert_suspension (invoke "main") "unhandled")
@dhil dhil added bug Something isn't working wontfix This will not be worked on labels Oct 16, 2023
@dhil
Copy link
Member Author

dhil commented Oct 17, 2023

This should be fixed in the exception handling implementation first (in which case we get the fix for free).

@dhil dhil removed the wontfix This will not be worked on label May 30, 2024
@dhil
Copy link
Member Author

dhil commented May 30, 2024

Extended testsuite for this issue:

(module $foo
  (type $ft (func (result i32)))
  (type $ct (cont $ft))
  (type $ft-2 (func (param i32) (result i32)))
  (type $ct-2 (cont $ft-2))

  (tag $foo (export "foo") (result i32)) ;; occupies defined tag entry 0

  (func $do_foo (export "do_foo") (result i32)
     (suspend $foo))
  (func $handle_foo (export "handle_foo") (param $f (ref $ft)) (result i32)
    (block $on_foo (result (ref $ct-2))
      (resume $ct (tag $foo $on_foo) (cont.new $ct (local.get $f)))
      (return)
    ) ;; on_foo
    (drop)
    (return (i32.const 1))
  )
  (func (export "test_foo") (result i32)
    (call $handle_foo (ref.func $do_foo)))
  (elem declare func $do_foo)
)
(register "foo")
(assert_return (invoke "test_foo") (i32.const 1))

(module $bar
  (type $ft (func (result i32)))
  (type $ct (cont $ft))

  (type $ft-2 (func (param i32) (result i32)))
  (type $ct-2 (cont $ft-2))

  (tag $foo (import "foo" "foo") (result i32))
  (tag $bar (result i32))
  (func $do_foo (result i32)
    (suspend $foo))

  ;; Don't handle the imported foo.
  (func (export "skip-imported-foo") (result i32)
    (block $on_bar (result (ref $ct-2))
      (resume $ct (tag $bar $on_bar) (cont.new $ct (ref.func $do_foo)))
      (unreachable)
    )
    (unreachable))

  ;; Handle the imported foo.
  (func (export "handle-imported-foo") (result i32)
    (block $on_foo (result (ref $ct-2))
      (resume $ct (tag $foo $on_foo) (cont.new $ct (ref.func $do_foo)))
      (unreachable)
    )
    (drop)
    (return (i32.const 2))
  )

  (elem declare func $do_foo)
)
(register "bar")
(assert_suspension (invoke "skip-imported-foo") "unhandled")
(assert_return (invoke "handle-imported-foo") (i32.const 2))


(module $baz
  (type $ft (func (result i32)))
  (type $ct (cont $ft))

  (type $ft-2 (func (param i32) (result i32)))
  (type $ct-2 (cont $ft-2))

  (func $handle_foo (import "foo" "handle_foo") (param (ref $ft)) (result i32))
  (func $do_foo (import "foo" "do_foo") (result i32))

  (tag $baz (result i32)) ;; unused, but occupies defined tag entry 0

  (func $handle_baz (param $f (ref $ft)) (result i32)
    (block $on_baz (result (ref $ct-2))
      (resume $ct (tag $baz $on_baz) (cont.new $ct (local.get $f)))
      (return)
    ) ;; on_baz
    (drop)
    (return (i32.const 3))
  )

  (func $inner-baz (result i32)
    (call $handle_baz (ref.func $do_foo)))
  (func (export "compose-handle-foo-baz") (result i32)
    (call $handle_foo (ref.func $inner-baz)))

  (func $inner-foo (result i32)
    (call $handle_foo (ref.func $do_foo)))
  (func (export "compose-handle-baz-foo") (result i32)
    (call $handle_baz (ref.func $inner-foo)))
  (elem declare func $do_foo $inner-baz $inner-foo)
)
(register "baz")
(assert_return (invoke "compose-handle-baz-foo") (i32.const 1))
(assert_return (invoke "compose-handle-foo-baz") (i32.const 1))

(module $quux
  (type $ft (func (result i32)))
  (type $ct (cont $ft))

  (type $ft-2 (func (param i32) (result i32)))
  (type $ct-2 (cont $ft-2))

  (func $handle_foo (import "foo" "handle_foo") (param (ref $ft)) (result i32))
  (tag $foo (import "foo" "foo") (result i32))

  (func $do_foo (result i32)
    (suspend $foo))

  (func $my_handle_foo (param $f (ref $ft)) (result i32)
    (block $on_foo (result (ref $ct-2))
      (resume $ct (tag $foo $on_foo) (cont.new $ct (local.get $f)))
      (return)
    ) ;; on_foo
    (drop)
    (return (i32.const 4))
  )

  (func $inner-my-foo (result i32)
    (call $my_handle_foo (ref.func $do_foo)))
  (func (export "compose-handle-foo-my-foo") (result i32)
    (call $handle_foo (ref.func $inner-my-foo)))

  (func $inner-foo (result i32)
    (call $handle_foo (ref.func $do_foo)))
  (func (export "compose-handle-my-foo-foo") (result i32)
    (call $my_handle_foo (ref.func $inner-foo)))
  (elem declare func $do_foo $inner-my-foo $inner-foo)
)
(register "quux")
(assert_return (invoke "compose-handle-foo-my-foo") (i32.const 4))
(assert_return (invoke "compose-handle-my-foo-foo") (i32.const 1))

dhil added a commit to dhil/wasmtime that referenced this issue Aug 20, 2024
This patch implements support for importing and exporting tags in the
virtual machine. As a consequence tags are now unique to their origin
instance, meaning that two different instantiations of the same module
yields distinct tags.

The runtime representation of a tag has changed from an `u32` to a
`usize` (or native pointer). The identity of a tag is given by its
address in the vmcontext.

Resolves wasmfx#25.
@dhil dhil mentioned this issue Aug 20, 2024
dhil added a commit to dhil/wasmtime that referenced this issue Aug 21, 2024
This patch implements support for importing and exporting tags in the
virtual machine. As a consequence tags are now unique to their origin
instance, meaning that two different instantiations of the same module
yields distinct tags.

The runtime representation of a tag has changed from an `u32` to a
`usize` (or native pointer). The identity of a tag is given by its
address in the vmcontext.

Resolves wasmfx#25.
@dhil dhil closed this as completed in #215 Aug 23, 2024
@dhil dhil closed this as completed in d66ad85 Aug 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant