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

[spec] Can memory.grow take n < 0 ? #924

Closed
Centril opened this issue Nov 28, 2018 · 11 comments
Closed

[spec] Can memory.grow take n < 0 ? #924

Centril opened this issue Nov 28, 2018 · 11 comments

Comments

@Centril
Copy link

Centril commented Nov 28, 2018

Reading the operational semantics of memory.grow it isn't clear whether you can shrink the amount of memory with that instruction (the meaning of "grow" and "append" isn't detailed but once can guess what it means...).

Similarly, reading growmem does not bring clarity; I didn't see the syntax meminst.data (0x00)n⋅64Ki defined anywhere; I assume it means that meminst.data is concatenated with (0x00)n⋅64Ki but it would be nice to make this clearer wrt. behavior and inductively define the operation A B.

cc rust-lang/rust#56292
Some advice would be good. :)

@gnzlbg
Copy link

gnzlbg commented Nov 28, 2018

In particular growmem states:

  1. Let len be n added to the length of meminst.𝖽𝖺𝗍𝖺 divided by the page size 64Ki.

Where "added" works for both signed and unsigned integers, but "divided" does not specify if a signed / unsigned dive operation is performed. And the check for "overflow" happens afterwards:

  1. If len is larger than 2^16, then fail.

So if n is either large enough or negative, depending on whether one interprets its bits as a signed or unsigned integer, the addition of step 3 can wrap around and be smaller than 2^16, shrinking the allocation.

Also, in step 3, "is larger than", does not specify whether the greater than signed or unsigned instruction is used.

The growmem section does not specify the types of n, len, etc. so it is also a bit unclear to me whether we are talking about i32 here or not - probably yes, otherwise 2^16 does not make much sense.

@sunfishcode
Copy link
Member

For reference, the design PR where resize_memory was renamed to grow_memory, and the delta was made explicitly unsigned, with the intent that if shrinking should ever be supported, it should be a different operation, is WebAssembly/design#389.

@binji
Copy link
Member

binji commented Nov 28, 2018

Runtime integer values are always stored on the execution stack unsigned, see the definition of Values here, which references the definition of integers here:

The latter class defines uninterpreted integers, whose signedness interpretation can vary depending on context. In the abstract syntax, they are represented as unsigned values. However, some operations convert them to signed based on a two’s complement interpretation.

You can see an example of this in the definition of i32.gt_s.

Where "added" works for both signed and unsigned integers, but "divided" does not specify if a signed / unsigned dive operation is performed.

The numerics in the formal syntax always use the standard mathematical syntax. Unsigned integer division, for example, is defined like this: trunc(i1/i2)

Similarly, none of the numbers in the formal definitions use modular arithmetic (you can see an example of how that would be specified in i32.add) so it is not possible for them to wrap around.

I didn't see the syntax meminst.data (0x00)n⋅64Ki defined anywhere; I assume it means that meminst.data is concatenated with (0x00)n⋅64Ki but it would be nice to make this clearer wrt. behavior and inductively define the operation A B.

I don't see the definition of that either, though perhaps I missed it. It is indeed meant to be a concatenation.

@Centril
Copy link
Author

Centril commented Nov 28, 2018

@binji Thanks for the details! :)

Perhaps meminst.data ++ (0x00)n⋅64Ki would be clearer?

@binji
Copy link
Member

binji commented Nov 28, 2018

For this example, maybe, but this form of concatenation is used pervasively elsewhere in the spec (see the binary section for example) where it would be visually very noisy to do this.

@Centril
Copy link
Author

Centril commented Nov 28, 2018

@binji ah; makes sense -- how about adding A B to the list of conventions somewhere instead?

@binji
Copy link
Member

binji commented Nov 28, 2018

Sounds good to me, but I'll defer to @rossberg for that :-)

@rossberg
Copy link
Member

Since sequences are simply represented by iterations of a certain phrase class, juxtaposition already is concatenation by construction. Hence no further convention needs to be defined. If that is non-obvious we could add a note, but it seems like everybody read it correctly?

@Centril
Copy link
Author

Centril commented Nov 28, 2018

@rossberg I do think someone who is not familiar with reading literature on operational semantics could be confused so it seems noteworthy with a sentence somewhere. :) I understood what A B meant only from the context since it can also be function application in other contexts.

@binji
Copy link
Member

binji commented Jan 24, 2019

Perhaps the formal semantics could be clearer, but I think the meaning of "grow" and "append" in the prose would have to be awkwardly contorted to allow shrinking. As described here the purpose of the prose to provide the intuitive meaning, which seems to have been understood here.

Closing, but feel free to reopen if you feel strongly here.

@binji binji closed this as completed Jan 24, 2019
@xtuc
Copy link
Contributor

xtuc commented Jan 25, 2019

Now that we switched to the WebIDL specification, the {Table,Memory}.grow takes an unsigned 32 bits int.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants