Skip to content

Commit 96dfd60

Browse files
authored
Validate type references by index (#2584)
1 parent 9aa64a8 commit 96dfd60

File tree

7 files changed

+121
-4
lines changed

7 files changed

+121
-4
lines changed

include/wabt/shared-validator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class SharedValidator {
7272
Index type_index);
7373
Result OnStructType(const Location&, Index field_count, TypeMut* fields);
7474
Result OnArrayType(const Location&, TypeMut field);
75+
Result EndTypeSection();
7576

7677
Result OnFunction(const Location&, Var sig_var);
7778
Result OnTable(const Location&, Type elem_type, const Limits&);
@@ -294,6 +295,7 @@ class SharedValidator {
294295
Type actual,
295296
Type expected,
296297
const char* desc);
298+
Result CheckReferenceType(const Location&, Type type, const char* desc);
297299
Result CheckLimits(const Location&,
298300
const Limits&,
299301
uint64_t absolute_max,

src/shared-validator.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@ Result SharedValidator::OnArrayType(const Location&, TypeMut field) {
7676
return Result::Ok;
7777
}
7878

79+
Result SharedValidator::EndTypeSection() {
80+
Result result = Result::Ok;
81+
82+
for (auto func_type : func_types_) {
83+
for (auto type : func_type.second.params) {
84+
result |= CheckReferenceType(Location(), type, "params");
85+
}
86+
87+
for (auto type : func_type.second.results) {
88+
result |= CheckReferenceType(Location(), type, "results");
89+
}
90+
}
91+
return result;
92+
}
93+
7994
Result SharedValidator::OnFunction(const Location& loc, Var sig_var) {
8095
Result result = Result::Ok;
8196
FuncType type;
@@ -197,6 +212,22 @@ Result SharedValidator::CheckType(const Location& loc,
197212
return Result::Ok;
198213
}
199214

215+
Result SharedValidator::CheckReferenceType(const Location& loc,
216+
Type type,
217+
const char* desc) {
218+
if (type.IsReferenceWithIndex()) {
219+
Index index = type.GetReferenceIndex();
220+
auto iter = func_types_.find(index);
221+
222+
if (iter == func_types_.end()) {
223+
return PrintError(loc, "reference %d is out of range in %s",
224+
static_cast<int>(index), desc);
225+
}
226+
}
227+
228+
return Result::Ok;
229+
}
230+
200231
Result SharedValidator::OnTag(const Location& loc, Var sig_var) {
201232
Result result = Result::Ok;
202233
FuncType type;
@@ -479,6 +510,9 @@ Result SharedValidator::OnLocalDecl(const Location& loc,
479510
PrintError(loc, "local count must be < 0x10000000");
480511
return Result::Error;
481512
}
513+
514+
CHECK_RESULT(CheckReferenceType(loc, type, "locals"));
515+
482516
locals_.push_back(LocalDecl{type, GetLocalCount() + count});
483517
return Result::Ok;
484518
}

src/validator.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,8 @@ Result Validator::CheckModule() {
736736
}
737737
}
738738

739+
result_ |= validator_.EndTypeSection();
740+
739741
// Import section.
740742
for (const ModuleField& field : module->fields) {
741743
if (auto* f = dyn_cast<ImportModuleField>(&field)) {

src/wast-parser.cc

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,11 @@ void AppendInlineExportFields(Module* module,
542542
module->AppendFields(fields);
543543
}
544544

545+
bool IsIndexLikelyType(Index index) {
546+
// TODO: Incorrect values can be misinterpreted by the parser.
547+
return index >= static_cast<Index>(Type::Void);
548+
}
549+
545550
} // End of anonymous namespace
546551

547552
WastParser::WastParser(WastLexer* lexer,
@@ -937,10 +942,10 @@ Result WastParser::ParseValueTypeList(TypeVector* out_type_list,
937942
CHECK_RESULT(ParseValueType(&type));
938943

939944
if (type.is_index()) {
940-
// TODO: Incorrect values can be misinterpreted by the parser.
941-
if (type.index() >= static_cast<Index>(Type::Void)) {
945+
if (IsIndexLikelyType(type.index())) {
942946
out_type_list->push_back(Type(type.index()));
943947
} else {
948+
type_vars->push_back(ReferenceVar(out_type_list->size(), type));
944949
out_type_list->push_back(Type(Type::Reference, type.index()));
945950
}
946951
} else {
@@ -1313,11 +1318,24 @@ Result WastParser::ResolveRefTypes(const Module& module,
13131318

13141319
assert(type.IsReferenceWithIndex());
13151320

1321+
if (ref_var.var.is_index()) {
1322+
if (type.GetReferenceIndex() >= module.types.size()) {
1323+
errors->emplace_back(
1324+
ErrorLevel::Error, ref_var.var.loc,
1325+
StringPrintf("reference type out of range: %d (max: %d)",
1326+
static_cast<int>(type.GetReferenceIndex()),
1327+
static_cast<int>(module.types.size())));
1328+
result = Result::Error;
1329+
}
1330+
continue;
1331+
}
1332+
13161333
if (type.GetReferenceIndex() != kInvalidIndex) {
1334+
// Resolved earlier.
13171335
continue;
13181336
}
13191337

1320-
const auto type_index = module.type_bindings.FindIndex(ref_var.var.name());
1338+
Index type_index = module.type_bindings.FindIndex(ref_var.var.name());
13211339

13221340
if (type_index == kInvalidIndex) {
13231341
errors->emplace_back(ErrorLevel::Error, ref_var.var.loc,
@@ -2057,7 +2075,12 @@ Result WastParser::ParseBoundValueTypeList(TokenType token,
20572075
bindings->emplace(name,
20582076
Binding(loc, binding_index_offset + types->size()));
20592077
if (type.is_index()) {
2060-
types->push_back(Type(type.index()));
2078+
if (IsIndexLikelyType(type.index())) {
2079+
types->push_back(Type(type.index()));
2080+
} else {
2081+
type_vars->push_back(ReferenceVar(types->size(), type));
2082+
types->push_back(Type(Type::Reference, type.index()));
2083+
}
20612084
} else {
20622085
assert(type.is_name());
20632086
assert(options_->features.function_references_enabled());
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
;;; TOOL: run-gen-wasm-bad
2+
;;; ARGS1: --enable-function-references
3+
;;; ARGS2: --enable-function-references
4+
magic
5+
version
6+
section(TYPE) {
7+
count[2]
8+
function params[1] reference 10 results[1] reference 20
9+
function params[0] results[0]
10+
}
11+
section(FUNCTION) { count[1] sig[1] }
12+
section(CODE) {
13+
count[1]
14+
func {
15+
local_decls[1]
16+
locals[1] reference 30
17+
}
18+
}
19+
(;; STDERR ;;;
20+
0000000: error: reference 10 is out of range in params
21+
0000000: error: reference 20 is out of range in results
22+
out/test/binary/bad-reference-indicies/bad-reference-indicies.wasm:000001d: error: reference 30 is out of range in locals
23+
0000000: error: reference 10 is out of range in params
24+
0000000: error: reference 20 is out of range in results
25+
out/test/binary/bad-reference-indicies/bad-reference-indicies.wasm:000001d: error: reference 30 is out of range in locals
26+
;;; STDERR ;;)

test/gen-wasm.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
'f64': 0x7c, # -4
4444
'v128': 0x7b, # -5
4545
'funcref': 0x70, # -0x10
46+
'reference': 0x6b, # -0x15
4647
'function': 0x60, # -0x20
4748
'struct': 0x5f, # -0x21
4849
'array': 0x5e, # -0x22

test/parse/bad-references.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
;;; TOOL: wat2wasm
2+
;;; ARGS: --enable-function-references
3+
;;; ERROR: 1
4+
(module
5+
;; Implicit type declarations are not allowed
6+
(type $t0 (func (param (ref 2))))
7+
(type $t1 (func (param (ref 33)) (result (ref 444))))
8+
9+
(func $f (param $p1 (ref 5555))
10+
(local $p2 (ref 66666))
11+
)
12+
)
13+
(;; STDERR ;;;
14+
out/test/parse/bad-references.txt:6:31: error: reference type out of range: 2 (max: 2)
15+
(type $t0 (func (param (ref 2))))
16+
^
17+
out/test/parse/bad-references.txt:7:31: error: reference type out of range: 33 (max: 2)
18+
(type $t1 (func (param (ref 33)) (result (ref 444))))
19+
^^
20+
out/test/parse/bad-references.txt:7:49: error: reference type out of range: 444 (max: 2)
21+
(type $t1 (func (param (ref 33)) (result (ref 444))))
22+
^^^
23+
out/test/parse/bad-references.txt:9:28: error: reference type out of range: 5555 (max: 2)
24+
(func $f (param $p1 (ref 5555))
25+
^^^^
26+
out/test/parse/bad-references.txt:10:21: error: reference type out of range: 66666 (max: 2)
27+
(local $p2 (ref 66666))
28+
^^^^^
29+
;;; STDERR ;;)

0 commit comments

Comments
 (0)