Skip to content

Commit b004290

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 parsed a full heap type there, which additionally accepts a bare non-negative type index, so `0x00` was wrongly decoded as the value type `(ref null 0)`. Parse an abstract heap type directly in the short-form path (handling the `0x65` prefix for `shared` variants) so a bare index is rejected at decode time. This also covers the over-long-LEB variant (`ff 00`). In value-type position the error surfaces as `invalid value type`; in a reference-type-only position (e.g. a table element type) as `malformed reference type`. The legitimate `0x63 <idx>` / `0x64 <idx>` concrete reftypes and the `shared` abstract shorthands (`0x65 ...`) are unaffected.
1 parent b3fdc82 commit b004290

5 files changed

Lines changed: 115 additions & 6 deletions

File tree

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,17 +1822,25 @@ impl<'a> FromReader<'a> for RefType {
18221822
}
18231823
0x62 => Err(crate::Error::new("unexpected exact type", pos)),
18241824
_ => {
1825-
// Reclassify errors as invalid reference types here because
1826-
// that's the "root" of what was being parsed rather than
1827-
// heap types.
1828-
let hty = reader.read().map_err(|mut e| {
1825+
// The short form of a reference type (without a `0x63`/`0x64`
1826+
// prefix byte) is only an abbreviation for `ref null <ht>` where
1827+
// `<ht>` is an *abstract* heap type; a bare (non-negative) type
1828+
// index is not a value type. Parse an abstract heap type
1829+
// directly, handling the `0x65` prefix for `shared` variants,
1830+
// rather than parsing a full heap type and then rejecting the
1831+
// concrete/exact cases that a heap type additionally allows.
1832+
let shared = reader.peek()? == 0x65;
1833+
if shared {
1834+
reader.read_u8()?;
1835+
}
1836+
let ty = reader.read().map_err(|mut e| {
18291837
if let ErrorKind::InvalidHeapType = e.kind() {
18301838
e.set_message("malformed reference type");
18311839
}
18321840
e
18331841
})?;
1834-
RefType::new(true, hty)
1835-
.ok_or_else(|| crate::Error::new("type index too large", pos))
1842+
// `RefType::new` is infallible for abstract heap types.
1843+
Ok(RefType::new(true, HeapType::Abstract { shared, ty }).unwrap())
18361844
}
18371845
}
18381846
}

tests/cli/bad-reftype.wast

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
;; A bare index used as a value type. In value-type position the error is
9+
;; reclassified as "invalid value type".
10+
(assert_malformed
11+
(module binary
12+
"\00asm" "\01\00\00\00" ;; module header
13+
14+
"\01\08\02" ;; type section, 2 types
15+
"\60\00\00" ;; type 0: (func)
16+
"\60\01" ;; type 1: (func (param ...)), 1 param
17+
"\00" ;; param 0: bare type index 0x00 (invalid value type)
18+
"\00" ;; 0 results
19+
)
20+
"invalid value type")
21+
22+
;; The same bug with an over-long LEB encoding of the bare index (`\ff\00` = 127).
23+
;; The reftype discriminator is a single byte, so this must be rejected at decode
24+
;; time rather than re-interpreted as a type index.
25+
(assert_malformed
26+
(module binary
27+
"\00asm" "\01\00\00\00" ;; module header
28+
29+
"\01\09\02" ;; type section, 2 types
30+
"\60\00\00" ;; type 0: (func)
31+
"\60\01" ;; type 1: (func (param ...)), 1 param
32+
"\ff\00" ;; param 0: bare index 0x00 with an over-long LEB
33+
"\00" ;; 0 results
34+
)
35+
"invalid value type")
36+
37+
;; The same bare index in a reference-type-only position (a table's element type)
38+
;; is reported as a malformed reference type.
39+
(assert_malformed
40+
(module binary
41+
"\00asm" "\01\00\00\00" ;; module header
42+
43+
"\04\04\01" ;; table section, 1 table
44+
"\00" ;; element type: bare index 0x00 (malformed reftype)
45+
"\00\00" ;; limits: no max, minimum 0
46+
)
47+
"malformed reference type")
48+
49+
;; Boundary: the legitimate concrete reftypes `0x63 <idx>` (`ref null $t`) and
50+
;; `0x64 <idx>` (`ref $t`), where the index is an sLEB after the prefix byte, must
51+
;; still be accepted.
52+
(module binary
53+
"\00asm" "\01\00\00\00" ;; module header
54+
55+
"\01\0b\02" ;; type section, 2 types
56+
"\60\00\00" ;; type 0: (func)
57+
"\60\02" ;; type 1: (func (param ...)), 2 params, 0 results
58+
"\63\00" ;; param 0: (ref null 0)
59+
"\64\00" ;; param 1: (ref 0)
60+
"\00" ;; 0 results
61+
)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"source_filename": "tests/cli/bad-reftype.wast",
3+
"commands": [
4+
{
5+
"type": "assert_malformed",
6+
"line": 11,
7+
"filename": "bad-reftype.0.wasm",
8+
"module_type": "binary",
9+
"text": "invalid value type"
10+
},
11+
{
12+
"type": "assert_malformed",
13+
"line": 26,
14+
"filename": "bad-reftype.1.wasm",
15+
"module_type": "binary",
16+
"text": "invalid value type"
17+
},
18+
{
19+
"type": "assert_malformed",
20+
"line": 40,
21+
"filename": "bad-reftype.2.wasm",
22+
"module_type": "binary",
23+
"text": "malformed reference type"
24+
},
25+
{
26+
"type": "module",
27+
"line": 52,
28+
"filename": "bad-reftype.3.wasm",
29+
"module_type": "binary"
30+
}
31+
]
32+
}
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+
)
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)