WebAssembly / WebAssembly/wabt
wat2wasm/wast2json: assertion failure (!IsReferenceWithIndex()) parsing a typed reference in a GC struct/array field
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 8.1k
- Forks
- 827
- Avg merge
- 4d 6h
- Merged PRs (30d)
- 18
Description
Summary
The WAT text parser aborts with an assertion failure when a GC struct or array field has a typed reference element type ((ref N) / (ref null N)). WastParser::ParseField builds the field's Type with the single-argument Type(Type::Enum) constructor, which discards the type index and asserts !IsReferenceWithIndex().
This is reachable from any tool/library entry point that parses WebAssembly text via ParseWatModule / ParseWastScript: wat2wasm, wast2json, spectest-interp, and any application linking libwabt.
- Debug/assert builds:
abort()→ denial of service (CWE-617, reachable assertion). - Release (
NDEBUG) builds: the assertion is compiled out and the field silently gets aTypewithtype_index_ = 0— the referenced type index is lost (incorrect parse result / type confusion).
Tested on main @ 03a00a1, Ubuntu 24.04, clang 18.1.3.
Steps to reproduce
$ echo '(module (type (struct (field (ref 0)))))' | wat2wasm --enable-gc --enable-function-references -
wat2wasm: .../include/wabt/type.h:75: wabt::Type::Type(wabt::Type::Enum): Assertion `!IsReferenceWithIndex()' failed.
Aborted (core dumped)
$ echo '(module (type (array (ref 0))))' | wat2wasm --enable-gc --enable-function-references -
Aborted (core dumped)
The same inputs also crash wast2json --enable-all.
Required feature flags
Both --enable-gc (for struct/array) and --enable-function-references (for the (ref N) syntax) are required.
What does / does not trigger it
Input inside (module (type ...)) |
flags | result |
|---|---|---|
(struct (field (ref 0))) |
gc + function-references | abort |
(array (ref 0)) |
gc + function-references | abort |
(struct (field (mut (ref 0)))) |
gc + function-references | abort |
(struct (field (ref 0))) |
gc only | clean parse error (ok) |
(struct (field i32)) |
gc + function-references | ok |
(struct (field funcref)) (non-indexed ref) |
gc + function-references | ok |
Only indexed typed references crash; non-reference and non-indexed reference types are fine.
Affected tools / functions
libwabt — WastParser::ParseField (reached by ParseWatModule and ParseWastScript). Tools: wat2wasm, wast2json, spectest-interp.
Root cause
src/wast-parser.cc, WastParser::ParseField() → lambda parse_mut_valuetype (lines ~1785–1792):
Var type;
CHECK_RESULT(ParseValueType(&type));
field->type = Type(type.opt_type()); // single-arg ctor drops the type index
ParseValueType may yield a typed reference (Type::Ref / Type::RefNull) whose opt_type() IsReferenceWithIndex(). Passing it to the single-arg constructor triggers the assert in include/wabt/type.h:74:
Type(Enum e) : enum_(e), type_index_(0) { assert(!IsReferenceWithIndex()); }
The sibling code in the same file already handles this correctly with the two-argument constructor:
// src/wast-parser.cc:1031 (ParseValueTypeList)
out_type_list->push_back(Type(type.opt_type(), kInvalidIndex));
So ParseField is simply missing the index argument that the rest of the parser uses.
Suggested fix
Preserve the reference's type index instead of dropping it — either mirror line 1031:
- field->type = Type(type.opt_type());
+ field->type = Type(type.opt_type(), kInvalidIndex);
(applied to both occurrences), or, better, resolve the parsed Var to a fully-typed reference the way other call sites do (VarToType(...), used for table element types), so that (ref N) keeps its actual target index N. The minimal change stops the crash; the VarToType-based change additionally fixes the silent index loss in release builds.
Discovery
Found via libFuzzer + ASAN/UBSAN with a custom wast2json harness mirroring src/tools/wast2json.cc.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/wast-parser.cc at WastParser::ParseField and compare parse_mut_valuetype with ParseValueTypeList around line 1031; inspect include/wabt/type.h to understand the assertion. Reproduce with the listed wat2wasm and wast2json inputs, then verify typed reference indices are preserved and both tools parse struct and array fields without aborting.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, wasm
- Domain
- compilers, devtools
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100