diff options
Diffstat (limited to 'src/wasm/wasm-s-parser.cpp')
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 110 |
1 files changed, 74 insertions, 36 deletions
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 1842237a5..6536d78fb 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -37,11 +37,20 @@ int unhex(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; - abort(); + throw wasm::ParseException("invalid hexadecimal"); } } namespace wasm { + +static Address getCheckedAddress(const Element* s, const char* errorText) { + uint64_t num = atoll(s->c_str()); + if (num > std::numeric_limits<Address::address_t>::max()) { + throw ParseException(errorText, s->line, s->col); + } + return num; +} + Element::List& Element::list() { if (!isList()) throw ParseException("expected list", line, col); return list_; @@ -53,12 +62,12 @@ Element* Element::operator[](unsigned i) { return list()[i]; } -IString Element::str() { +IString Element::str() const { if (!isStr()) throw ParseException("expected string", line, col); return str_; } -const char* Element::c_str() { +const char* Element::c_str() const { if (!isStr()) throw ParseException("expected string", line, col); return str_.str; } @@ -409,6 +418,7 @@ void SExpressionWasmBuilder::preParseFunctionType(Element& s) { if (need) { functionType->name = Name::fromInt(wasm.functionTypes.size()); functionTypeNames.push_back(functionType->name); + if (wasm.getFunctionTypeOrNull(functionType->name)) throw ParseException("duplicate function type", s.line, s.col); wasm.addFunctionType(functionType.release()); } } @@ -569,20 +579,21 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) { } if (importModule.is()) { // this is an import, actually - assert(preParseImport); + if (!preParseImport) throw ParseException("!preParseImport in func"); std::unique_ptr<Import> im = make_unique<Import>(); im->name = name; im->module = importModule; im->base = importBase; im->kind = ExternalKind::Function; im->functionType = wasm.getFunctionType(type)->name; + if (wasm.getImportOrNull(im->name)) throw ParseException("duplicate import", s.line, s.col); wasm.addImport(im.release()); - assert(!currFunction); + if (currFunction) throw ParseException("import module inside function dec"); currLocalTypes.clear(); nameMapper.clear(); return; } - assert(!preParseImport); + if (preParseImport) throw ParseException("preParseImport in func"); if (brokeToAutoBlock) { ensureAutoBlock(); autoBlock->name = FAKE_RETURN; @@ -597,6 +608,7 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) { if (currFunction->result != result) throw ParseException("bad func declaration", s.line, s.col); currFunction->body = body; currFunction->type = type; + if (wasm.getFunctionOrNull(currFunction->name)) throw ParseException("duplicate function", s.line, s.col); wasm.addFunction(currFunction.release()); currLocalTypes.clear(); nameMapper.clear(); @@ -612,7 +624,7 @@ WasmType SExpressionWasmBuilder::stringToWasmType(const char* str, bool allowErr if (str[1] == '6' && str[2] == '4' && (prefix || str[3] == 0)) return f64; } if (allowError) return none; - abort(); + throw ParseException("invalid wasm type"); } Expression* SExpressionWasmBuilder::parseExpression(Element& s) { @@ -852,7 +864,7 @@ Expression* SExpressionWasmBuilder::makeExpression(Element& s) { default: abort_on(str); } } - abort(); + abort_on("unrecognized input string for parsing"); } Expression* SExpressionWasmBuilder::makeBinary(Element& s, BinaryOp op, WasmType type) { @@ -951,6 +963,15 @@ Expression* SExpressionWasmBuilder::makeHost(Element& s, HostOp op) { } else { parseCallOperands(s, 1, s.size(), ret); } + if (ret->op == HostOp::GrowMemory) { + if (ret->operands.size() != 1) { + throw ParseException("grow_memory needs one operand"); + } + } else { + if (ret->operands.size() != 0) { + throw ParseException("host needs zero operands"); + } + } ret->finalize(); return ret; } @@ -1112,11 +1133,11 @@ Expression* SExpressionWasmBuilder::makeLoad(Element& s, WasmType type) { ret->bytes = 1; extra++; } else if (extra[0] == '1') { - assert(extra[1] == '6'); + if (extra[1] != '6') throw ParseException("expected load16"); ret->bytes = 2; extra += 2; } else if (extra[0] == '3') { - assert(extra[1] == '2'); + if (extra[1] != '2') throw ParseException("expected load32"); ret->bytes = 4; extra += 2; } @@ -1127,10 +1148,12 @@ Expression* SExpressionWasmBuilder::makeLoad(Element& s, WasmType type) { while (!s[i]->isList()) { const char *str = s[i]->c_str(); const char *eq = strchr(str, '='); - assert(eq); + if (!eq) throw ParseException("no = in load attribute"); eq++; if (str[0] == 'a') { - ret->align = atoi(eq); + uint64_t align = atoll(eq); + if (align > std::numeric_limits<uint32_t>::max()) throw ParseException("bad align"); + ret->align = align; } else if (str[0] == 'o') { uint64_t offset = atoll(eq); if (offset > std::numeric_limits<uint32_t>::max()) throw ParseException("bad offset"); @@ -1152,11 +1175,11 @@ Expression* SExpressionWasmBuilder::makeStore(Element& s, WasmType type) { ret->bytes = 1; extra++; } else if (extra[0] == '1') { - assert(extra[1] == '6'); + if (extra[1] != '6') throw ParseException("expected store16"); ret->bytes = 2; extra += 2; } else if (extra[0] == '3') { - assert(extra[1] == '2'); + if (extra[1] != '2') throw ParseException("expected store32");; ret->bytes = 4; extra += 2; } @@ -1166,10 +1189,12 @@ Expression* SExpressionWasmBuilder::makeStore(Element& s, WasmType type) { while (!s[i]->isList()) { const char *str = s[i]->c_str(); const char *eq = strchr(str, '='); - assert(eq); + if (!eq) throw ParseException("missing = in store attribute");; eq++; if (str[0] == 'a') { - ret->align = atoi(eq); + uint64_t align = atoll(eq); + if (align > std::numeric_limits<uint32_t>::max()) throw ParseException("bad align"); + ret->align = align; } else if (str[0] == 'o') { ret->offset = atoi(eq); } else throw ParseException("bad store attribute"); @@ -1299,7 +1324,14 @@ Name SExpressionWasmBuilder::getLabel(Element& s) { return nameMapper.sourceToUnique(s.str()); } else { // offset, break to nth outside label - uint64_t offset = std::stoll(s.c_str(), nullptr, 0); + uint64_t offset; + try { + offset = std::stoll(s.c_str(), nullptr, 0); + } catch (std::invalid_argument) { + throw ParseException("invalid break offset"); + } catch (std::out_of_range) { + throw ParseException("out of range break offset"); + } if (offset > nameMapper.labelStack.size()) throw ParseException("invalid label", s.line, s.col); if (offset == nameMapper.labelStack.size()) { // a break to the function's scope. this means we need an automatic block, with a name @@ -1335,6 +1367,7 @@ Expression* SExpressionWasmBuilder::makeBreakTable(Element& s) { while (!s[i]->isList()) { ret->targets.push_back(getLabel(*s[i++])); } + if (ret->targets.size() == 0) throw ParseException("switch with no targets"); ret->default_ = ret->targets.back(); ret->targets.pop_back(); ret->condition = parseExpression(s[i++]); @@ -1424,17 +1457,18 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) { im->module = importModule; im->base = importBase; im->name = importModule; + if (wasm.getImportOrNull(im->name)) throw ParseException("duplicate import", s.line, s.col); wasm.addImport(im.release()); i++; } else { - assert(inner.size() > 0 ? inner[0]->str() != IMPORT : true); + if (!(inner.size() > 0 ? inner[0]->str() != IMPORT : true)) throw ParseException("bad import ending"); // (memory (data ..)) format parseInnerData(*s[i]); wasm.memory.initial = wasm.memory.segments[0].data.size(); return; } } - wasm.memory.initial = atoi(s[i++]->c_str()); + wasm.memory.initial = getCheckedAddress(s[i++], "excessive memory init"); if (i == s.size()) return; if (s[i]->isStr()) { uint64_t max = atoll(s[i]->c_str()); @@ -1449,7 +1483,7 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) { if (curr[0]->str() == DATA) { offsetValue = 0; } else { - offsetValue = atoi(curr[j++]->c_str()); + offsetValue = getCheckedAddress(curr[j++], "excessive memory offset"); } const char *input = curr[j]->c_str(); auto* offset = allocator.alloc<Const>(); @@ -1507,7 +1541,7 @@ void SExpressionWasmBuilder::parseExport(Element& s) { ex->kind = ExternalKind::Global; if (wasm.getGlobalOrNull(ex->value) && wasm.getGlobal(ex->value)->mutable_) throw ParseException("cannot export a mutable global", s.line, s.col); } else { - WASM_UNREACHABLE(); + throw ParseException("invalid export"); } } else if (!s[2]->dollared() && !std::isdigit(s[2]->str()[0])) { ex->value = s[3]->str(); @@ -1519,7 +1553,7 @@ void SExpressionWasmBuilder::parseExport(Element& s) { } else if (s[2]->str() == GLOBAL) { ex->kind = ExternalKind::Global; } else { - WASM_UNREACHABLE(); + throw ParseException("invalid ext export"); } } else { // function @@ -1571,7 +1605,7 @@ void SExpressionWasmBuilder::parseImport(Element& s) { } else if (im->kind == ExternalKind::Table) { im->name = Name("import$table$" + std::to_string(0)); } else { - WASM_UNREACHABLE(); + throw ParseException("invalid import"); } } if (!s[i]->quoted()) { @@ -1582,7 +1616,7 @@ void SExpressionWasmBuilder::parseImport(Element& s) { } else if (s[i]->str() == GLOBAL) { im->kind = ExternalKind::Global; } else { - WASM_UNREACHABLE(); + throw ParseException("invalid ext import"); } i++; } else if (!newStyle) { @@ -1614,7 +1648,7 @@ void SExpressionWasmBuilder::parseImport(Element& s) { } if (inner.size() > j+1) { Element& result = *inner[j+1]; - assert(result[0]->str() == RESULT); + if (result[0]->str() != RESULT) throw ParseException("expected result"); type->result = stringToWasmType(result[1]->str()); } } @@ -1624,28 +1658,29 @@ void SExpressionWasmBuilder::parseImport(Element& s) { im->globalType = stringToWasmType(inner[j]->str()); } else { auto& inner2 = *inner[j]; - assert(inner2[0]->str() == MUT); + if (inner2[0]->str() != MUT) throw ParseException("expected mut"); im->globalType = stringToWasmType(inner2[1]->str()); throw ParseException("cannot import a mutable global", s.line, s.col); } } else if (im->kind == ExternalKind::Table) { if (j < inner.size() - 1) { - wasm.table.initial = atoi(inner[j++]->c_str()); + wasm.table.initial = getCheckedAddress(inner[j++], "excessive table init size"); } if (j < inner.size() - 1) { - wasm.table.max = atoi(inner[j++]->c_str()); + wasm.table.max = getCheckedAddress(inner[j++], "excessive table max size"); } else { wasm.table.max = Table::kMaxSize; } // ends with the table element type } else if (im->kind == ExternalKind::Memory) { if (j < inner.size()) { - wasm.memory.initial = atoi(inner[j++]->c_str()); + wasm.memory.initial = getCheckedAddress(inner[j++], "excessive memory init size"); } if (j < inner.size()) { - wasm.memory.max = atoi(inner[j++]->c_str()); + wasm.memory.max = getCheckedAddress(inner[j++], "excessive memory max size"); } } + if (wasm.getImportOrNull(im->name)) throw ParseException("duplicate import", s.line, s.col); wasm.addImport(im.release()); } @@ -1692,7 +1727,7 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { } if (importModule.is()) { // this is an import, actually - assert(preParseImport); + if (!preParseImport) throw ParseException("!preParseImport in global"); if (mutable_) throw ParseException("cannot import a mutable global", s.line, s.col); std::unique_ptr<Import> im = make_unique<Import>(); im->name = global->name; @@ -1700,10 +1735,11 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { im->base = importBase; im->kind = ExternalKind::Global; im->globalType = type; + if (wasm.getImportOrNull(im->name)) throw ParseException("duplicate import", s.line, s.col); wasm.addImport(im.release()); return; } - assert(!preParseImport); + if (preParseImport) throw ParseException("preParseImport in global"); global->type = type; if (i < s.size()) { global->init = parseExpression(s[i++]); @@ -1711,7 +1747,8 @@ void SExpressionWasmBuilder::parseGlobal(Element& s, bool preParseImport) { throw ParseException("global without init", s.line, s.col); } global->mutable_ = mutable_; - assert(i == s.size()); + if (i != s.size()) throw ParseException("extra import elements"); + if (wasm.getGlobalOrNull(global->name)) throw ParseException("duplicate import", s.line, s.col); wasm.addGlobal(global.release()); } @@ -1740,16 +1777,17 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { } else if (inner[0]->str() == IMPORT) { importModule = inner[1]->str(); importBase = inner[2]->str(); - assert(preParseImport); + if (!preParseImport) throw ParseException("!preParseImport in table"); auto im = make_unique<Import>(); im->kind = ExternalKind::Table; im->module = importModule; im->base = importBase; im->name = importModule; + if (wasm.getImportOrNull(im->name)) throw ParseException("duplicate import", s.line, s.col); wasm.addImport(im.release()); i++; } else { - WASM_UNREACHABLE(); + throw ParseException("invalid table"); } } if (i == s.size()) return; @@ -1815,7 +1853,6 @@ void SExpressionWasmBuilder::parseType(Element& s) { i++; } Element& func = *s[i]; - assert(func.isList()); for (size_t k = 1; k < func.size(); k++) { Element& curr = *func[k]; if (curr[0]->str() == PARAM) { @@ -1831,6 +1868,7 @@ void SExpressionWasmBuilder::parseType(Element& s) { type->name = Name::fromInt(wasm.functionTypes.size()); } functionTypeNames.push_back(type->name); + if (wasm.getFunctionTypeOrNull(type->name)) throw ParseException("duplicate function type", s.line, s.col); wasm.addFunctionType(type.release()); } |