Skip to content

Commit 4c40f51

Browse files
committed
wasmparser: reject bare type index as a value type
The short form of a reference type (without a `0x63`/`0x64` prefix) is only an abbreviation for `ref null <abstract-heap-type>`. The decoder instead read a full heap type there, so a bare non-negative type index was accepted as a value type, e.g. `0x00` decoding to `(ref null 0)`. Reject concrete/exact heap types reached through the short-form path with `malformed reference type` at decode time, matching the reference interpreter. This also covers the over-long-LEB variant (`ff 00`). The legitimate `0x63 <idx>` / `0x64 <idx>` concrete reftypes and the `shared` abstract shorthands (`0x65 ...`) are unaffected.
1 parent b3fdc82 commit 4c40f51

4 files changed

Lines changed: 64 additions & 0 deletions

File tree

crates/wasmparser/src/readers/core/types.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,6 +1831,15 @@ impl<'a> FromReader<'a> for RefType {
18311831
}
18321832
e
18331833
})?;
1834+
// The short form of a reference type (without a `0x63`/`0x64`
1835+
// prefix byte) is only an abbreviation for `ref null <ht>` where
1836+
// `<ht>` is an *abstract* heap type. A bare (non-negative) type
1837+
// index is not a value type, so reject concrete/exact heap types
1838+
// reached through this path even though they parse as heap types
1839+
// in their own right.
1840+
if let HeapType::Concrete(_) | HeapType::Exact(_) = hty {
1841+
return Err(crate::Error::new("malformed reference type", pos));
1842+
}
18341843
RefType::new(true, hty)
18351844
.ok_or_else(|| crate::Error::new("type index too large", pos))
18361845
}

tests/cli/bad-reftype.wast

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
;; RUN: wast --assert default --snapshot tests/snapshots %
2+
3+
;; A value type is `numtype | vectype | reftype`, and a reference type is either
4+
;; an abstract heap type shorthand byte or the two-byte `0x64 heaptype` (`ref ht`)
5+
;; / `0x63 heaptype` (`ref null ht`) forms. There is no bare type-index value
6+
;; type, so a leading byte of `0x00` (a non-negative sLEB) is malformed.
7+
8+
;; type 0 = (func), type 1 = (func (param <0x00>)) — bare index used as a value type.
9+
(assert_malformed
10+
(module binary
11+
"\00asm\01\00\00\00\01\08\02\60\00\00\60\01\00\00")
12+
"malformed reference type")
13+
14+
;; The same bug with an over-long LEB encoding of the bare index (`\ff\00` = 127).
15+
;; The reftype discriminator is a single byte, so this must be rejected at decode
16+
;; time rather than re-interpreted as a type index.
17+
(assert_malformed
18+
(module binary
19+
"\00asm\01\00\00\00\01\09\02\60\00\00\60\01\ff\00\00")
20+
"malformed reference type")
21+
22+
;; Boundary: the legitimate concrete reftypes `0x63 <idx>` (`ref null $t`) and
23+
;; `0x64 <idx>` (`ref $t`), where the index is an sLEB after the prefix byte, must
24+
;; still be accepted.
25+
(module binary
26+
"\00asm\01\00\00\00\01\0b\02\60\00\00\60\02\63\00\64\00\00")
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"source_filename": "tests/cli/bad-reftype.wast",
3+
"commands": [
4+
{
5+
"type": "assert_malformed",
6+
"line": 10,
7+
"filename": "bad-reftype.0.wasm",
8+
"module_type": "binary",
9+
"text": "malformed reference type"
10+
},
11+
{
12+
"type": "assert_malformed",
13+
"line": 18,
14+
"filename": "bad-reftype.1.wasm",
15+
"module_type": "binary",
16+
"text": "malformed reference type"
17+
},
18+
{
19+
"type": "module",
20+
"line": 25,
21+
"filename": "bad-reftype.2.wasm",
22+
"module_type": "binary"
23+
}
24+
]
25+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
(module
2+
(type (;0;) (func))
3+
(type (;1;) (func (param (ref null 0) (ref 0))))
4+
)

0 commit comments

Comments
 (0)