summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/tools/wasm-opt.cpp2
-rw-r--r--src/wasm-binary.h15
-rw-r--r--src/wasm-interpreter.h26
-rw-r--r--src/wasm/wasm-binary.cpp160
-rw-r--r--src/wasm/wasm-s-parser.cpp6
5 files changed, 156 insertions, 53 deletions
diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp
index a663b1a04..bf79cb31d 100644
--- a/src/tools/wasm-opt.cpp
+++ b/src/tools/wasm-opt.cpp
@@ -90,6 +90,8 @@ int main(int argc, const char* argv[]) {
} catch (ParseException& p) {
p.dump(std::cerr);
Fatal() << "error in parsing input";
+ } catch (std::bad_alloc& b) {
+ Fatal() << "error in building module, std::bad_alloc (possibly invalid request for silly amounts of memory)";
}
}
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 2f2df7c9b..921f90ac8 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -94,13 +94,16 @@ struct LEB {
: ((mask_type(1) << (sizeof(T) * 8 - shift)) - 1u);
T significant_payload = payload & shift_mask;
if (significant_payload != payload) {
- assert(std::is_signed<T>::value && last &&
- "dropped bits only valid for signed LEB");
+ if (!(std::is_signed<T>::value && last)) {
+ throw ParseException("LEB dropped bits only valid for signed LEB");
+ }
}
value |= significant_payload << shift;
if (last) break;
shift += 7;
- assert(size_t(shift) < sizeof(T) * 8 && "LEB overflow");
+ if (size_t(shift) >= sizeof(T) * 8) {
+ throw ParseException("LEB overflow");
+ }
}
// If signed LEB, then we might need to sign-extend. (compile should
// optimize this out if not needed).
@@ -110,7 +113,9 @@ struct LEB {
size_t sext_bits = 8 * sizeof(T) - size_t(shift);
value <<= sext_bits;
value >>= sext_bits;
- assert(value < 0 && "sign-extend should produces a negative value");
+ if (value >= 0) {
+ throw ParseException(" LEBsign-extend should produce a negative value");
+ }
}
}
}
@@ -640,6 +645,8 @@ class WasmBinaryBuilder {
size_t pos = 0;
Index startIndex = -1;
+ std::set<BinaryConsts::Section> seenSections;
+
public:
WasmBinaryBuilder(Module& wasm, std::vector<char>& input, bool debug) : wasm(wasm), allocator(wasm.allocator), input(input), debug(debug) {}
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 37cf7a7a6..b06afb1a1 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -240,7 +240,7 @@ public:
case ConvertUInt32ToFloat64: return value.convertUToF64();
case ConvertSInt32ToFloat32: return value.convertSToF32();
case ConvertSInt32ToFloat64: return value.convertSToF64();
- default: abort();
+ default: WASM_UNREACHABLE();
}
}
if (value.type == i64) {
@@ -255,7 +255,7 @@ public:
case ConvertUInt64ToFloat64: return value.convertUToF64();
case ConvertSInt64ToFloat32: return value.convertSToF32();
case ConvertSInt64ToFloat64: return value.convertSToF64();
- default: abort();
+ default: WASM_UNREACHABLE();
}
}
if (value.type == f32) {
@@ -273,7 +273,7 @@ public:
case TruncUFloat32ToInt64: return truncUFloat(curr, value);
case ReinterpretFloat32: return value.castToI32();
case PromoteFloat32: return value.extendToF64();
- default: abort();
+ default: WASM_UNREACHABLE();
}
}
if (value.type == f64) {
@@ -304,10 +304,10 @@ public:
if (val > std::numeric_limits<float>::max()) return Literal(std::numeric_limits<float>::infinity());
return value.truncateToF32();
}
- default: abort();
+ default: WASM_UNREACHABLE();
}
}
- abort();
+ WASM_UNREACHABLE();
}
Flow visitBinary(Binary *curr) {
NOTE_ENTER("Binary");
@@ -361,7 +361,7 @@ public:
case GtUInt32: return left.gtU(right);
case GeSInt32: return left.geS(right);
case GeUInt32: return left.geU(right);
- default: abort();
+ default: WASM_UNREACHABLE();
}
} else if (left.type == i64) {
switch (curr->op) {
@@ -404,7 +404,7 @@ public:
case GtUInt64: return left.gtU(right);
case GeSInt64: return left.geS(right);
case GeUInt64: return left.geU(right);
- default: abort();
+ default: WASM_UNREACHABLE();
}
} else if (left.type == f32 || left.type == f64) {
switch (curr->op) {
@@ -421,10 +421,10 @@ public:
case LeFloat32: case LeFloat64: return left.le(right);
case GtFloat32: case GtFloat64: return left.gt(right);
case GeFloat32: case GeFloat64: return left.ge(right);
- default: abort();
+ default: WASM_UNREACHABLE();
}
}
- abort();
+ WASM_UNREACHABLE();
}
Flow visitSelect(Select *curr) {
NOTE_ENTER("Select");
@@ -715,7 +715,7 @@ public:
std::cerr << "Function `" << function->name << "` expects "
<< function->params.size() << " parameters, got "
<< arguments.size() << " arguments." << std::endl;
- abort();
+ WASM_UNREACHABLE();
}
locals.resize(function->getNumLocals());
for (size_t i = 0; i < function->getNumLocals(); i++) {
@@ -726,7 +726,7 @@ public:
<< printWasmType(function->params[i])
<< " for parameter " << i << ", got "
<< printWasmType(arguments[i].type) << "." << std::endl;
- abort();
+ WASM_UNREACHABLE();
}
locals[i] = arguments[i];
} else {
@@ -873,7 +873,7 @@ public:
if (id == WASM) return Literal(1);
return Literal((int32_t)0);
}
- default: abort();
+ default: WASM_UNREACHABLE();
}
}
@@ -906,7 +906,7 @@ public:
if (function->result == none) ret = Literal();
if (function->result != ret.type) {
std::cerr << "calling " << function->name << " resulted in " << ret << " but the function type is " << function->result << '\n';
- abort();
+ WASM_UNREACHABLE();
}
callDepth = previousCallDepth; // may decrease more than one, if we jumped up the stack
// if we jumped up the stack, we also need to pop higher frames
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 521edab39..6da37cd86 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -945,6 +945,15 @@ void WasmBinaryBuilder::read() {
auto oldPos = pos;
+ // almost no sections can appear more than once
+ if (seenSections.count(BinaryConsts::Section(sectionCode)) > 0) {
+ if (sectionCode != BinaryConsts::Section::User && sectionCode != BinaryConsts::Section::Code) {
+ throw ParseException("section seen more than once: " + std::to_string(sectionCode));
+ }
+ } else {
+ seenSections.insert(BinaryConsts::Section(sectionCode));
+ }
+
switch (sectionCode) {
case BinaryConsts::Section::Start: readStart(); break;
case BinaryConsts::Section::Memory: readMemory(); break;
@@ -966,13 +975,17 @@ void WasmBinaryBuilder::read() {
case BinaryConsts::Section::Table: readFunctionTableDeclaration(); break;
default: {
readUserSection(payloadLen);
- assert(pos <= oldPos + payloadLen);
+ if (pos > oldPos + payloadLen) {
+ throw ParseException("bad user section size, started at " + std::to_string(oldPos) + " plus payload " + std::to_string(payloadLen) + " not being equal to new position " + std::to_string(pos));
+ }
pos = oldPos + payloadLen;
}
}
// make sure we advanced exactly past this section
- assert(pos == oldPos + payloadLen);
+ if (pos != oldPos + payloadLen) {
+ throw ParseException("bad section size, started at " + std::to_string(oldPos) + " plus payload " + std::to_string(payloadLen) + " not being equal to new position " + std::to_string(pos));
+ }
}
processFunctions();
@@ -1091,7 +1104,7 @@ WasmType WasmBinaryBuilder::getWasmType() {
case BinaryConsts::EncodedType::i64: return i64;
case BinaryConsts::EncodedType::f32: return f32;
case BinaryConsts::EncodedType::f64: return f64;
- default: abort();
+ default: throw ParseException("invalid wasm type: " + std::to_string(type));
}
}
@@ -1155,8 +1168,12 @@ void WasmBinaryBuilder::readMemory() {
if (debug) std::cerr << "== readMemory" << std::endl;
auto numMemories = getU32LEB();
if (!numMemories) return;
- assert(numMemories == 1);
- if (wasm.memory.exists) throw ParseException("Memory cannot be both imported and defined");
+ if (numMemories != 1) {
+ throw ParseException("Must be exactly 1 memory");
+ }
+ if (wasm.memory.exists) {
+ throw ParseException("Memory cannot be both imported and defined");
+ }
wasm.memory.exists = true;
getResizableLimits(wasm.memory.initial, wasm.memory.max, Memory::kMaxSize);
}
@@ -1169,8 +1186,9 @@ void WasmBinaryBuilder::readSignatures() {
if (debug) std::cerr << "read one" << std::endl;
auto curr = new FunctionType;
auto form = getS32LEB();
- WASM_UNUSED(form);
- assert(form == BinaryConsts::EncodedType::Func);
+ if (form != BinaryConsts::EncodedType::Func) {
+ throw ParseException("bad signature form " + std::to_string(form));
+ }
size_t numParams = getU32LEB();
if (debug) std::cerr << "num params: " << numParams << std::endl;
for (size_t j = 0; j < numParams; j++) {
@@ -1180,7 +1198,9 @@ void WasmBinaryBuilder::readSignatures() {
if (numResults == 0) {
curr->result = none;
} else {
- assert(numResults == 1);
+ if (numResults != 1) {
+ throw ParseException("signature must have 1 result");
+ }
curr->result = getWasmType();
}
curr->name = Name::fromInt(wasm.functionTypes.size());
@@ -1195,7 +1215,10 @@ Name WasmBinaryBuilder::getFunctionIndexName(Index i) {
return import->name;
} else {
i -= functionImportIndexes.size();
- return wasm.functions.at(i)->name;
+ if (i >= wasm.functions.size()) {
+ throw ParseException("bad function index");
+ }
+ return wasm.functions[i]->name;
}
}
@@ -1221,7 +1244,9 @@ void WasmBinaryBuilder::readImports() {
switch (curr->kind) {
case ExternalKind::Function: {
auto index = getU32LEB();
- assert(index < wasm.functionTypes.size());
+ if (index >= wasm.functionTypes.size()) {
+ throw ParseException("invalid function index " + std::to_string(index) + " / " + std::to_string(wasm.functionTypes.size()));
+ }
curr->functionType = wasm.functionTypes[index]->name;
assert(curr->functionType.is());
functionImportIndexes.push_back(curr->name);
@@ -1245,11 +1270,14 @@ void WasmBinaryBuilder::readImports() {
case ExternalKind::Global: {
curr->globalType = getWasmType();
auto globalMutable = getU32LEB();
- WASM_UNUSED(globalMutable);
- assert(!globalMutable);
+ if (globalMutable) {
+ throw ParseException("imported globals cannot be mutable");
+ }
break;
}
- default: WASM_UNREACHABLE();
+ default: {
+ throw ParseException("bad import kind");
+ }
}
wasm.addImport(curr);
}
@@ -1262,6 +1290,9 @@ void WasmBinaryBuilder::readFunctionSignatures() {
for (size_t i = 0; i < num; i++) {
if (debug) std::cerr << "read one" << std::endl;
auto index = getU32LEB();
+ if (index >= wasm.functionTypes.size()) {
+ throw ParseException("invalid function type index for function");
+ }
functionTypes.push_back(wasm.functionTypes[index].get());
}
}
@@ -1269,11 +1300,15 @@ void WasmBinaryBuilder::readFunctionSignatures() {
void WasmBinaryBuilder::readFunctions() {
if (debug) std::cerr << "== readFunctions" << std::endl;
size_t total = getU32LEB();
- assert(total == functionTypes.size());
+ if (total != functionTypes.size()) {
+ throw ParseException("invalid function section size, must equal types");
+ }
for (size_t i = 0; i < total; i++) {
if (debug) std::cerr << "read one at " << pos << std::endl;
size_t size = getU32LEB();
- assert(size > 0);
+ if (size == 0) {
+ throw ParseException("empty function size");
+ }
endOfFunction = pos + size;
auto type = functionTypes[i];
if (debug) std::cerr << "reading " << i << std::endl;
@@ -1317,8 +1352,12 @@ void WasmBinaryBuilder::readFunctions() {
assert(depth == 0);
assert(breakStack.size() == 1);
breakStack.pop_back();
- assert(expressionStack.empty());
- assert(pos == endOfFunction);
+ if (!expressionStack.empty()) {
+ throw ParseException("stack not empty on function exit");
+ }
+ if (pos != endOfFunction) {
+ throw ParseException("binary offset at function exit not at expected location");
+ }
if (breaksToReturn) {
// we broke to return, so we need an outer block to break to
func->body = Builder(wasm).blockifyWithName(func->body, RETURN_BREAK);
@@ -1334,10 +1373,15 @@ void WasmBinaryBuilder::readExports() {
if (debug) std::cerr << "== readExports" << std::endl;
size_t num = getU32LEB();
if (debug) std::cerr << "num: " << num << std::endl;
+ std::set<Name> names;
for (size_t i = 0; i < num; i++) {
if (debug) std::cerr << "read one" << std::endl;
auto curr = new Export;
curr->name = getInlineString();
+ if (names.count(curr->name) > 0) {
+ throw ParseException("duplicate export name");
+ }
+ names.insert(curr->name);
curr->kind = (ExternalKind)getU32LEB();
auto index = getU32LEB();
exportIndexes[curr] = index;
@@ -1348,7 +1392,9 @@ void WasmBinaryBuilder::readExports() {
Expression* WasmBinaryBuilder::readExpression() {
assert(depth == 0);
processExpressions();
- assert(expressionStack.size() == 1);
+ if (expressionStack.size() != 1) {
+ throw ParseException("expected to read a single expression");
+ }
auto* ret = popExpression();
assert(depth == 0);
return ret;
@@ -1384,7 +1430,9 @@ void WasmBinaryBuilder::processExpressions() { // until an end or else marker, o
}
Expression* WasmBinaryBuilder::popExpression() {
- assert(expressionStack.size() > 0);
+ if (expressionStack.empty()) {
+ throw ParseException("attempted pop from empty stack");
+ }
auto ret = expressionStack.back();
expressionStack.pop_back();
return ret;
@@ -1409,6 +1457,9 @@ Expression* WasmBinaryBuilder::popNonVoidExpression() {
expressions.pop_back();
}
auto type = block->list[0]->type;
+ if (!currFunction) {
+ throw ParseException("popping void outside of function, where we need a new local");
+ }
auto local = builder.addVar(currFunction, type);
block->list[0] = builder.makeSetLocal(local, block->list[0]);
block->list.push_back(builder.makeGetLocal(local, type));
@@ -1430,7 +1481,9 @@ Name WasmBinaryBuilder::getGlobalName(Index index) {
}
}
if (index == Index(-1)) return Name("null"); // just a force-rebuild
- assert(mappedGlobals.count(index));
+ if (mappedGlobals.count(index) == 0) {
+ throw ParseException("bad global index");
+ }
return mappedGlobals[index];
}
@@ -1454,7 +1507,7 @@ void WasmBinaryBuilder::processFunctions() {
case ExternalKind::Table: curr->value = Name::fromInt(0); break;
case ExternalKind::Memory: curr->value = Name::fromInt(0); break;
case ExternalKind::Global: curr->value = getGlobalName(index); break;
- default: WASM_UNREACHABLE();
+ default: throw ParseException("bad export kind");
}
wasm.addExport(curr);
}
@@ -1482,7 +1535,9 @@ void WasmBinaryBuilder::readDataSegments() {
for (size_t i = 0; i < num; i++) {
auto memoryIndex = getU32LEB();
WASM_UNUSED(memoryIndex);
- assert(memoryIndex == 0); // Only one linear memory in the MVP
+ if (memoryIndex != 0) {
+ throw ParseException("bad memory index, must be 0");
+ }
Memory::Segment curr;
auto offset = readExpression();
auto size = getU32LEB();
@@ -1542,17 +1597,27 @@ void WasmBinaryBuilder::readNames(size_t payloadLen) {
if (import->kind != ExternalKind::Function) continue;
importedFunctions++;
}
+ std::set<Name> functionNames;
for (size_t i = 0; i < num; i++) {
auto index = getU32LEB();
if (index < importedFunctions) {
getInlineString(); // TODO: use this
} else if (index - importedFunctions < functions.size()) {
- functions[index - importedFunctions]->name = getInlineString();
+ auto name = getInlineString();
+ functions[index - importedFunctions]->name = name;
+ if (functionNames.count(name) > 0) {
+ throw ParseException("duplicate function names");
+ }
+ functionNames.insert(name);
}
}
- assert(pos == subsectionPos + subsectionSize);
+ if (pos != subsectionPos + subsectionSize) {
+ throw ParseException("bad names subsection position change");
+ }
+ }
+ if (pos != sectionPos + payloadLen) {
+ throw ParseException("bad names section position change");
}
- assert(pos == sectionPos + payloadLen);
}
BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
@@ -1591,8 +1656,7 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
if (maybeVisitLoad(curr, code)) break;
if (maybeVisitStore(curr, code)) break;
if (maybeVisitHost(curr, code)) break;
- std::cerr << "bad code 0x" << std::hex << (int)code << std::endl;
- abort();
+ throw ParseException("bad node code " + std::to_string(code));
}
}
if (debug) std::cerr << "zz recurse from " << depth-- << " at " << pos << std::endl;
@@ -1631,7 +1695,9 @@ void WasmBinaryBuilder::visitBlock(Block *curr) {
last = curr;
processExpressions();
size_t end = expressionStack.size();
- assert(end >= start);
+ if (end < start) {
+ throw ParseException("block cannot pop from outside");
+ }
for (size_t i = start; i < end; i++) {
if (debug) std::cerr << " " << size_t(expressionStack[i]) << "\n zz Block element " << curr->list.size() << std::endl;
curr->list.push_back(expressionStack[i]);
@@ -1649,6 +1715,9 @@ Expression* WasmBinaryBuilder::getMaybeBlock(WasmType type) {
if (start - end == 1) {
return popExpression();
}
+ if (start > end) {
+ throw ParseException("block cannot pop from outside");
+ }
auto* block = allocator.alloc<Block>();
for (size_t i = start; i < end; i++) {
block->list.push_back(expressionStack[i]);
@@ -1677,7 +1746,9 @@ void WasmBinaryBuilder::visitIf(If *curr) {
curr->ifFalse = getBlock(curr->type);
}
curr->finalize(curr->type);
- assert(lastSeparator == BinaryConsts::End);
+ if (lastSeparator != BinaryConsts::End) {
+ throw ParseException("if should end with End");
+ }
}
void WasmBinaryBuilder::visitLoop(Loop *curr) {
@@ -1693,7 +1764,9 @@ void WasmBinaryBuilder::visitLoop(Loop *curr) {
WasmBinaryBuilder::BreakTarget WasmBinaryBuilder::getBreakTarget(int32_t offset) {
if (debug) std::cerr << "getBreakTarget " << offset << std::endl;
size_t index = breakStack.size() - 1 - offset;
- assert(index < breakStack.size());
+ if (index >= breakStack.size()) {
+ throw ParseException("bad breakindex");
+ }
if (index == 0) {
// trying to access the topmost element means we break out
// to the function scope, doing in effect a return, we'll
@@ -1745,7 +1818,9 @@ Expression* WasmBinaryBuilder::visitCall() {
// this is a call of a defined function
auto* call = allocator.alloc<Call>();
auto adjustedIndex = index - functionImportIndexes.size();
- assert(adjustedIndex < functionTypes.size());
+ if (adjustedIndex >= functionTypes.size()) {
+ throw ParseException("bad call index");
+ }
type = functionTypes[adjustedIndex];
fillCall(call, type);
functionCalls[adjustedIndex].push_back(call); // we don't know function names yet
@@ -1756,7 +1831,11 @@ Expression* WasmBinaryBuilder::visitCall() {
void WasmBinaryBuilder::visitCallIndirect(CallIndirect *curr) {
if (debug) std::cerr << "zz node: CallIndirect" << std::endl;
- auto* fullType = wasm.functionTypes.at(getU32LEB()).get();
+ auto index = getU32LEB();
+ if (index >= wasm.functionTypes.size()) {
+ throw ParseException("bad call_indirect function index");
+ }
+ auto* fullType = wasm.functionTypes[index].get();
auto reserved = getU32LEB();
if (reserved != 0) throw ParseException("Invalid flags field in call_indirect");
curr->fullType = fullType->name;
@@ -1771,15 +1850,25 @@ void WasmBinaryBuilder::visitCallIndirect(CallIndirect *curr) {
void WasmBinaryBuilder::visitGetLocal(GetLocal *curr) {
if (debug) std::cerr << "zz node: GetLocal " << pos << std::endl;
+ if (!currFunction) {
+ throw ParseException("get_local outside of function");
+ }
curr->index = getU32LEB();
- assert(curr->index < currFunction->getNumLocals());
+ if (curr->index >= currFunction->getNumLocals()) {
+ throw ParseException("bad get_local index");
+ }
curr->type = currFunction->getLocalType(curr->index);
}
void WasmBinaryBuilder::visitSetLocal(SetLocal *curr, uint8_t code) {
if (debug) std::cerr << "zz node: Set|TeeLocal" << std::endl;
+ if (!currFunction) {
+ throw ParseException("set_local outside of function");
+ }
curr->index = getU32LEB();
- assert(curr->index < currFunction->getNumLocals());
+ if (curr->index >= currFunction->getNumLocals()) {
+ throw ParseException("bad set_local index");
+ }
curr->value = popNonVoidExpression();
curr->type = curr->value->type;
curr->setTee(code == BinaryConsts::TeeLocal);
@@ -2014,6 +2103,9 @@ void WasmBinaryBuilder::visitSelect(Select *curr) {
void WasmBinaryBuilder::visitReturn(Return *curr) {
if (debug) std::cerr << "zz node: Return" << std::endl;
+ if (!currFunction) {
+ throw ParseException("return outside of function");
+ }
if (currFunction->result != none) {
curr->value = popNonVoidExpression();
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 0263b2112..2290a4972 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -48,7 +48,7 @@ Element::List& Element::list() {
}
Element* Element::operator[](unsigned i) {
- if (i >= list().size()) element_assert(0 && "expected more elements in list");
+ if (i >= list().size()) throw ParseException("expected more elements in list", line, col);
return list()[i];
}
@@ -114,8 +114,10 @@ Element* SExpressionParser::parse() {
} else if (input[0] == ')') {
input++;
auto last = curr;
+ if (stack.empty()) {
+ throw ParseException("s-expr stack empty");
+ }
curr = stack.back();
- assert(stack.size());
stack.pop_back();
curr->list().push_back(last);
} else {