From d537e0656717ee53040529cb3006b6cd24becd67 Mon Sep 17 00:00:00 2001 From: Gorog Peter Date: Fri, 14 Jul 2023 12:50:45 +0200 Subject: [PATCH] Print error message - fix 2 typos (uint16_t to Walrus::ByteCodeStackOffset) - fix 1 typo (because of it 3 tests failed, altough it was unnoticable hence the error wasn't caught) - refactor nested if...else to switch...case - print error message before exit - make string() operator for Value class --- src/parser/WASMParser.cpp | 4 +- src/runtime/Module.cpp | 2 +- src/runtime/Value.h | 20 ++++ src/shell/Shell.cpp | 200 +++++++++++++++++++++++++++++--------- 4 files changed, 177 insertions(+), 49 deletions(-) diff --git a/src/parser/WASMParser.cpp b/src/parser/WASMParser.cpp index f63aab79f..c25302a31 100644 --- a/src/parser/WASMParser.cpp +++ b/src/parser/WASMParser.cpp @@ -1338,7 +1338,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { ASSERT(peekVMStackSize() == Walrus::valueSizeInStack(toValueKind(Type::I32))); auto stackPos = popVMStack(); size_t pos = m_currentFunction->currentByteCodeSize(); - pushByteCode(Walrus::JumpIfFalse(stackPos, sizeof(Walrus::JumpIfFalse) + sizeof(Walrus::End) + sizeof(uint16_t) * m_currentFunctionType->result().size()), WASMOpcode::BrIfOpcode); + pushByteCode(Walrus::JumpIfFalse(stackPos, sizeof(Walrus::JumpIfFalse) + sizeof(Walrus::End) + sizeof(Walrus::ByteCodeStackOffset) * m_currentFunctionType->result().size()), WASMOpcode::BrIfOpcode); for (size_t i = 0; i < m_currentFunctionType->result().size(); i++) { ASSERT((m_vmStack.rbegin() + i)->m_size == Walrus::valueSizeInStack(m_currentFunctionType->result()[m_currentFunctionType->result().size() - i - 1])); } @@ -1458,7 +1458,7 @@ class WASMBinaryReader : public wabt::WASMBinaryReaderDelegate { if (tagIndex != std::numeric_limits::max()) { auto functionType = m_result.m_functionTypes[m_result.m_tagTypes[tagIndex]->sigIndex()]; auto& param = functionType->param(); - m_currentFunction->expandByteCode(sizeof(uint16_t) * param.size()); + m_currentFunction->expandByteCode(sizeof(Walrus::ByteCodeStackOffset) * param.size()); Walrus::Throw* code = m_currentFunction->peekByteCode(pos); for (size_t i = 0; i < param.size(); i++) { code->dataOffsets()[param.size() - i - 1] = (m_vmStack.rbegin() + i)->m_position; diff --git a/src/runtime/Module.cpp b/src/runtime/Module.cpp index 5d757137a..eea7051ea 100644 --- a/src/runtime/Module.cpp +++ b/src/runtime/Module.cpp @@ -282,7 +282,7 @@ Instance* Module::instantiate(ExecutionState& state, const ExternVector& imports &data); } - if (UNLIKELY(elem->tableIndex() >= numberOfTableTypes() || index >= instance->m_tables[elem->tableIndex()]->size() || index + elem->functionIndex().size() > instance->m_tables[elem->tableIndex()]->size())) { + if (UNLIKELY(elem->tableIndex() >= numberOfTableTypes() || index > instance->m_tables[elem->tableIndex()]->size() || index + elem->functionIndex().size() > instance->m_tables[elem->tableIndex()]->size())) { Trap::throwException(state, "out of bounds table access"); } diff --git a/src/runtime/Value.h b/src/runtime/Value.h index a1eacbb65..c0609dc0e 100644 --- a/src/runtime/Value.h +++ b/src/runtime/Value.h @@ -356,6 +356,26 @@ class Value { return false; } + operator std::string() const + { + switch (m_type) { + case I32: + return std::to_string(asI32()); + case I64: + return std::to_string(asI64()); + case F32: + return std::to_string(asF32()); + case F64: + return std::to_string(asF64()); + case FuncRef: + case ExternRef: + return std::to_string((size_t)(asExternal())); + default: + ASSERT_NOT_REACHED(); + return ""; + } + } + private: union { int32_t m_i32; diff --git a/src/shell/Shell.cpp b/src/shell/Shell.cpp index 92934fe0b..9cb0e12c1 100644 --- a/src/shell/Shell.cpp +++ b/src/shell/Shell.cpp @@ -346,19 +346,30 @@ static Trap::TrapResult executeWASM(Store* store, const std::string& filename, c if (iter != registeredInstanceMap->end()) { Instance* instance = iter->second; auto e = instance->resolveExportType(import->fieldName()); - RELEASE_ASSERT(e); - if (e->exportType() == ExportType::Function) { + if (e == nullptr) { + printf("Error: %s:%s module has not been found.\n", import->fieldName().c_str(), import->moduleName().c_str()); + ASSERT_NOT_REACHED(); + } + switch (e->exportType()) { + case ExportType::Function: importValues.push_back(instance->resolveExportFunction(import->fieldName())); - } else if (e->exportType() == ExportType::Tag) { + break; + case ExportType::Tag: importValues.push_back(instance->resolveExportTag(import->fieldName())); - } else if (e->exportType() == ExportType::Table) { + break; + case ExportType::Table: importValues.push_back(instance->resolveExportTable(import->fieldName())); - } else if (e->exportType() == ExportType::Memory) { + break; + case ExportType::Memory: importValues.push_back(instance->resolveExportMemory(import->fieldName())); - } else if (e->exportType() == ExportType::Global) { + break; + case ExportType::Global: importValues.push_back(instance->resolveExportGlobal(import->fieldName())); - } else { - RELEASE_ASSERT_NOT_REACHED(); + break; + default: + printf("Error: unsupported export type: %s\n", import->moduleName().c_str()); + ASSERT_NOT_REACHED(); + break; } } } @@ -427,7 +438,9 @@ static Walrus::Value toWalrusValue(wabt::Const& c) return Walrus::Value(Walrus::Value::ExternRef, c.ref_bits() + 1, Walrus::Value::Force); } default: - RELEASE_ASSERT_NOT_REACHED(); + printf("Error: unknown value type during converting wabt::Const to wabt::Value\n"); + ASSERT_NOT_REACHED(); + return Walrus::Value(); } } @@ -555,11 +568,16 @@ static void printConstVector(wabt::ConstVector& v) { for (size_t i = 0; i < v.size(); i++) { auto c = v[i]; - if (c.type() == wabt::Type::I32) { + switch (c.type()) { + case wabt::Type::I32: { printf("%" PRIu32, c.u32()); - } else if (c.type() == wabt::Type::I64) { + break; + } + case wabt::Type::I64: { printf("%" PRIu64, c.u64()); - } else if (c.type() == wabt::Type::F32) { + break; + } + case wabt::Type::F32: { if (c.is_expected_nan(0)) { printf("nan"); return; @@ -568,7 +586,9 @@ static void printConstVector(wabt::ConstVector& v) auto bits = c.f32_bits(); memcpy(&s, &bits, sizeof(float)); printf("%f", s); - } else if (c.type() == wabt::Type::F64) { + break; + } + case wabt::Type::F64: { if (c.is_expected_nan(0)) { printf("nan"); return; @@ -577,7 +597,13 @@ static void printConstVector(wabt::ConstVector& v) auto bits = c.f64_bits(); memcpy(&s, &bits, sizeof(double)); printf("%lf", s); - } else if (c.type() == wabt::Type::ExternRef) { + break; + } + case wabt::Type::V128: { + printf("v128"); + break; + } + case wabt::Type::ExternRef: { // FIXME value of c.ref_bits() for RefNull wabt::Const constNull; constNull.set_null(c.type()); @@ -585,7 +611,9 @@ static void printConstVector(wabt::ConstVector& v) printf("ref.null"); return; } - } else if (c.type() == wabt::Type::FuncRef) { + break; + } + case wabt::Type::FuncRef: { // FIXME value of c.ref_bits() for RefNull wabt::Const constNull; constNull.set_null(c.type()); @@ -593,10 +621,13 @@ static void printConstVector(wabt::ConstVector& v) printf("ref.null"); return; } - } else if (c.type() == wabt::Type::V128) { - printf("v128"); - } else { - RELEASE_ASSERT_NOT_REACHED(); + break; + } + default: { + printf("Error: unkown wabt::Const type\n"); + ASSERT_NOT_REACHED(); + break; + } } if (i + 1 != v.size()) { printf(", "); @@ -607,7 +638,10 @@ static void printConstVector(wabt::ConstVector& v) static void executeInvokeAction(wabt::InvokeAction* action, Walrus::Function* fn, wabt::ConstVector expectedResult, const char* expectedException, bool expectUserException = false) { - RELEASE_ASSERT(fn->functionType()->param().size() == action->args.size()); + if (fn->functionType()->param().size() != action->args.size()) { + printf("Error: expected %zu parameter(s) but got %zu.\n", fn->functionType()->param().size(), action->args.size()); + ASSERT_NOT_REACHED(); + } Walrus::ValueVector args; for (auto& a : action->args) { args.push_back(toWalrusValue(a)); @@ -617,7 +651,8 @@ static void executeInvokeAction(wabt::InvokeAction* action, Walrus::Function* fn Walrus::Function* fn; wabt::ConstVector& expectedResult; Walrus::ValueVector& args; - } data = { fn, expectedResult, args }; + wabt::InvokeAction* action; + } data = { fn, expectedResult, args, action }; Walrus::Trap trap; auto trapResult = trap.run([](Walrus::ExecutionState& state, void* d) { RunData* data = reinterpret_cast(d); @@ -625,26 +660,51 @@ static void executeInvokeAction(wabt::InvokeAction* action, Walrus::Function* fn result.resize(data->expectedResult.size()); data->fn->call(state, data->args.size(), data->args.data(), result.data()); if (data->expectedResult.size()) { - RELEASE_ASSERT(data->fn->functionType()->result().size() == data->expectedResult.size()); + if (data->fn->functionType()->result().size() != data->expectedResult.size()) { + printf("Error: %s returned with %zu parameter(s) but expected %zu", data->action->name.data(), data->fn->functionType()->result().size(), data->expectedResult.size()); + ASSERT_NOT_REACHED(); + } // compare result for (size_t i = 0; i < result.size(); i++) { - RELEASE_ASSERT(equals(result[i], data->expectedResult[i])); + if (!equals(result[i], data->expectedResult[i])) { + printf("Assertion failed at %d: ", data->action->loc.line); + printf("%s(", data->action->name.data()); + printConstVector(data->action->args); + printf(") expected "); + printConstVector(data->expectedResult); + printf(", but got %s\n", ((std::string)result[i]).c_str()); + ASSERT_NOT_REACHED(); + } } } }, &data); if (expectedResult.size()) { - RELEASE_ASSERT(!trapResult.exception); + if (trapResult.exception != nullptr) { + printf("Error: %s\n", trapResult.exception->message().c_str()); + ASSERT_NOT_REACHED(); + } } if (expectedException) { - RELEASE_ASSERT(trapResult.exception); + if (trapResult.exception == nullptr) { + printf("Missing exception: %s\n", expectedException); + ASSERT_NOT_REACHED(); + } std::string& s = trapResult.exception->message(); - RELEASE_ASSERT(s.find(expectedException) == 0); + if (s.find(expectedException) != 0) { + printf("Error: different error message than expected!\n"); + printf("Expected: %s\n", expectedException); + printf("But got: %s\n", s.c_str()); + ASSERT_NOT_REACHED(); + } printf("invoke %s(", action->name.data()); printConstVector(action->args); printf("), expect exception: %s (line: %d) : OK\n", expectedException, action->loc.line); } else if (expectUserException) { - RELEASE_ASSERT(trapResult.exception->tag()); + if (trapResult.exception->tag() == nullptr) { + printf("Missing user exception: %s\n", action->name.data()); + ASSERT_NOT_REACHED(); + } printf("invoke %s(", action->name.data()); printConstVector(action->args); printf(") expect user exception() (line: %d) : OK\n", action->loc.line); @@ -681,9 +741,9 @@ static Instance* fetchInstance(wabt::Var& moduleVar, std::map static void executeWAST(Store* store, const std::string& filename, const std::vector& src, SpecTestFunctionTypes& functionTypes) { auto lexer = wabt::WastLexer::CreateBufferLexer("test.wabt", src.data(), src.size()); - if (!lexer) { - RELEASE_ASSERT_NOT_REACHED(); - return; + if (lexer == nullptr) { + printf("Error during lexer initialization!\n"); + ASSERT_NOT_REACHED(); } wabt::Errors errors; @@ -692,9 +752,12 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve features.EnableAll(); wabt::WastParseOptions parse_wast_options(features); auto result = wabt::ParseWastScript(lexer.get(), &script, &errors, &parse_wast_options); - if (!wabt::Succeeded(result)) { - RELEASE_ASSERT_NOT_REACHED(); - return; + if (wabt::Succeeded(result) == false) { + printf("Syntax error(s):\n"); + for (auto e : errors) + printf(" %s\n", e.message.c_str()); + printf("\n"); + ASSERT_NOT_REACHED(); } std::map instanceMap; @@ -706,7 +769,12 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve case wabt::CommandType::ScriptModule: { auto* moduleCommand = static_cast(command.get()); auto buf = readModuleData(&moduleCommand->module); - executeWASM(store, filename, buf->data, functionTypes, ®isteredInstanceMap); + auto trapResult = executeWASM(store, filename, buf->data, functionTypes, ®isteredInstanceMap); + if (trapResult.exception) { + std::string& errorMessage = trapResult.exception->message(); + printf("Error: %s\n", errorMessage.c_str()); + ASSERT_NOT_REACHED(); + } instanceMap[commandCount] = store->getLastInstance(); if (moduleCommand->module.name.size()) { registeredInstanceMap[moduleCommand->module.name] = store->getLastInstance(); @@ -716,7 +784,10 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve case wabt::CommandType::AssertReturn: { auto* assertReturn = static_cast(command.get()); auto value = fetchInstance(assertReturn->action->module_var, instanceMap, registeredInstanceMap)->resolveExportType(assertReturn->action->name); - RELEASE_ASSERT(value); + if (value == nullptr) { + printf("Undefined function: %s\n", assertReturn->action->name.c_str()); + ASSERT_NOT_REACHED(); + } if (assertReturn->action->type() == wabt::ActionType::Invoke) { auto action = static_cast(assertReturn->action.get()); auto fn = fetchInstance(action->module_var, instanceMap, registeredInstanceMap)->resolveExportFunction(action->name); @@ -724,12 +795,16 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve } else if (assertReturn->action->type() == wabt::ActionType::Get) { auto action = static_cast(assertReturn->action.get()); auto v = fetchInstance(action->module_var, instanceMap, registeredInstanceMap)->resolveExportGlobal(action->name)->value(); - RELEASE_ASSERT(equals(v, assertReturn->expected[0])) + if (equals(v, assertReturn->expected[0]) == false) { + printf("Assert failed.\n"); + ASSERT_NOT_REACHED(); + } printf("get %s", action->name.data()); printf(" expect value("); printConstVector(assertReturn->expected); printf(") (line: %d) : OK\n", action->loc.line); } else { + printf("Not supported action type.\n"); ASSERT_NOT_REACHED(); } break; @@ -737,7 +812,10 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve case wabt::CommandType::AssertTrap: { auto* assertTrap = static_cast(command.get()); auto value = fetchInstance(assertTrap->action->module_var, instanceMap, registeredInstanceMap)->resolveExportFunction(assertTrap->action->name); - RELEASE_ASSERT(value); + if (value == nullptr) { + printf("Error: fetchInstance returned with nullptr.\n"); + ASSERT_NOT_REACHED(); + } if (assertTrap->action->type() == wabt::ActionType::Invoke) { auto action = static_cast(assertTrap->action.get()); auto fn = fetchInstance(action->module_var, instanceMap, registeredInstanceMap)->resolveExportFunction(action->name); @@ -750,7 +828,10 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve case wabt::CommandType::AssertException: { auto* assertException = static_cast(command.get()); auto value = fetchInstance(assertException->action->module_var, instanceMap, registeredInstanceMap)->resolveExportFunction(assertException->action->name); - RELEASE_ASSERT(value); + if (value == nullptr) { + printf("Fetching instance failed (at wabt::CommandType::AssertException case)\n"); + ASSERT_NOT_REACHED(); + } if (assertException->action->type() == wabt::ActionType::Invoke) { auto action = static_cast(assertException->action.get()); auto fn = fetchInstance(action->module_var, instanceMap, registeredInstanceMap)->resolveExportFunction(action->name); @@ -764,11 +845,19 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve auto* assertModuleUninstantiable = static_cast*>(command.get()); auto m = assertModuleUninstantiable->module.get(); auto tsm = dynamic_cast(m); - RELEASE_ASSERT(tsm); + if (tsm == nullptr) { + printf("Error at casting to wabt::TextScriptModule*.\n"); + ASSERT_NOT_REACHED(); + } auto buf = readModuleData(&tsm->module); auto trapResult = executeWASM(store, filename, buf->data, functionTypes, ®isteredInstanceMap); std::string& s = trapResult.exception->message(); - RELEASE_ASSERT(s.find(assertModuleUninstantiable->text) == 0); + if (s.find(assertModuleUninstantiable->text) != 0) { + printf("Error: different error message than expected!\n"); + printf("Expected: %s\n", assertModuleUninstantiable->text.c_str()); + printf("But got: %s\n", s.c_str()); + ASSERT_NOT_REACHED(); + } printf("assertModuleUninstantiable (expect exception: %s(line: %d)) : OK\n", assertModuleUninstantiable->text.data(), assertModuleUninstantiable->module->location().line); break; } @@ -780,7 +869,10 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve case wabt::CommandType::Action: { auto* actionCommand = static_cast(command.get()); auto value = fetchInstance(actionCommand->action->module_var, instanceMap, registeredInstanceMap)->resolveExportFunction(actionCommand->action->name); - RELEASE_ASSERT(value); + if (value == nullptr) { + printf("Fetching instance failed (at wabt::CommandType::Action case)"); + ASSERT_NOT_REACHED(); + } if (actionCommand->action->type() == wabt::ActionType::Invoke) { auto action = static_cast(actionCommand->action.get()); auto fn = fetchInstance(action->module_var, instanceMap, registeredInstanceMap)->resolveExportFunction(action->name); @@ -795,7 +887,10 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve auto m = assertModuleInvalid->module.get(); auto tsm = dynamic_cast(m); auto dsm = dynamic_cast(m); - RELEASE_ASSERT(tsm || dsm); + if (!tsm && !dsm) { + printf("Module is neither TextScriptModule nor BinaryScriptModule.\n"); + ASSERT_NOT_REACHED(); + } std::vector buf; if (tsm) { buf = readModuleData(&tsm->module)->data; @@ -803,7 +898,10 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve buf = dsm->data; } auto trapResult = executeWASM(store, filename, buf, functionTypes); - RELEASE_ASSERT(trapResult.exception); + if (trapResult.exception == nullptr) { + printf("Execute WASM returned nullptr (in wabt::CommandType::AssertInvalid case)\n"); + RELEASE_ASSERT_NOT_REACHED(); + } std::string& actual = trapResult.exception->message(); printf("assertModuleInvalid (expect compile error: '%s', actual '%s'(line: %d)) : OK\n", assertModuleInvalid->text.data(), actual.data(), assertModuleInvalid->module->location().line); break; @@ -818,7 +916,11 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve auto m = assertUnlinkable->module.get(); auto tsm = dynamic_cast(m); auto dsm = dynamic_cast(m); - RELEASE_ASSERT(tsm || dsm); + if (!tsm && !dsm) { + printf("Both TextScriptModule* and BinaryScriptModule* castings failed (in wabt::CommandType::AssertUnlinkable case)\n"); + ASSERT_NOT_REACHED(); + } + std::vector buf; if (tsm) { buf = readModuleData(&tsm->module)->data; @@ -826,13 +928,19 @@ static void executeWAST(Store* store, const std::string& filename, const std::ve buf = dsm->data; } auto trapResult = executeWASM(store, filename, buf, functionTypes); - RELEASE_ASSERT(trapResult.exception); + if (trapResult.exception == nullptr) { + printf("Execute WASM returned nullptr (in wabt::CommandType::AssertUnlinkable case)\n"); + RELEASE_ASSERT_NOT_REACHED(); + } break; } case wabt::CommandType::AssertExhaustion: { auto* assertExhaustion = static_cast(command.get()); auto value = fetchInstance(assertExhaustion->action->module_var, instanceMap, registeredInstanceMap)->resolveExportFunction(assertExhaustion->action->name); - RELEASE_ASSERT(value); + if (value == nullptr) { + printf("Fetching instance failed (at wabt::CommandType::AssertExhaustion case)\n"); + ASSERT_NOT_REACHED(); + } if (assertExhaustion->action->type() == wabt::ActionType::Invoke) { auto action = static_cast(assertExhaustion->action.get()); auto fn = fetchInstance(action->module_var, instanceMap, registeredInstanceMap)->resolveExportFunction(action->name);