Description
https://webassembly.github.io/spec/core/exec/modules.html#instantiation
The current specification for instantiation is all or nothing - if fail occurs during the process, the store and memories are not altered.
For example, in step 10, there is a bounds check to ensure that each data segment initialiser fits within the bounds of the memory, and if any of them fail, no copying takes place at all, and the whole instantiation aborts.
This is quite a strong specification, especially now that the memory being initialised may have been imported from another thread. Conceptually, all memory bounds must be explicitly calculated and checked at the start of instantiation, so that we never get in a situation where one data segment initialiser succeeds (and can be observed by another thread) but a subsequent one fails.
This is possible because the size of the memory will only ever increase, so implementations may in practice interleave mem.grows of other threads with the initialisation, so long as the bounds were calculated at the start.
However, if mem.protect is added, this "monotonicity" of memory writability will no longer hold. There is no ahead of time check that can be made to guarantee that the memory will be writable at the instant of data segment initialisation. I'm having trouble conceptualising a sane implementation that offers this all or nothing initialisation for a shared memory in the presence of mem.protect.
What do people think should happen in this case? Does this point to a fundamental problem with all or nothing initialisation?
My hot take: disallow data segment initialisers ("active" data segments) for shared memories at the validation level - instead force people to use the bulk memory proposal's instructions in the start function. This would make initialisation order, ahead of time bounds checking (if desired), and trap behaviour explicit, and probably avoids more gotchas down the road.