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

Fix binary parser of declarative element segments #6618

Merged
merged 2 commits into from
Jun 3, 2024

Conversation

tanishiking
Copy link
Contributor

@tanishiking tanishiking commented May 21, 2024

The parser was incorrectly handling the parsing of declarative element segments (those with the elemkind of declarative).
According to the spec, the init of the declarative element should be a vec(expr) if the prefix is 7.
https://webassembly.github.io/spec/core/binary/modules.html#element-section
However, binaryen was simply reading a single u32LEB value for each
expression instead of parsing a expression regardless usesExpressions = true.

This commit updates the WasmBinaryReader::readElementSegments function
to correctly parse the expressions for declarative element segments by
calling readExpression instead of getU32LEB if usesExpressions = true.

Resolves the parsing exception:
"[parse exception: bad section size, started at ... not being equal to new position ...]"

Related discussion: tanishiking/scala-wasm#136

@tanishiking tanishiking changed the title Fix parser of declarative element segments Fix binary parser of declarative element segments May 21, 2024
@kripken
Copy link
Member

kripken commented May 22, 2024

I'm not very familiar with this part of the spec, but it looks like there are broken tests on CI here so perhaps additional changes are needed?

@tanishiking
Copy link
Contributor Author

tanishiking commented May 23, 2024

Thanks! Indeed, it seems like the problem is, we have to switch the init is vec(expr) or vec(funcidx) based on the the prefix is 3 or 7 (and we didn't). https://webassembly.github.io/spec/core/binary/modules.html#element-section

Screenshot 2024-05-23 at 10 33 54

And, also some tests need to be fixed. I'll take a look

@tanishiking tanishiking force-pushed the fix-elem-declarative branch 2 times, most recently from 4269354 to 9b56e6d Compare May 23, 2024 01:56
@tanishiking
Copy link
Contributor Author

tanishiking commented May 23, 2024

I think I could fix the issue, but in my local environment some tests are still fail because of the following error message

/Users/tanishiking/ghq/github.com/tanishiking/binaryen/test/lit/fuzz-types.test:31:15: error: found empty check string with prefix 'CHECK:'
;; CHECK-NEXT:
              ^

error: command failed with exit status: 2

which seems some kind of problem in my local setup(?) and unrelated to the change (actually it fails even in main branch) 😃

@kripken
Copy link
Member

kripken commented May 23, 2024

Maybe the local error is due to the lit version? Installing it this way may help:

# Install with `pip3 install -r requirements-dev.txt`

The code here looks right to me. Please add a test for this so we don't regress it. The test could be under test/lit/ if there isn't a specific obvious file to add to.

@tanishiking
Copy link
Contributor Author

tanishiking commented May 27, 2024

Thanks @kripken !

Now, I'm struggling to test this change because

  • The S-expr parser in binaryen (and the binary parser too) does not keep declared elements in the IR
  • When generating output, it calculates the necessary declarations using the getFunctionsNeedingElemDeclare function, and then outputs those in Text output and Binary output.
  • Therefore, whether we include declared element segments in the input WAST or binary in test cases, binaryen will ignore the input declared elements and generate the calculated ones in the output.

That's why, it is not possible to test parsing of declared element segments based on the output of binaryen. A possible approach would be to use another tool (e.g., the reference interpreter?) to generate a binary with declared elements and test if binaryen can parse that.

Are there any test cases that parses wasm binary/WAT generated by other tools?

Ah, it looks like .fromBinary is the thing

@tlively
Copy link
Member

tlively commented May 27, 2024

Note that the SExpressionWasmBuilder is deprecated and about to be removed in #6607. The parser your tests are using is implemented in the src/parser directory. It still doesn't preserve declarative segments in the IR, though.

This is a case where checking in a binary test would be appropriate. Other such tests live in the test/lit/binary directory.

The parser was incorrectly handling the parsing of declarative element segments whose `init` is a `vec(expr)`.
https://webassembly.github.io/spec/core/binary/modules.html#element-section
Binry parser was simply reading a single `u32LEB` value for `init`
instead of parsing a expression regardless `usesExpressions = true`.

This commit updates the `WasmBinaryReader::readElementSegments` function
to correctly parse the expressions for declarative element segments by
calling `readExpression` instead of `getU32LEB` when `usesExpressions = true`.

Resolves the parsing exception:
"[parse exception: bad section size, started at ... not being equal to new position ...]"

Related discussion: tanishiking/scala-wasm#136
@tanishiking
Copy link
Contributor Author

Thanks, I added a test for wasm-dis that verifies the binary parser parses the declarative element segment that uses expression.
36bb145

@tlively
Copy link
Member

tlively commented May 31, 2024

Can you move the test to test/lit/binary and follow the pattern used by other tests there? We're generally trying to move tests to lit over time because it is faster and requires less maintenance than our bespoke test runners.

…`vec(expr)`

This commit adds a binary in `test/lit/binary` that is generated from the
following WAT file with a reference-interpreter from the `wasm-3.0-exn` branch:
WebAssembly/spec@b16745e

```wat
(module
  (elem declare funcref (item ref.func $f))
  (func $f (block
    (ref.func $f)
    (drop)
  ))
)
```

The disassembled result contains `(elem declare func $f)` instead
of `(elem declare funcref (item ref.func $f))` because the binaryen parser
doesn't preserve declarative segments. This is fine, as we test that
the binary parser can parse the declarative element segment whose
`init` is `vec(expr)` without trapping.
@tanishiking
Copy link
Contributor Author

Sure, moved the test to test/lit/binary 02efecd

Copy link
Member

@tlively tlively left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@tlively tlively enabled auto-merge (squash) June 3, 2024 19:24
@tlively tlively merged commit 9347a22 into WebAssembly:main Jun 3, 2024
13 checks passed
@tanishiking tanishiking deleted the fix-elem-declarative branch June 3, 2024 22:49
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

Successfully merging this pull request may close these issues.

None yet

3 participants