Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Should partial memory/table initializations after instantiation traps still be visible? #138

Closed
fitzgen opened this issue Feb 25, 2020 · 4 comments · Fixed by #139
Closed

Comments

@fitzgen
Copy link
Contributor

fitzgen commented Feb 25, 2020

Thinking particularly about these tests:

IIRC memory.init and table.init didn't used to do up front bounds checks, which would explain the behavior prescribed by those tests.

However, the spec now has bounds checks before any mutations for memory.init and table.init. Since instantiation of active table segments and data segments is described in terms of memory.init and table.init, I would expect the bounds checks to happen before any mutations to the memory and table.

Am I overlooking something?

@fitzgen
Copy link
Contributor Author

fitzgen commented Feb 25, 2020

Basically, these tests look out of date to me, but I want to make sure my understanding is correct before I open PRs to fix them.

Thanks!

@binji
Copy link
Member

binji commented Feb 25, 2020

I think these are still correct. The MVP requires that all data segments and element segments are in bounds before writing any of them. If any of them are out of bounds, then no changes are made.

The bulk memory proposal loosens this so that segments are written in order, first element segments and then data segments. An individual segment is bounds-checked, so it will never be partially updated. But previously initialized segments are persisted.

It used to be that a segment would also be partially written if it were out-of-bounds, but we rolled back that part of the change.

@fitzgen
Copy link
Contributor Author

fitzgen commented Feb 26, 2020

Ah yes, of course! Thanks for the explanation.

It seems that while the linking.wast test checks that an in bounds segment is initialized into the table before an out-of-bounds trap happens when initializing a following segment, it is missing a check that none of a partially out of bounds segment's elements end up in the table. And similar for data segments.

(module $m
  (table (export "table") funcref (elem $zero $zero $zero $zero $zero $zero $zero $zero $zero $zero))

  (func $zero (result i32)
    (i32.const 0))

  (func (export "indirect-call") (param i32) (result i32)
    local.get 0
    call_indirect (result i32)))

(register "m" $m)

(assert_trap
  (module
    (table (import "m" "table") 10 funcref)

    (func $one (result i32)
      (i32.const 1))

    ;; An in-bounds segment that should get initialized in the table.
    (elem (i32.const 7) $one)

    ;; Part of this segment is out of bounds, so none of its elements should be
    ;; initialized into the table, and it should trap.
    (elem (i32.const 9) $one $one $one)
  )
  "out of bounds"
)

;; The first `$one` segment *was* initialized OK.
;;
;; We already have tests for this case.
(assert_return (invoke "indirect-call" (i32.const 7)) (i32.const 1))

;; The second `$one` segment is partially out of bounds, and therefore none of
;; its elements were written into the table.
;;
;; We do *not* have tests for this case.
(assert_return (invoke "indirect-call" (i32.const 9)) (i32.const 0))

Should I make a PR to add this second assertion?

@binji
Copy link
Member

binji commented Feb 26, 2020

Yes, thanks!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
2 participants