Fix invalid tag index when parsing declarative element segments with … - #9093
Conversation
| } else { | ||
| auto elemKind = getU32LEB(); | ||
| if (elemKind != 0x0) { | ||
| throwError("Invalid kind (!= funcref(0)) since !usesExpressions."); |
There was a problem hiding this comment.
Please rewrite this error message to be something like "unexpected passive segment elemkind, expected 0, got X". This will be a user-facing error.
| @@ -0,0 +1,24 @@ | |||
| ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. | |||
| ;; RUN: wasm-opt %s -all --roundtrip -S -o - | filecheck %s | |||
There was a problem hiding this comment.
Unfortunately --roundtrip won't work to test this because the declarative segments will be discarded after parsing and will not be present in the emitted binary format.
The best way to test this will be with a binary spec test. Can you add one to test/spec? Or even better, add one in the upstream spec tests (if there isn't one already) and we can pull it into Binaryen.
…GC reftypes The binary reader in readElementSegments() read only a single LEB for the type of declarative element segments (flag 0x07). For that flag the type is a full reftype, which may be a prefix byte plus a heap- type LEB (e.g. 0x63 0x02 for (ref null 2)). This misaligned the stream and eventually caused a spurious 'invalid tag index' error. The fix uses the same logic already applied to passive and hasTableIdx segments: read a full reftype when usesExpressions is true, and an elemkind (single byte) otherwise. Fixes WebAssembly#8540.
3c9b2c3 to
0e92cd6
Compare
|
@tlively, Thanks for the review. I've rewritten the |
| ;; Before the fix, parsing this module failed with "invalid tag index". | ||
| ;; See https://github.com/WebAssembly/binaryen/issues/8540 | ||
|
|
||
| (module binary "\00asm\01\00\00\00\01\1b\01N\06^w\00P\00_\00^r\01P\00`\01~\00^}\01P\00^{\01\03\03\02\03\03\09\0f\03\07c\02\00\07c\03\01\d0\03\0b\07q\00\0a\07\02\02\00\0b\02\00\0b") |
There was a problem hiding this comment.
Please see the style used in other module binary instances in the test suite. They usually have explanatory comments on the side explaining the meaning of each byte sequence for the benefit of the reader.
Summary
Fix a parser bug where
wasm-optrejected valid modules containingdeclarative element segments with GC reftypes, failing with
parse exception: invalid tag index.Problem
Binaryen's binary reader (
WasmBinaryReader::readElementSegmentsinsrc/wasm/wasm-binary.cpp) misread the type field of declarativeelement segments (flag
0x07).In the binary format, a declarative segment is encoded as:
where
reftypecan be a single byte (e.g.nullref) or a prefix byteplus a heap-type LEB (e.g.
0x63 0x02for(ref null 2)).The reader only consumed a single
getU32LEB()for the type. When thereftype was
(ref null 2)— i.e. a prefixed heap type — the readerwould consume the prefix byte as if it were the whole type, then
misinterpret the following bytes as the vector length. This misaligned
the stream, and downstream parsing eventually tried to resolve a value
against the tag table, producing:
parse exception:
invalid tag index (at 0:51)Minimal repro (from the issue):
wasm-toolsvalidate accepts this module; Binaryen rejects it.Fix
Apply the same logic that is already used for passive and table-indexed
segments to the declarative case:
If usesExpressions is set (flag
0x07), read a full reftype usinggetType().Otherwise (flag
0x03), read the single-byte elemkind and validateit is 0 (funcref).
Previously, the declarative branch unconditionally called
getU32LEB()for the type, which works only for flag 0x03.Why this approach: The fix is minimal and localized to the
declarative branch. It reuses the existing, correct reftype-reading
path rather than introducing a new helper. Declared segments are
intentionally dropped from Binaryen IR (they are not needed there), so
no IR representation changes are required — only the binary reader
needs to consume the correct number of bytes.
Testing
Manual verification:
Before the fix:
After the fix:
Cross-checked against the reference toolchain:
wasm-toolsaccepts the module, confirming the input is spec-compliant.New regression test:
test/lit/binary/gc-elem-declare.wastexercises
--roundtripon thereproducer, which forces Binaryen towrite and re-read the module through the binary format. Before the
fix, --roundtrip would hit the same invalid tag index error.
Full test suite:
All lit tests pass.
Related Issues
Fixes #8540.
Follow-up Work
None. Declared segments remain intentionally dropped from Binaryen IR,
so no additional handling is needed beyond correct parsing.