Skip to content

Commit 9b5ce47

Browse files
authored
Fix bad param/var type error handling (WebAssembly#1499)
Improve error handling, validation, and assertions for having a non-concrete type in an inappropriate place. Fixes a fuzz testcase.
1 parent df19ebd commit 9b5ce47

6 files changed

Lines changed: 373 additions & 8 deletions

File tree

src/wasm-binary.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,7 @@ class WasmBinaryBuilder {
840840
int32_t getS32LEB();
841841
int64_t getS64LEB();
842842
Type getType();
843+
Type getConcreteType();
843844
Name getString();
844845
Name getInlineString();
845846
void verifyInt8(int8_t x);

src/wasm-builder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ class Builder {
375375

376376
static Index addVar(Function* func, Name name, Type type) {
377377
// always ok to add a var, it does not affect other indices
378+
assert(isConcreteType(type));
378379
Index index = func->getNumLocals();
379380
if (name.is()) {
380381
func->localIndices[name] = index;

src/wasm/wasm-binary.cpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,6 +1491,14 @@ Type WasmBinaryBuilder::getType() {
14911491
}
14921492
}
14931493

1494+
Type WasmBinaryBuilder::getConcreteType() {
1495+
auto type = getType();
1496+
if (!isConcreteType(type)) {
1497+
throw ParseException("non-concrete type when one expected");
1498+
}
1499+
return type;
1500+
}
1501+
14941502
Name WasmBinaryBuilder::getString() {
14951503
if (debug) std::cerr << "<==" << std::endl;
14961504
size_t offset = getInt32();
@@ -1579,7 +1587,7 @@ void WasmBinaryBuilder::readSignatures() {
15791587
size_t numParams = getU32LEB();
15801588
if (debug) std::cerr << "num params: " << numParams << std::endl;
15811589
for (size_t j = 0; j < numParams; j++) {
1582-
curr->params.push_back(getType());
1590+
curr->params.push_back(getConcreteType());
15831591
}
15841592
auto numResults = getU32LEB();
15851593
if (numResults == 0) {
@@ -1667,7 +1675,7 @@ void WasmBinaryBuilder::readImports() {
16671675
}
16681676
case ExternalKind::Global: {
16691677
curr->name = Name(std::string("gimport$") + std::to_string(i));
1670-
curr->globalType = getType();
1678+
curr->globalType = getConcreteType();
16711679
auto globalMutable = getU32LEB();
16721680
// TODO: actually use the globalMutable flag. Currently mutable global
16731681
// imports is a future feature, to be implemented with thread support.
@@ -1734,7 +1742,7 @@ void WasmBinaryBuilder::readFunctions() {
17341742
size_t numLocalTypes = getU32LEB();
17351743
for (size_t t = 0; t < numLocalTypes; t++) {
17361744
auto num = getU32LEB();
1737-
auto type = getType();
1745+
auto type = getConcreteType();
17381746
while (num > 0) {
17391747
vars.emplace_back(addVar(), type);
17401748
num--;
@@ -1943,7 +1951,7 @@ void WasmBinaryBuilder::readGlobals() {
19431951
if (debug) std::cerr << "num: " << num << std::endl;
19441952
for (size_t i = 0; i < num; i++) {
19451953
if (debug) std::cerr << "read one" << std::endl;
1946-
auto type = getType();
1954+
auto type = getConcreteType();
19471955
auto mutable_ = getU32LEB();
19481956
if (bool(mutable_) != mutable_) throw ParseException("Global mutability must be 0 or 1");
19491957
auto* init = readExpression();
@@ -2057,11 +2065,16 @@ Expression* WasmBinaryBuilder::popNonVoidExpression() {
20572065
block->list.push_back(expressions.back());
20582066
expressions.pop_back();
20592067
}
2060-
auto type = block->list[0]->type;
20612068
requireFunctionContext("popping void where we need a new local");
2062-
auto local = builder.addVar(currFunction, type);
2063-
block->list[0] = builder.makeSetLocal(local, block->list[0]);
2064-
block->list.push_back(builder.makeGetLocal(local, type));
2069+
auto type = block->list[0]->type;
2070+
if (isConcreteType(type)) {
2071+
auto local = builder.addVar(currFunction, type);
2072+
block->list[0] = builder.makeSetLocal(local, block->list[0]);
2073+
block->list.push_back(builder.makeGetLocal(local, type));
2074+
} else {
2075+
assert(type == unreachable);
2076+
// nothing to do here - unreachable anyhow
2077+
}
20652078
block->finalize();
20662079
return block;
20672080
}

src/wasm/wasm-validator.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,12 @@ void FunctionValidator::visitHost(Host* curr) {
795795
}
796796

797797
void FunctionValidator::visitFunction(Function* curr) {
798+
for (auto type : curr->params) {
799+
shouldBeTrue(isConcreteType(type), curr, "params must be concretely typed");
800+
}
801+
for (auto type : curr->vars) {
802+
shouldBeTrue(isConcreteType(type), curr, "vars must be concretely typed");
803+
}
798804
// if function has no result, it is ignored
799805
// if body is unreachable, it might be e.g. a return
800806
if (curr->body->type != unreachable) {

test/badvartype.wasm

698 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)