diff --git a/BUILD b/BUILD index 2f760f841..350eccbd2 100644 --- a/BUILD +++ b/BUILD @@ -25,10 +25,9 @@ cc_library( "src/*.h", "src/*.cc", "src/common/*.h", - "src/common/*.cc", + "src/null/*.cc", "src/third_party/*.h", "src/third_party/*.cc", - "src/null/*.cc", ]), deps = [ ":include", diff --git a/src/common/bytecode_util.h b/include/proxy-wasm/bytecode_util.h similarity index 98% rename from src/common/bytecode_util.h rename to include/proxy-wasm/bytecode_util.h index 438969fb5..1f4b600b2 100644 --- a/src/common/bytecode_util.h +++ b/include/proxy-wasm/bytecode_util.h @@ -20,7 +20,6 @@ #include "include/proxy-wasm/wasm_vm.h" namespace proxy_wasm { -namespace common { // Utilitiy functions which directly operate on Wasm bytecodes. class BytecodeUtil { @@ -73,5 +72,4 @@ class BytecodeUtil { static bool parseVarint(const char *&begin, const char *end, uint32_t &ret); }; -} // namespace common } // namespace proxy_wasm diff --git a/include/proxy-wasm/null_vm.h b/include/proxy-wasm/null_vm.h index a1a2f73d5..27e371389 100644 --- a/include/proxy-wasm/null_vm.h +++ b/include/proxy-wasm/null_vm.h @@ -35,8 +35,8 @@ struct NullVm : public WasmVm { std::string_view runtime() override { return "null"; } Cloneable cloneable() override { return Cloneable::InstantiatedModule; }; std::unique_ptr clone() override; - bool load(const std::string &code, bool allow_precompiled) override; - AbiVersion getAbiVersion() override; + bool load(std::string_view bytecode, std::string_view precompiled, + std::unordered_map function_names) override; bool link(std::string_view debug_name) override; uint64_t getMemorySize() override; std::optional getMemory(uint64_t pointer, uint64_t size) override; diff --git a/include/proxy-wasm/wasm.h b/include/proxy-wasm/wasm.h index e77b9b03d..9accb4c7b 100644 --- a/include/proxy-wasm/wasm.h +++ b/include/proxy-wasm/wasm.h @@ -58,7 +58,8 @@ class WasmBase : public std::enable_shared_from_this { WasmBase(const std::shared_ptr &other, WasmVmFactory factory); virtual ~WasmBase(); - bool initialize(const std::string &code, bool allow_precompiled = false); + bool load(const std::string &code, bool allow_precompiled = false); + bool initialize(); void startVm(ContextBase *root_context); bool configure(ContextBase *root_context, std::shared_ptr plugin); // Returns the root ContextBase or nullptr if onStart returns false. @@ -79,9 +80,11 @@ class WasmBase : public std::enable_shared_from_this { bool isFailed() { return failed_ != FailState::Ok; } FailState fail_state() { return failed_; } - const std::string &code() const { return code_; } const std::string &vm_configuration() const; - bool allow_precompiled() const { return allow_precompiled_; } + + const std::string &moduleBytecode() const { return module_bytecode_; } + const std::string &modulePrecompiled() const { return module_precompiled_; } + const std::unordered_map functionNames() const { return function_names_; } void timerReady(uint32_t root_context_id); void queueReady(uint32_t root_context_id, uint32_t token); @@ -135,7 +138,7 @@ class WasmBase : public std::enable_shared_from_this { virtual void error(std::string_view message) { std::cerr << message << "\n"; } virtual void unimplemented() { error("unimplemented proxy-wasm API"); } - AbiVersion abiVersion() { return abi_version_; } + AbiVersion abiVersion() const { return abi_version_; } const std::unordered_map &envs() { return envs_; } @@ -182,7 +185,7 @@ class WasmBase : public std::enable_shared_from_this { std::string vm_id_; // User-provided vm_id. std::string vm_key_; // vm_id + hash of code. std::unique_ptr wasm_vm_; - Cloneable started_from_{Cloneable::NotCloneable}; + std::optional started_from_; uint32_t next_context_id_ = 1; // 0 is reserved for the VM context. std::shared_ptr vm_context_; // Context unrelated to any specific root or stream @@ -260,15 +263,17 @@ class WasmBase : public std::enable_shared_from_this { std::shared_ptr base_wasm_handle_; // Used by the base_wasm to enable non-clonable thread local Wasm(s) to be constructed. - std::string code_; - std::string vm_configuration_; - bool allow_precompiled_ = false; - bool stop_iteration_ = false; - FailState failed_ = FailState::Ok; // Wasm VM fatal error. + std::string module_bytecode_; + std::string module_precompiled_; + std::unordered_map function_names_; // ABI version. AbiVersion abi_version_ = AbiVersion::Unknown; + std::string vm_configuration_; + bool stop_iteration_ = false; + FailState failed_ = FailState::Ok; // Wasm VM fatal error. + // Plugin Stats/Metrics uint32_t next_counter_metric_id_ = static_cast(MetricType::Counter); uint32_t next_gauge_metric_id_ = static_cast(MetricType::Gauge); diff --git a/include/proxy-wasm/wasm_vm.h b/include/proxy-wasm/wasm_vm.h index c794e6f4c..4e07086ed 100644 --- a/include/proxy-wasm/wasm_vm.h +++ b/include/proxy-wasm/wasm_vm.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "include/proxy-wasm/word.h" @@ -174,14 +175,13 @@ class WasmVm { * Load the WASM code from a file. Return true on success. Once the module is loaded it can be * queried, e.g. to see which version of emscripten support is required. After loading, the * appropriate ABI callbacks can be registered and then the module can be link()ed (see below). - * @param code the WASM binary code (or registered NullVm plugin name). - * @param allow_precompiled if true, allows supporting VMs (e.g. WAVM) to load the binary - * machine code from a user-defined section of the WASM file. Because that code is not verified by - * the proxy process it is up to the user to ensure that the code is both safe and is built for - * the linked in version of WAVM. + * @param bytecode the Wasm bytecode or registered NullVm plugin name. + * @param precompiled (optional) the precompiled Wasm module. + * @param function_names (optional) an index-to-name mapping for the functions. * @return whether or not the load was successful. */ - virtual bool load(const std::string &code, bool allow_precompiled) = 0; + virtual bool load(std::string_view bytecode, std::string_view precompiled, + const std::unordered_map function_names) = 0; /** * Link the WASM code to the host-provided functions, e.g. the ABI. Prior to linking, the module @@ -192,12 +192,6 @@ class WasmVm { */ virtual bool link(std::string_view debug_name) = 0; - /** - * Get ABI version of the module. - * @return the ABI version. - */ - virtual AbiVersion getAbiVersion() = 0; - /** * Get size of the currently allocated memory in the VM. * @return the size of memory in bytes. diff --git a/src/common/bytecode_util.cc b/src/bytecode_util.cc similarity index 98% rename from src/common/bytecode_util.cc rename to src/bytecode_util.cc index 4b6a8a804..22866c3a7 100644 --- a/src/common/bytecode_util.cc +++ b/src/bytecode_util.cc @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "src/common/bytecode_util.h" +#include "include/proxy-wasm/bytecode_util.h" + #include namespace proxy_wasm { -namespace common { bool BytecodeUtil::checkWasmHeader(std::string_view bytecode) { // Wasm file header is 8 bytes (magic number + version). @@ -240,5 +240,4 @@ bool BytecodeUtil::parseVarint(const char *&pos, const char *end, uint32_t &ret) return ret != static_cast(-1); } -} // namespace common } // namespace proxy_wasm diff --git a/src/null/null_vm.cc b/src/null/null_vm.cc index a048c7da4..de2511a0f 100644 --- a/src/null/null_vm.cc +++ b/src/null/null_vm.cc @@ -40,24 +40,23 @@ std::unique_ptr NullVm::clone() { auto cloned_null_vm = std::make_unique(*this); if (integration()) cloned_null_vm->integration().reset(integration()->clone()); - cloned_null_vm->load(plugin_name_, false /* unused */); + cloned_null_vm->load(plugin_name_, {} /* unused */, {} /* unused */); return cloned_null_vm; } // "Load" the plugin by obtaining a pointer to it from the factory. -bool NullVm::load(const std::string &name, bool /* allow_precompiled */) { +bool NullVm::load(std::string_view name, std::string_view, + const std::unordered_map) { if (!null_vm_plugin_factories_) return false; - auto factory = (*null_vm_plugin_factories_)[name]; + auto factory = (*null_vm_plugin_factories_)[std::string(name)]; if (!factory) return false; plugin_name_ = name; plugin_ = factory(); plugin_->wasm_vm_ = this; return true; -} - -AbiVersion NullVm::getAbiVersion() { return AbiVersion::ProxyWasm_0_2_1; } +} // namespace proxy_wasm bool NullVm::link(std::string_view /* name */) { return true; } diff --git a/src/v8/v8.cc b/src/v8/v8.cc index 57c9c6dcc..dee841702 100644 --- a/src/v8/v8.cc +++ b/src/v8/v8.cc @@ -25,8 +25,6 @@ #include #include -#include "src/common/bytecode_util.h" - #include "v8.h" #include "v8-version.h" #include "wasm-api/wasm.hh" @@ -64,8 +62,8 @@ class V8 : public WasmVm { // WasmVm std::string_view runtime() override { return "v8"; } - bool load(const std::string &code, bool allow_precompiled) override; - AbiVersion getAbiVersion() override; + bool load(std::string_view bytecode, std::string_view precompiled, + const std::unordered_map function_names) override; std::string_view getPrecompiledSectionName() override; bool link(std::string_view debug_name) override; @@ -122,8 +120,6 @@ class V8 : public WasmVm { std::unordered_map host_functions_; std::unordered_map> module_functions_; - - AbiVersion abi_version_; std::unordered_map function_names_index_; }; @@ -251,58 +247,31 @@ template constexpr T convertValTypesToArgsTuple(const U // V8 implementation. -bool V8::load(const std::string &code, bool allow_precompiled) { +bool V8::load(std::string_view bytecode, std::string_view precompiled, + const std::unordered_map function_names) { store_ = wasm::Store::make(engine()); - // Get ABI version from bytecode. - if (!common::BytecodeUtil::getAbiVersion(code, abi_version_)) { - fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); - return false; - } + if (!precompiled.empty()) { + auto vec = wasm::vec::make_uninitialized(precompiled.size()); + ::memcpy(vec.get(), precompiled.data(), precompiled.size()); + module_ = wasm::Module::deserialize(store_.get(), vec); - if (allow_precompiled) { - const auto section_name = getPrecompiledSectionName(); - if (!section_name.empty()) { - std::string_view precompiled = {}; - if (!common::BytecodeUtil::getCustomSection(code, section_name, precompiled)) { - fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); - return false; - } - if (!precompiled.empty()) { - auto vec = wasm::vec::make_uninitialized(precompiled.size()); - ::memcpy(vec.get(), precompiled.data(), precompiled.size()); - - module_ = wasm::Module::deserialize(store_.get(), vec); - if (!module_) { - // Precompiled module that cannot be loaded is considered a hard error, - // so don't fallback to compiling the bytecode. - return false; - } - } - } + } else { + auto vec = wasm::vec::make_uninitialized(bytecode.size()); + ::memcpy(vec.get(), bytecode.data(), bytecode.size()); + module_ = wasm::Module::make(store_.get(), vec); } if (!module_) { - std::string stripped; - if (!common::BytecodeUtil::getStrippedSource(code, stripped)) { - fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); - return false; - }; - wasm::vec stripped_vec = wasm::vec::make(stripped.size(), stripped.data()); - module_ = wasm::Module::make(store_.get(), stripped_vec); + return false; } - if (module_) { - shared_module_ = module_->share(); - assert((shared_module_ != nullptr)); - } + shared_module_ = module_->share(); + assert(shared_module_ != nullptr); - if (!common::BytecodeUtil::getFunctionNameIndex(code, function_names_index_)) { - fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); - return false; - }; + function_names_index_ = function_names; - return module_ != nullptr; + return true; } std::unique_ptr V8::clone() { @@ -314,7 +283,6 @@ std::unique_ptr V8::clone() { clone->module_ = wasm::Module::obtain(clone->store_.get(), shared_module_.get()); clone->function_names_index_ = function_names_index_; - clone->abi_version_ = abi_version_; return clone; } @@ -335,8 +303,6 @@ std::string_view V8::getPrecompiledSectionName() { return name; } -AbiVersion V8::getAbiVersion() { return abi_version_; } - bool V8::link(std::string_view debug_name) { assert(module_ != nullptr); diff --git a/src/wamr/wamr.cc b/src/wamr/wamr.cc index 5cc63f06b..9b7375137 100644 --- a/src/wamr/wamr.cc +++ b/src/wamr/wamr.cc @@ -29,9 +29,10 @@ #include #include +#include "include/proxy-wasm/bytecode_util.h" + #include "src/wamr/types.h" #include "wasm_c_api.h" -#include "src/common/bytecode_util.h" namespace proxy_wasm { namespace wamr { @@ -62,9 +63,8 @@ class Wamr : public WasmVm { Cloneable cloneable() override { return Cloneable::NotCloneable; } std::unique_ptr clone() override { return nullptr; } - AbiVersion getAbiVersion() override; - - bool load(const std::string &code, bool allow_precompiled = false) override; + bool load(std::string_view bytecode, std::string_view precompiled, + const std::unordered_map function_names) override; bool link(std::string_view debug_name) override; uint64_t getMemorySize() override; std::optional getMemory(uint64_t pointer, uint64_t size) override; @@ -113,27 +113,15 @@ class Wamr : public WasmVm { std::unordered_map host_functions_; std::unordered_map module_functions_; - AbiVersion abi_version_; }; -bool Wamr::load(const std::string &code, bool allow_precompiled) { +bool Wamr::load(std::string_view bytecode, std::string_view, + const std::unordered_map) { store_ = wasm_store_new(engine()); - // Get ABI version from bytecode. - if (!common::BytecodeUtil::getAbiVersion(code, abi_version_)) { - fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); - return false; - } - - std::string stripped; - if (!common::BytecodeUtil::getStrippedSource(code, stripped)) { - fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); - return false; - }; - - WasmByteVec stripped_vec; - wasm_byte_vec_new(stripped_vec.get(), stripped.size(), stripped.data()); - module_ = wasm_module_new(store_.get(), stripped_vec.get()); + WasmByteVec vec; + wasm_byte_vec_new(vec.get(), bytecode.size(), bytecode.data()); + module_ = wasm_module_new(store_.get(), vec.get()); return module_ != nullptr; } @@ -622,8 +610,6 @@ void Wamr::getModuleFunctionImpl(std::string_view function_name, }; }; -AbiVersion Wamr::getAbiVersion() { return abi_version_; } - } // namespace wamr std::unique_ptr createWamrVm() { return std::make_unique(); } diff --git a/src/wasm.cc b/src/wasm.cc index 7fda02629..cf2010ff9 100644 --- a/src/wasm.cc +++ b/src/wasm.cc @@ -26,9 +26,11 @@ #include #include +#include "include/proxy-wasm/bytecode_util.h" +#include "include/proxy-wasm/vm_id_handle.h" + #include "src/third_party/base64.h" #include "src/third_party/picosha2.h" -#include "include/proxy-wasm/vm_id_handle.h" namespace proxy_wasm { @@ -231,27 +233,93 @@ WasmBase::~WasmBase() { pending_delete_.clear(); } -bool WasmBase::initialize(const std::string &code, bool allow_precompiled) { +bool WasmBase::load(const std::string &code, bool allow_precompiled) { + assert(!started_from_.has_value()); + if (!wasm_vm_) { return false; } - if (started_from_ == Cloneable::NotCloneable) { - auto ok = wasm_vm_->load(code, allow_precompiled); + if (wasm_vm_->runtime() == "null") { + auto ok = wasm_vm_->load(code, {}, {}); if (!ok) { - fail(FailState::UnableToInitializeCode, "Failed to load Wasm code"); + fail(FailState::UnableToInitializeCode, "Failed to load NullVM plugin"); return false; } - code_ = code; - allow_precompiled_ = allow_precompiled; + abi_version_ = AbiVersion::ProxyWasm_0_2_1; + return true; } - abi_version_ = wasm_vm_->getAbiVersion(); + // Get ABI version from the module. + if (!BytecodeUtil::getAbiVersion(code, abi_version_)) { + fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); + return false; + } if (abi_version_ == AbiVersion::Unknown) { fail(FailState::UnableToInitializeCode, "Missing or unknown Proxy-Wasm ABI version"); return false; } + // Get function names from the module. + if (!BytecodeUtil::getFunctionNameIndex(code, function_names_)) { + fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); + return false; + } + + std::string_view precompiled = {}; + + if (allow_precompiled) { + // Check if precompiled module exists. + const auto section_name = wasm_vm_->getPrecompiledSectionName(); + if (!section_name.empty()) { + if (!BytecodeUtil::getCustomSection(code, section_name, precompiled)) { + fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); + return false; + } + } + } + + // Get original bytecode (possibly stripped). + std::string stripped; + if (!BytecodeUtil::getStrippedSource(code, stripped)) { + fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); + return false; + } + + auto ok = wasm_vm_->load(stripped, precompiled, function_names_); + if (!ok) { + fail(FailState::UnableToInitializeCode, "Failed to load Wasm bytecode"); + return false; + } + + // Store for future use in non-cloneable runtimes. + if (wasm_vm_->cloneable() == Cloneable::NotCloneable) { + module_bytecode_ = stripped; + module_precompiled_ = precompiled; + } + + return true; +} + +bool WasmBase::initialize() { + if (!wasm_vm_) { + return false; + } + + if (started_from_ == Cloneable::NotCloneable) { + auto ok = wasm_vm_->load(base_wasm_handle_->wasm()->moduleBytecode(), + base_wasm_handle_->wasm()->modulePrecompiled(), + base_wasm_handle_->wasm()->functionNames()); + if (!ok) { + fail(FailState::UnableToInitializeCode, "Failed to load Wasm module from base Wasm"); + return false; + } + } + + if (started_from_.has_value()) { + abi_version_ = base_wasm_handle_->wasm()->abiVersion(); + } + if (started_from_ != Cloneable::InstantiatedModule) { registerCallbacks(); if (!wasm_vm_->link(vm_id_)) { @@ -414,7 +482,11 @@ std::shared_ptr createWasm(std::string vm_key, std::string code, (*base_wasms)[vm_key] = wasm_handle; } - if (!wasm_handle->wasm()->initialize(code, allow_precompiled)) { + if (!wasm_handle->wasm()->load(code, allow_precompiled)) { + wasm_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to load Wasm code"); + return nullptr; + } + if (!wasm_handle->wasm()->initialize()) { wasm_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to initialize Wasm code"); return nullptr; } @@ -423,7 +495,7 @@ std::shared_ptr createWasm(std::string vm_key, std::string code, wasm_handle->wasm()->fail(FailState::UnableToCloneVM, "Failed to clone Base Wasm"); return nullptr; } - if (!configuration_canary_handle->wasm()->initialize(code, allow_precompiled)) { + if (!configuration_canary_handle->wasm()->initialize()) { wasm_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to initialize Wasm code"); return nullptr; } @@ -473,8 +545,8 @@ getOrCreateThreadLocalWasm(std::shared_ptr base_handle, base_handle->wasm()->fail(FailState::UnableToCloneVM, "Failed to clone Base Wasm"); return nullptr; } - if (!wasm_handle->wasm()->initialize(base_handle->wasm()->code(), - base_handle->wasm()->allow_precompiled())) { + + if (!wasm_handle->wasm()->initialize()) { base_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to initialize Wasm code"); return nullptr; } diff --git a/src/wasmtime/wasmtime.cc b/src/wasmtime/wasmtime.cc index 3ff503645..98b339658 100644 --- a/src/wasmtime/wasmtime.cc +++ b/src/wasmtime/wasmtime.cc @@ -25,7 +25,6 @@ #include #include "include/proxy-wasm/wasm_vm.h" -#include "src/common/bytecode_util.h" #include "src/wasmtime/types.h" #include "wasmtime/include/wasm.h" @@ -57,8 +56,8 @@ class Wasmtime : public WasmVm { Cloneable cloneable() override { return Cloneable::CompiledBytecode; } std::string_view getPrecompiledSectionName() override { return ""; } - bool load(const std::string &code, bool allow_precompiled = false) override; - AbiVersion getAbiVersion() override; + bool load(std::string_view bytecode, std::string_view precompiled, + const std::unordered_map function_names) override; bool link(std::string_view debug_name) override; std::unique_ptr clone() override; uint64_t getMemorySize() override; @@ -108,35 +107,24 @@ class Wasmtime : public WasmVm { std::unordered_map host_functions_; std::unordered_map module_functions_; - - AbiVersion abi_version_; }; -bool Wasmtime::load(const std::string &code, bool allow_precompiled) { +bool Wasmtime::load(std::string_view bytecode, std::string_view, + const std::unordered_map) { store_ = wasm_store_new(engine()); - // Get ABI version from bytecode. - if (!common::BytecodeUtil::getAbiVersion(code, abi_version_)) { - fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); - return false; - } + WasmByteVec vec; + wasm_byte_vec_new(vec.get(), bytecode.size(), bytecode.data()); - std::string stripped; - if (!common::BytecodeUtil::getStrippedSource(code, stripped)) { - fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); + module_ = wasm_module_new(store_.get(), vec.get()); + if (!module_) { return false; - }; - - WasmByteVec stripped_vec; - wasm_byte_vec_new(stripped_vec.get(), stripped.size(), stripped.data()); - module_ = wasm_module_new(store_.get(), stripped_vec.get()); - - if (module_) { - shared_module_ = wasm_module_share(module_.get()); - assert(shared_module_ != nullptr); } - return module_ != nullptr; + shared_module_ = wasm_module_share(module_.get()); + assert(shared_module_ != nullptr); + + return true; } std::unique_ptr Wasmtime::clone() { @@ -146,7 +134,6 @@ std::unique_ptr Wasmtime::clone() { clone->integration().reset(integration()->clone()); clone->store_ = wasm_store_new(engine()); clone->module_ = wasm_module_obtain(clone->store_.get(), shared_module_.get()); - clone->abi_version_ = abi_version_; return clone; } @@ -643,8 +630,6 @@ void Wasmtime::getModuleFunctionImpl(std::string_view function_name, }; }; -AbiVersion Wasmtime::getAbiVersion() { return abi_version_; } - } // namespace wasmtime std::unique_ptr createWasmtimeVm() { return std::make_unique(); } diff --git a/src/wavm/wavm.cc b/src/wavm/wavm.cc index d3a4d7627..2c3a3adb9 100644 --- a/src/wavm/wavm.cc +++ b/src/wavm/wavm.cc @@ -27,8 +27,6 @@ #include #include -#include "src/common/bytecode_util.h" - #include "WAVM/IR/Module.h" #include "WAVM/IR/Operators.h" #include "WAVM/IR/Types.h" @@ -186,22 +184,6 @@ class RootResolver : public WAVM::Runtime::Resolver { const uint64_t WasmPageSize = 1 << 16; -bool loadModule(const std::string &code, IR::Module &out_module) { - // If the code starts with the WASM binary magic number, load it as a binary IR::Module. - static const uint8_t WasmMagicNumber[4] = {0x00, 0x61, 0x73, 0x6d}; - if (code.size() >= 4 && !memcmp(code.data(), WasmMagicNumber, 4)) { - return WASM::loadBinaryModule(reinterpret_cast(code.data()), code.size(), - out_module); - } else { - // Load it as a text IR::Module. - std::vector parseErrors; - if (!WAST::parseModule(code.c_str(), code.size() + 1, out_module, parseErrors)) { - return false; - } - return true; - } -} - } // namespace template struct NativeWord { using type = T; }; @@ -224,7 +206,8 @@ struct Wavm : public WasmVm { 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; + bool load(std::string_view bytecode, std::string_view precompiled, + const std::unordered_map function_names) override; bool link(std::string_view debug_name) override; uint64_t getMemorySize() override; std::optional getMemory(uint64_t pointer, uint64_t size) override; @@ -233,7 +216,6 @@ struct Wavm : public WasmVm { bool setWord(uint64_t pointer, Word data) override; size_t getWordSize() override { return sizeof(uint32_t); }; std::string_view getPrecompiledSectionName() override; - AbiVersion getAbiVersion() override; #define _GET_FUNCTION(_T) \ void getFunction(std::string_view function_name, _T *f) override { \ @@ -250,7 +232,6 @@ struct Wavm : public WasmVm { FOR_ALL_WASM_VM_IMPORTS(_REGISTER_CALLBACK) #undef _REGISTER_CALLBACK - bool has_instantiated_module_ = false; IR::Module ir_module_; WAVM::Runtime::ModuleRef module_ = nullptr; WAVM::Runtime::GCPointer module_instance_; @@ -262,7 +243,6 @@ struct Wavm : public WasmVm { intrinsic_module_instances_; std::vector> host_functions_; uint8_t *memory_base_ = nullptr; - AbiVersion abi_version_ = AbiVersion::Unknown; }; Wavm::~Wavm() { @@ -279,13 +259,12 @@ Wavm::~Wavm() { std::unique_ptr Wavm::clone() { auto wavm = std::make_unique(); wavm->integration().reset(integration()->clone()); - wavm->abi_version_ = abi_version_; wavm->compartment_ = WAVM::Runtime::cloneCompartment(compartment_); 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_)); @@ -295,38 +274,24 @@ std::unique_ptr Wavm::clone() { return wavm; } -bool Wavm::load(const std::string &code, bool allow_precompiled) { - ASSERT(!has_instantiated_module_); - has_instantiated_module_ = true; +bool Wavm::load(std::string_view bytecode, std::string_view precompiled, + const std::unordered_map) { compartment_ = WAVM::Runtime::createCompartment(); context_ = WAVM::Runtime::createContext(compartment_); - if (!loadModule(code, ir_module_)) { - return false; - } - - // Get ABI version from bytecode. - if (!common::BytecodeUtil::getAbiVersion(code, abi_version_)) { - fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); + if (!WASM::loadBinaryModule(reinterpret_cast(bytecode.data()), + bytecode.size(), ir_module_)) { return false; } - std::string_view precompiled = {}; - if (allow_precompiled) { - if (!common::BytecodeUtil::getCustomSection(code, getPrecompiledSectionName(), precompiled)) { - fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); - return false; - } - } - if (precompiled.empty()) { - module_ = WAVM::Runtime::compileModule(ir_module_); - } else { + if (!precompiled.empty()) { module_ = WAVM::Runtime::loadPrecompiledModule( ir_module_, {precompiled.data(), precompiled.data() + precompiled.size()}); + } else { + module_ = WAVM::Runtime::compileModule(ir_module_); } - return true; -} -AbiVersion Wavm::getAbiVersion() { return abi_version_; } + return module_ != nullptr; +} bool Wavm::link(std::string_view debug_name) { RootResolver rootResolver(compartment_, this); diff --git a/test/BUILD b/test/BUILD index f1e179f32..ec45c17b2 100644 --- a/test/BUILD +++ b/test/BUILD @@ -12,6 +12,20 @@ cc_test( ], ) +cc_test( + name = "bytecode_util_test", + srcs = ["bytecode_util_test.cc"], + data = [ + "//test/test_data:abi_export.wasm", + ], + deps = [ + ":utility_lib", + "//:lib", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "runtime_test", srcs = ["runtime_test.cc"], diff --git a/test/common/bytecode_util_test.cc b/test/bytecode_util_test.cc similarity index 94% rename from test/common/bytecode_util_test.cc rename to test/bytecode_util_test.cc index 50900c0ce..529434577 100644 --- a/test/common/bytecode_util_test.cc +++ b/test/bytecode_util_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "src/common/bytecode_util.h" +#include "include/proxy-wasm/bytecode_util.h" #include #include @@ -23,9 +23,8 @@ #include "gtest/gtest.h" namespace proxy_wasm { -namespace common { -TEST(TestWasmCommonUtil, getCustomSection) { +TEST(TestBytecodeUtil, getCustomSection) { std::string custom_section = { 0x00, 0x61, 0x73, 0x6d, // Wasm magic 0x01, 0x00, 0x00, 0x00, // Wasm version @@ -54,7 +53,7 @@ TEST(TestWasmCommonUtil, getCustomSection) { EXPECT_FALSE(BytecodeUtil::getCustomSection(corrupted, "hey", section)); } -TEST(TestWasmCommonUtil, getFunctionNameIndex) { +TEST(TestBytecodeUtil, getFunctionNameIndex) { const auto source = readTestWasmFile("abi_export.wasm"); std::unordered_map actual; // OK. @@ -73,7 +72,7 @@ TEST(TestWasmCommonUtil, getFunctionNameIndex) { EXPECT_TRUE(actual.empty()); } -TEST(TestWasmCommonUtil, getStrippedSource) { +TEST(TestBytecodeUtil, getStrippedSource) { // Unmodified case. auto source = readTestWasmFile("abi_export.wasm"); std::string actual; @@ -110,12 +109,11 @@ TEST(TestWasmCommonUtil, getStrippedSource) { EXPECT_EQ(actual.size(), source.size() - custom_section.size()); } -TEST(TestWasmCommonUtil, getAbiVersion) { +TEST(TestBytecodeUtil, getAbiVersion) { const auto source = readTestWasmFile("abi_export.wasm"); proxy_wasm::AbiVersion actual; EXPECT_TRUE(BytecodeUtil::getAbiVersion(source, actual)); EXPECT_EQ(actual, proxy_wasm::AbiVersion::ProxyWasm_0_2_0); } -} // namespace common } // namespace proxy_wasm diff --git a/test/common/BUILD b/test/common/BUILD deleted file mode 100644 index 23e21ba71..000000000 --- a/test/common/BUILD +++ /dev/null @@ -1,15 +0,0 @@ -load("@rules_cc//cc:defs.bzl", "cc_test") - -cc_test( - name = "bytecode_util_test", - srcs = ["bytecode_util_test.cc"], - data = [ - "//test/test_data:abi_export.wasm", - ], - deps = [ - "//:lib", - "//test:utility_lib", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], -) diff --git a/test/exports_test.cc b/test/exports_test.cc index c35ea02d8..d18e0983a 100644 --- a/test/exports_test.cc +++ b/test/exports_test.cc @@ -52,7 +52,7 @@ TEST_P(TestVM, Environment) { initialize("env.wasm"); auto wasm_base = WasmBase(std::move(vm_), "vm_id", "", "", envs, {}); - ASSERT_TRUE(wasm_base.wasm_vm()->load(source_, false)); + ASSERT_TRUE(wasm_base.wasm_vm()->load(source_, {}, {})); TestContext context(&wasm_base); current_context_ = &context; @@ -74,7 +74,7 @@ TEST_P(TestVM, Environment) { TEST_P(TestVM, WithoutEnvironment) { initialize("env.wasm"); auto wasm_base = WasmBase(std::move(vm_), "vm_id", "", "", {}, {}); - ASSERT_TRUE(wasm_base.wasm_vm()->load(source_, false)); + ASSERT_TRUE(wasm_base.wasm_vm()->load(source_, {}, {})); TestContext context(&wasm_base); current_context_ = &context; @@ -94,7 +94,7 @@ TEST_P(TestVM, WithoutEnvironment) { TEST_P(TestVM, Clock) { initialize("clock.wasm"); auto wasm_base = WasmBase(std::move(vm_), "vm_id", "", "", {}, {}); - ASSERT_TRUE(wasm_base.wasm_vm()->load(source_, false)); + ASSERT_TRUE(wasm_base.wasm_vm()->load(source_, {}, {})); TestContext context(&wasm_base); current_context_ = &context; diff --git a/test/null_vm_test.cc b/test/null_vm_test.cc index 0201b8599..eeae92698 100644 --- a/test/null_vm_test.cc +++ b/test/null_vm_test.cc @@ -68,7 +68,7 @@ TEST_F(BaseVmTest, NullVmStartup) { EXPECT_TRUE(wasm_vm->cloneable() == Cloneable::InstantiatedModule); auto wasm_vm_clone = wasm_vm->clone(); EXPECT_TRUE(wasm_vm_clone != nullptr); - EXPECT_TRUE(wasm_vm->load("test_null_vm_plugin", true)); + EXPECT_TRUE(wasm_vm->load("test_null_vm_plugin", {}, {})); EXPECT_NE(test_null_vm_plugin, nullptr); } diff --git a/test/runtime_test.cc b/test/runtime_test.cc index 7128d8c76..3ee96ab48 100644 --- a/test/runtime_test.cc +++ b/test/runtime_test.cc @@ -38,15 +38,9 @@ TEST_P(TestVM, Basic) { EXPECT_EQ(vm_->runtime(), runtime_); } -TEST_P(TestVM, ABIVersion) { - initialize("abi_export.wasm"); - ASSERT_TRUE(vm_->load(source_, false)); - ASSERT_EQ(vm_->getAbiVersion(), AbiVersion::ProxyWasm_0_2_0); -} - TEST_P(TestVM, Memory) { initialize("abi_export.wasm"); - ASSERT_TRUE(vm_->load(source_, false)); + ASSERT_TRUE(vm_->load(source_, {}, {})); ASSERT_TRUE(vm_->link("")); Word word; @@ -64,7 +58,7 @@ TEST_P(TestVM, Memory) { TEST_P(TestVM, Clone) { initialize("abi_export.wasm"); - ASSERT_TRUE(vm_->load(source_, false)); + ASSERT_TRUE(vm_->load(source_, {}, {})); ASSERT_TRUE(vm_->link("")); const auto address = 0x2000; Word word; @@ -102,7 +96,7 @@ Word callback2(void *raw_context, Word val) { return val + 100; } TEST_P(TestVM, StraceLogLevel) { initialize("callback.wasm"); - ASSERT_TRUE(vm_->load(source_, false)); + ASSERT_TRUE(vm_->load(source_, {}, {})); vm_->registerCallback("env", "callback", &nopCallback, &ConvertFunctionWordToUint32::convertFunctionWordToUint32); @@ -125,7 +119,7 @@ TEST_P(TestVM, StraceLogLevel) { TEST_P(TestVM, Callback) { initialize("callback.wasm"); - ASSERT_TRUE(vm_->load(source_, false)); + ASSERT_TRUE(vm_->load(source_, {}, {})); TestContext context; current_context_ = &context; @@ -156,7 +150,7 @@ TEST_P(TestVM, Callback) { TEST_P(TestVM, Trap) { initialize("trap.wasm"); - ASSERT_TRUE(vm_->load(source_, false)); + ASSERT_TRUE(vm_->load(source_, {}, {})); ASSERT_TRUE(vm_->link("")); WasmCallVoid<0> trigger; vm_->getFunction("trigger", &trigger); @@ -173,26 +167,5 @@ TEST_P(TestVM, Trap) { ASSERT_TRUE(integration_->error_message_.find(exp_message) != std::string::npos); } -TEST_P(TestVM, WithPrecompiledSection) { - // Verify that stripping precompile_* custom section works. - initialize("abi_export.wasm"); - // Append precompiled_test section - std::vector custom_section = {// custom section id - 0x00, - // section length - 0x13, - // name length - 0x10, - // name = precompiled_test - 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, - 0x64, 0x5f, 0x74, 0x65, 0x73, 0x74, - // content - 0x01, 0x01}; - - source_.append(custom_section.data(), custom_section.size()); - ASSERT_TRUE(vm_->load(source_, false)); - ASSERT_EQ(vm_->getAbiVersion(), AbiVersion::ProxyWasm_0_2_0); -} - } // namespace } // namespace proxy_wasm