From 295dcc7ce276a132d6d37c860e47256e82b8e13a Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Mon, 3 Aug 2020 17:06:08 -0700 Subject: [PATCH 1/5] Fix WAVM support. Signed-off-by: John Plevyak --- src/wasm.cc | 4 +- src/wavm/wavm.cc | 141 +++++++++++++++++++++++++++-------------------- 2 files changed, 85 insertions(+), 60 deletions(-) diff --git a/src/wasm.cc b/src/wasm.cc index a874d1ac..30576b63 100644 --- a/src/wasm.cc +++ b/src/wasm.cc @@ -317,7 +317,9 @@ bool WasmBase::initialize(const std::string &code, bool allow_precompiled) { if (started_from_ != Cloneable::InstantiatedModule) { registerCallbacks(); - wasm_vm_->link(vm_id_); + if (!wasm_vm_->link(vm_id_)) { + return false; + } } vm_context_.reset(createVmContext()); diff --git a/src/wavm/wavm.cc b/src/wavm/wavm.cc index 03c9f299..2a19f937 100644 --- a/src/wavm/wavm.cc +++ b/src/wavm/wavm.cc @@ -15,7 +15,9 @@ #include "include/proxy-wasm/wavm.h" +#include #include +#include #include #include #include @@ -43,8 +45,16 @@ #include "WAVM/Runtime/Runtime.h" #include "WAVM/WASM/WASM.h" #include "WAVM/WASTParse/WASTParse.h" -#include "absl/container/node_hash_map.h" -#include "absl/strings/match.h" + +#ifdef NDEBUG +#define ASSERT(_X) _x +#else +#define ASSERT(_x) \ + do { \ + if (!_x) \ + ::exit(1); \ + } while (0) +#endif using namespace WAVM; using namespace WAVM::IR; @@ -74,15 +84,21 @@ struct Wavm; namespace { -#define CALL_WITH_CONTEXT(_x, _context) \ +#define CALL_WITH_CONTEXT(_x, _context, _wavm) \ do { \ - SaveRestoreContext _saved_context(static_cast(_context)); \ - WAVM::Runtime::catchRuntimeExceptions([&] { _x; }, \ - [&](WAVM::Runtime::Exception *exception) { \ - auto description = describeException(exception); \ - destroyException(exception); \ - throw WasmException(description); \ - }); \ + try { \ + SaveRestoreContext _saved_context(static_cast(_context)); \ + WAVM::Runtime::catchRuntimeExceptions( \ + [&] { _x; }, \ + [&](WAVM::Runtime::Exception *exception) { \ + auto description = describeException(exception); \ + _wavm->fail(FailState::RuntimeError, \ + "Function: " + std::string(function_name) + " failed: " + description); \ + destroyException(exception); \ + throw std::exception(); \ + }); \ + } catch (...) { \ + } \ } while (0) struct WasmUntaggedValue : public WAVM::IR::UntaggedValue { @@ -96,11 +112,9 @@ struct WasmUntaggedValue : public WAVM::IR::UntaggedValue { WasmUntaggedValue(F64 inF64) { f64 = inF64; } }; -const Logger::Id wasmId = Logger::Id::wasm; - -class RootResolver : public WAVM::Runtime::Resolver, public Logger::Loggable { +class RootResolver : public WAVM::Runtime::Resolver { public: - RootResolver(WAVM::Runtime::Compartment *, WavmVm *vm) : vm_(vm) {} + RootResolver(WAVM::Runtime::Compartment *, WasmVm *vm) : vm_(vm) {} virtual ~RootResolver() { module_name_to_instance_map_.clear(); } @@ -113,10 +127,12 @@ class RootResolver : public WAVM::Runtime::Resolver, public Logger::Loggableerror("Failed to load WASM module due to a type mismatch in an import: " + - std::string(module_name) + "." + export_name + " " + - asString(WAVM::Runtime::getExternType(out_object)) + - " but was expecting type: " + asString(type)); + vm_->fail(FailState::UnableToInitializeCode, + "Failed to load WASM module due to a type mismatch in an import: " + + std::string(module_name) + "." + export_name + " " + + asString(WAVM::Runtime::getExternType(out_object)) + + " but was expecting type: " + asString(type)); + return false; } } } @@ -125,19 +141,21 @@ class RootResolver : public WAVM::Runtime::Resolver, public Logger::Loggableerror("Failed to load Wasm module due to a missing import: " + std::string(module_name) + - "." + std::string(export_name) + " " + asString(type)); + vm_->fail(FailState::MissingFunction, + "Failed to load Wasm module due to a missing import: " + std::string(module_name) + + "." + std::string(export_name) + " " + asString(type)); + return false; } - HashMap &moduleNameToInstanceMap() { + HashMap &moduleNameToInstanceMap() { return module_name_to_instance_map_; } void addResolver(WAVM::Runtime::Resolver *r) { resolvers_.push_back(r); } private: - WavmVm *vm_; - HashMap module_name_to_instance_map_; + WasmVm *vm_; + HashMap module_name_to_instance_map_; std::vector resolvers_; }; @@ -173,16 +191,16 @@ struct PairHash { } }; -struct Wavm : public WasmVmBase { - Wavm(Stats::ScopeSharedPtr scope) : WasmVmBase(scope, WasmRuntimeNames::get().Wavm) {} +struct Wavm : public WasmVm { + Wavm() : WasmVm() {} ~Wavm() override; // WasmVm - std::string_view runtime() override { return WasmRuntimeNames::get().Wavm; } + std::string_view runtime() override { return "wavm"; } Cloneable cloneable() override { return Cloneable::InstantiatedModule; }; std::unique_ptr clone() override; bool load(const std::string &code, bool allow_precompiled) override; - void link(std::string_view debug_name) override; + bool link(std::string_view debug_name) override; uint64_t getMemorySize() override; std::optional getMemory(uint64_t pointer, uint64_t size) override; bool setMemory(uint64_t pointer, uint64_t size, const void *data) override; @@ -209,12 +227,12 @@ struct Wavm : public WasmVmBase { bool has_instantiated_module_ = false; IR::Module ir_module_; WAVM::Runtime::ModuleRef module_ = nullptr; - WAVM::Runtime::GCPointer module_instance_; + WAVM::Runtime::GCPointer module_instance_; WAVM::Runtime::Memory *memory_; WAVM::Runtime::GCPointer compartment_; WAVM::Runtime::GCPointer context_; - node_hash_map intrinsic_modules_; - node_hash_map> + std::map intrinsic_modules_; + std::map> intrinsic_module_instances_; std::vector> envoyFunctions_; uint8_t *memory_base_ = nullptr; @@ -232,7 +250,7 @@ Wavm::~Wavm() { } std::unique_ptr Wavm::clone() { - auto wavm = std::make_unique(scope_); + auto wavm = std::make_unique(); wavm->compartment_ = WAVM::Runtime::cloneCompartment(compartment_); wavm->memory_ = WAVM::Runtime::remapToClonedCompartment(memory_, wavm->compartment_); wavm->memory_base_ = WAVM::Runtime::getMemoryBaseAddress(wavm->memory_); @@ -272,8 +290,8 @@ bool Wavm::load(const std::string &code, bool allow_precompiled) { return true; } -void Wavm::link(std::string_view debug_name) { - RootResolver rootResolver(compartment_); +bool Wavm::link(std::string_view debug_name) { + RootResolver rootResolver(compartment_, this); for (auto &p : intrinsic_modules_) { auto instance = Intrinsics::instantiateModule(compartment_, {&intrinsic_modules_[p.first]}, std::string(p.first)); @@ -281,10 +299,18 @@ void Wavm::link(std::string_view debug_name) { rootResolver.moduleNameToInstanceMap().set(p.first, instance); } WAVM::Runtime::LinkResult link_result = linkModule(ir_module_, rootResolver); + if (!link_result.missingImports.empty()) { + for (auto &i : link_result.missingImports) { + error("Missing Wasm import " + i.moduleName + " " + i.exportName); + } + fail(FailState::MissingFunction, "Failed to load Wasm module due to a missing import(s)"); + return false; + } module_instance_ = instantiateModule( compartment_, module_, std::move(link_result.resolvedImports), std::string(debug_name)); memory_ = getDefaultMemory(module_instance_); memory_base_ = WAVM::Runtime::getMemoryBaseAddress(memory_); + return true; } uint64_t Wavm::getMemorySize() { return WAVM::Runtime::getMemoryNumPages(memory_) * WasmPageSize; } @@ -324,7 +350,7 @@ bool Wavm::setWord(uint64_t pointer, Word data) { return setMemory(pointer, sizeof(uint32_t), &data32); } -std::string_view Wavm::getCustomSection(string_view name) { +std::string_view Wavm::getCustomSection(std::string_view name) { for (auto §ion : ir_module_.customSections) { if (section.name == name) { return {reinterpret_cast(section.data.data()), section.data.size()}; @@ -335,12 +361,10 @@ std::string_view Wavm::getCustomSection(string_view name) { std::string_view Wavm::getPrecompiledSectionName() { return "wavm.precompiled_object"; } -std::unique_ptr createVm(Stats::ScopeSharedPtr scope) { - return std::make_unique(scope); -} - } // namespace Wavm +std::unique_ptr createWavmVm() { return std::make_unique(); } + template IR::FunctionType inferEnvoyFunctionType(R (*)(void *, Args...)) { return IR::FunctionType(IR::inferResultType(), IR::TypeTuple({IR::inferValueType()...}), @@ -352,10 +376,10 @@ using namespace Wavm; template void registerCallbackWavm(WasmVm *vm, std::string_view module_name, std::string_view function_name, R (*f)(Args...)) { - auto wavm = static_cast(vm); - wavm->envoyFunctions_.emplace_back( - new Intrinsics::Function(&wavm->intrinsic_modules_[module_name], function_name.data(), - reinterpret_cast(f), inferEnvoyFunctionType(f))); + auto wavm = static_cast(vm); + wavm->envoyFunctions_.emplace_back(new Intrinsics::Function( + &wavm->intrinsic_modules_[std::string(module_name)], function_name.data(), + reinterpret_cast(f), inferEnvoyFunctionType(f))); } template void registerCallbackWavm(WasmVm *vm, std::string_view module_name, @@ -450,7 +474,7 @@ static bool checkFunctionType(WAVM::Runtime::Function *f, IR::FunctionType t) { template void getFunctionWavmReturn(WasmVm *vm, std::string_view function_name, std::function *function, uint32_t) { - auto wavm = static_cast(vm); + auto wavm = static_cast(vm); auto f = asFunctionNullable(getInstanceExport(wavm->module_instance_, std::string(function_name))); if (!f) @@ -460,18 +484,19 @@ void getFunctionWavmReturn(WasmVm *vm, std::string_view function_name, return; } if (!checkFunctionType(f, inferStdFunctionType(function))) { - error("Bad function signature for: " + std::string(function_name)); + wavm->fail(FailState::UnableToInitializeCode, + "Bad function signature for: " + std::string(function_name)); } - *function = [wavm, f, function_name, this](ContextBase *context, Args... args) -> R { + *function = [wavm, f, function_name](ContextBase *context, Args... args) -> R { WasmUntaggedValue values[] = {args...}; WasmUntaggedValue return_value; - try { - CALL_WITH_CONTEXT( - invokeFunction(wavm->context_, f, getFunctionType(f), &values[0], &return_value), - context); + CALL_WITH_CONTEXT( + invokeFunction(wavm->context_, f, getFunctionType(f), &values[0], &return_value), context, + wavm); + if (!wavm->isFailed()) { return static_cast(return_value.i32); - } catch (const std::exception &e) { - error("Function: " + std::string(function_name) + " failed: " + e.what()); + } else { + return 0; } }; } @@ -481,7 +506,7 @@ struct Void {}; template void getFunctionWavmReturn(WasmVm *vm, std::string_view function_name, std::function *function, Void) { - auto wavm = static_cast(vm); + auto wavm = static_cast(vm); auto f = asFunctionNullable(getInstanceExport(wavm->module_instance_, std::string(function_name))); if (!f) @@ -491,15 +516,13 @@ void getFunctionWavmReturn(WasmVm *vm, std::string_view function_name, return; } if (!checkFunctionType(f, inferStdFunctionType(function))) { - vm->error("Bad function signature for: " + std::string(function_name)); + wavm->fail(FailState::UnableToInitializeCode, + "Bad function signature for: " + std::string(function_name)); } - *function = [wavm, f, function_name, this](ContextBase *context, Args... args) -> R { + *function = [wavm, f, function_name](ContextBase *context, Args... args) -> R { WasmUntaggedValue values[] = {args...}; - try { - CALL_WITH_CONTEXT(invokeFunction(wavm->context_, f, getFunctionType(f), &values[0]), context); - } catch (const std::exception &e) { - error("Function: " + std::string(function_name) + " failed: " + e.what()); - } + CALL_WITH_CONTEXT(invokeFunction(wavm->context_, f, getFunctionType(f), &values[0]), context, + wavm); }; } From 5262959b046819120c7a2ad529de243ccf704888 Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Mon, 3 Aug 2020 17:10:42 -0700 Subject: [PATCH 2/5] Fix NDEBUG ASSERT. Signed-off-by: John Plevyak --- src/wavm/wavm.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wavm/wavm.cc b/src/wavm/wavm.cc index 2a19f937..4dbfc16d 100644 --- a/src/wavm/wavm.cc +++ b/src/wavm/wavm.cc @@ -47,7 +47,7 @@ #include "WAVM/WASTParse/WASTParse.h" #ifdef NDEBUG -#define ASSERT(_X) _x +#define ASSERT(_x) _x #else #define ASSERT(_x) \ do { \ From f2ac72085f01efad7427149aea1034f24f61029c Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Tue, 4 Aug 2020 12:36:57 -0700 Subject: [PATCH 3/5] Fix getAbiVersion. Signed-off-by: John Plevyak --- src/wavm/wavm.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/wavm/wavm.cc b/src/wavm/wavm.cc index 815b21e5..2a6cee49 100644 --- a/src/wavm/wavm.cc +++ b/src/wavm/wavm.cc @@ -208,6 +208,7 @@ struct Wavm : public WasmVm { bool setWord(uint64_t pointer, Word data) override; std::string_view getCustomSection(std::string_view name) override; std::string_view getPrecompiledSectionName() override; + AbiVersion getAbiVersion() override; #define _GET_FUNCTION(_T) \ void getFunction(std::string_view function_name, _T *f) override { \ @@ -291,16 +292,18 @@ bool Wavm::load(const std::string &code, bool allow_precompiled) { } AbiVersion Wavm::getAbiVersion() { - if (asFunctionNullable(getInstanceExport(module_instance_, "proxy_abi_version_0_1_0")) { - return AbiVersion::ProxyWasm_0_1_0; - } - if (asFunctionNullable(getInstanceExport(module_instance_, "proxy_abi_version_0_2_0)")) { - return AbiVersion::ProxyWasm_0_2_0; + for (auto &e : ir_module_.exports) { + if (e.name == "proxy_abi_version_0_1_0") { + return AbiVersion::ProxyWasm_0_1_0; + } + if (e.name == "proxy_abi_version_0_2_0") { + return AbiVersion::ProxyWasm_0_2_0; + } } return AbiVersion::Unknown; } -void Wavm::link(std::string_view debug_name) { +bool Wavm::link(std::string_view debug_name) { RootResolver rootResolver(compartment_, this); for (auto &p : intrinsic_modules_) { auto instance = Intrinsics::instantiateModule(compartment_, {&intrinsic_modules_[p.first]}, From fff03bca20cd5335c8f43f098d6da88e90afdde0 Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Tue, 4 Aug 2020 13:40:57 -0700 Subject: [PATCH 4/5] Cache ABI version. Signed-off-by: John Plevyak --- src/wavm/wavm.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/wavm/wavm.cc b/src/wavm/wavm.cc index 2a6cee49..b4b48156 100644 --- a/src/wavm/wavm.cc +++ b/src/wavm/wavm.cc @@ -237,6 +237,7 @@ struct Wavm : public WasmVm { intrinsic_module_instances_; std::vector> envoyFunctions_; uint8_t *memory_base_ = nullptr; + AbiVersion abi_version_ = AbiVersion::Unknown; }; Wavm::~Wavm() { @@ -256,6 +257,7 @@ std::unique_ptr Wavm::clone() { wavm->memory_ = WAVM::Runtime::remapToClonedCompartment(memory_, wavm->compartment_); wavm->memory_base_ = WAVM::Runtime::getMemoryBaseAddress(wavm->memory_); wavm->context_ = WAVM::Runtime::createContext(wavm->compartment_); + wavm->abi_version_ = abi_version_; for (auto &p : intrinsic_module_instances_) { wavm->intrinsic_module_instances_.emplace( p.first, WAVM::Runtime::remapToClonedCompartment(p.second, wavm->compartment_)); @@ -273,7 +275,7 @@ bool Wavm::load(const std::string &code, bool allow_precompiled) { if (!loadModule(code, ir_module_)) { return false; } - // todo check percompiled section is permitted + getAbiVersion(); // Cache ABI version. const CustomSection *precompiled_object_section = nullptr; if (allow_precompiled) { for (const CustomSection &customSection : ir_module_.customSections) { @@ -292,12 +294,17 @@ bool Wavm::load(const std::string &code, bool allow_precompiled) { } AbiVersion Wavm::getAbiVersion() { + if (abi_version_ != AbiVersion::Unknown) { + return abi_version_; + } for (auto &e : ir_module_.exports) { if (e.name == "proxy_abi_version_0_1_0") { - return AbiVersion::ProxyWasm_0_1_0; + abi_version_ = AbiVersion::ProxyWasm_0_1_0; + return abi_version_; } if (e.name == "proxy_abi_version_0_2_0") { - return AbiVersion::ProxyWasm_0_2_0; + abi_version_ = AbiVersion::ProxyWasm_0_2_0; + return abi_version_; } } return AbiVersion::Unknown; From 83dd01f064a9c84cce67188580290a34d4fb560b Mon Sep 17 00:00:00 2001 From: John Plevyak Date: Wed, 5 Aug 2020 10:32:29 -0700 Subject: [PATCH 5/5] Add 0.2.1 test. Signed-off-by: John Plevyak --- src/wavm/wavm.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wavm/wavm.cc b/src/wavm/wavm.cc index b4b48156..d6b6b67a 100644 --- a/src/wavm/wavm.cc +++ b/src/wavm/wavm.cc @@ -306,6 +306,10 @@ AbiVersion Wavm::getAbiVersion() { abi_version_ = AbiVersion::ProxyWasm_0_2_0; return abi_version_; } + if (e.name == "proxy_abi_version_0_2_1") { + abi_version_ = AbiVersion::ProxyWasm_0_2_1; + return abi_version_; + } } return AbiVersion::Unknown; }