diff --git a/include/proxy-wasm/context.h b/include/proxy-wasm/context.h index e2a6abd8d..9623a498b 100644 --- a/include/proxy-wasm/context.h +++ b/include/proxy-wasm/context.h @@ -47,14 +47,16 @@ class WasmVm; * @param fail_open if true the plugin will pass traffic as opposed to close all streams. */ struct PluginBase { - PluginBase(string_view name, string_view root_id, string_view vm_id, + PluginBase(string_view name, string_view root_id, string_view vm_id, string_view runtime, string_view plugin_configuration, bool fail_open) : name_(std::string(name)), root_id_(std::string(root_id)), vm_id_(std::string(vm_id)), - plugin_configuration_(plugin_configuration), fail_open_(fail_open) {} + runtime_(std::string(runtime)), plugin_configuration_(plugin_configuration), + fail_open_(fail_open) {} const std::string name_; const std::string root_id_; const std::string vm_id_; + const std::string runtime_; std::string plugin_configuration_; const bool fail_open_; const std::string &log_prefix() const { return log_prefix_; } diff --git a/include/proxy-wasm/wasm.h b/include/proxy-wasm/wasm.h index e8364acb0..e9454ea6a 100644 --- a/include/proxy-wasm/wasm.h +++ b/include/proxy-wasm/wasm.h @@ -71,7 +71,8 @@ class WasmBase : public std::enable_shared_from_this { return nullptr; } uint32_t allocContextId(); - bool isFailed() { return failed_; } + bool isFailed() { return failed_ != FailState::Ok; } + FailState fail_state() { return failed_; } const std::string &code() const { return code_; } const std::string &vm_configuration() const; @@ -115,9 +116,9 @@ class WasmBase : public std::enable_shared_from_this { WasmForeignFunction getForeignFunction(string_view function_name); - void fail(string_view message) { + void fail(FailState fail_state, string_view message) { error(message); - failed_ = true; + failed_ = fail_state; } virtual void error(string_view message) { std::cerr << message << "\n"; } virtual void unimplemented() { error("unimplemented proxy-wasm API"); } @@ -236,7 +237,7 @@ class WasmBase : public std::enable_shared_from_this { std::string code_; std::string vm_configuration_; bool allow_precompiled_ = false; - bool failed_ = false; // The Wasm VM has experienced a fatal error. + FailState failed_ = FailState::Ok; // Wasm VM fatal error. bool is_emscripten_ = false; uint32_t emscripten_metadata_major_version_ = 0; diff --git a/include/proxy-wasm/wasm_vm.h b/include/proxy-wasm/wasm_vm.h index 1511a5ed4..64d3865a1 100644 --- a/include/proxy-wasm/wasm_vm.h +++ b/include/proxy-wasm/wasm_vm.h @@ -124,6 +124,17 @@ struct WasmVmIntegration { void *ptr_to_function_return) = 0; }; +enum class FailState : int { + Ok = 0, + UnableToCreateVM = 1, + UnableToCloneVM = 2, + MissingFunction = 3, + UnableToInitializeCode = 4, + StartFailed = 5, + ConfigureFailed = 6, + RuntimeError = 7, +}; + // Wasm VM instance. Provides the low level WASM interface. class WasmVm { public: @@ -250,24 +261,26 @@ class WasmVm { FOR_ALL_WASM_VM_IMPORTS(_REGISTER_CALLBACK) #undef _REGISTER_CALLBACK - bool isFailed() { return failed_; } - void fail(string_view message) { + bool isFailed() { return failed_ != FailState::Ok; } + void fail(FailState fail_state, string_view message) { error(message); - failed_ = true; + failed_ = fail_state; if (fail_callback_) { - fail_callback_(); + fail_callback_(fail_state); } } - void setFailCallback(std::function fail_callback) { fail_callback_ = fail_callback; } + void setFailCallback(std::function fail_callback) { + fail_callback_ = fail_callback; + } // Integrator operations. std::unique_ptr &integration() { return integration_; } void error(string_view message) { integration()->error(message); } -private: +protected: std::unique_ptr integration_; - bool failed_ = false; - std::function fail_callback_; + FailState failed_ = FailState::Ok; + std::function fail_callback_; }; // Thread local state set during a call into a WASM VM so that calls coming out of the diff --git a/src/v8/v8.cc b/src/v8/v8.cc index f13f91a7f..c4664f039 100644 --- a/src/v8/v8.cc +++ b/src/v8/v8.cc @@ -322,20 +322,20 @@ string_view V8::getCustomSection(string_view name) { const byte_t *end = source_.get() + source_.size(); while (pos < end) { if (pos + 1 > end) { - fail("Failed to parse corrupted Wasm module"); + fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); return ""; } const auto section_type = *pos++; const auto section_len = parseVarint(pos, end); if (section_len == static_cast(-1) || pos + section_len > end) { - fail("Failed to parse corrupted Wasm module"); + fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); return ""; } if (section_type == 0 /* custom section */) { const auto section_data_start = pos; const auto section_name_len = parseVarint(pos, end); if (section_name_len == static_cast(-1) || pos + section_name_len > end) { - fail("Failed to parse corrupted Wasm module"); + fail(FailState::UnableToInitializeCode, "Failed to parse corrupted Wasm module"); return ""; } if (section_name_len == name.size() && ::memcmp(pos, name.data(), section_name_len) == 0) { @@ -382,19 +382,21 @@ bool V8::link(string_view debug_name) { case wasm::EXTERN_FUNC: { auto it = host_functions_.find(std::string(module) + "." + std::string(name)); if (it == host_functions_.end()) { - fail(std::string("Failed to load Wasm module due to a missing import: ") + - std::string(module) + "." + std::string(name)); + fail(FailState::UnableToInitializeCode, + std::string("Failed to load Wasm module due to a missing import: ") + + std::string(module) + "." + std::string(name)); break; } auto func = it->second.get()->callback_.get(); if (!equalValTypes(import_type->func()->params(), func->type()->params()) || !equalValTypes(import_type->func()->results(), func->type()->results())) { - fail(std::string("Failed to load Wasm module due to an import type mismatch: ") + - std::string(module) + "." + std::string(name) + - ", want: " + printValTypes(import_type->func()->params()) + " -> " + - printValTypes(import_type->func()->results()) + - ", but host exports: " + printValTypes(func->type()->params()) + " -> " + - printValTypes(func->type()->results())); + fail(FailState::UnableToInitializeCode, + std::string("Failed to load Wasm module due to an import type mismatch: ") + + std::string(module) + "." + std::string(name) + + ", want: " + printValTypes(import_type->func()->params()) + " -> " + + printValTypes(import_type->func()->results()) + + ", but host exports: " + printValTypes(func->type()->params()) + " -> " + + printValTypes(func->type()->results())); break; } imports.push_back(func); @@ -402,8 +404,9 @@ bool V8::link(string_view debug_name) { case wasm::EXTERN_GLOBAL: { // TODO(PiotrSikora): add support when/if needed. - fail("Failed to load Wasm module due to a missing import: " + std::string(module) + "." + - std::string(name)); + fail(FailState::UnableToInitializeCode, + "Failed to load Wasm module due to a missing import: " + std::string(module) + "." + + std::string(name)); } break; case wasm::EXTERN_MEMORY: { @@ -565,7 +568,8 @@ void V8::getModuleFunctionImpl(string_view function_name, const wasm::Func *func = it->second.get(); if (!equalValTypes(func->type()->params(), convertArgsTupleToValTypes>()) || !equalValTypes(func->type()->results(), convertArgsTupleToValTypes>())) { - fail(std::string("Bad function signature for: ") + std::string(function_name)); + fail(FailState::UnableToInitializeCode, + std::string("Bad function signature for: ") + std::string(function_name)); *function = nullptr; return; } @@ -574,8 +578,8 @@ void V8::getModuleFunctionImpl(string_view function_name, SaveRestoreContext saved_context(context); auto trap = func->call(params, nullptr); if (trap) { - fail("Function: " + std::string(function_name) + - " failed: " + std::string(trap->message().get(), trap->message().size())); + fail(FailState::RuntimeError, "Function: " + std::string(function_name) + " failed: " + + std::string(trap->message().get(), trap->message().size())); } }; } @@ -591,7 +595,8 @@ void V8::getModuleFunctionImpl(string_view function_name, const wasm::Func *func = it->second.get(); if (!equalValTypes(func->type()->params(), convertArgsTupleToValTypes>()) || !equalValTypes(func->type()->results(), convertArgsTupleToValTypes>())) { - fail("Bad function signature for: " + std::string(function_name)); + fail(FailState::UnableToInitializeCode, + "Bad function signature for: " + std::string(function_name)); *function = nullptr; return; } @@ -601,8 +606,8 @@ void V8::getModuleFunctionImpl(string_view function_name, SaveRestoreContext saved_context(context); auto trap = func->call(params, results); if (trap) { - fail("Function: " + std::string(function_name) + - " failed: " + std::string(trap->message().get(), trap->message().size())); + fail(FailState::RuntimeError, "Function: " + std::string(function_name) + " failed: " + + std::string(trap->message().get(), trap->message().size())); return R{}; } R rvalue = results[0].get::type>(); diff --git a/src/wasm.cc b/src/wasm.cc index 59844daaa..64c64e52a 100644 --- a/src/wasm.cc +++ b/src/wasm.cc @@ -235,7 +235,7 @@ void WasmBase::getFunctions() { #undef _GET_PROXY if (!malloc_) { - fail("Wasm missing malloc"); + fail(FailState::MissingFunction, "Wasm missing malloc"); } } @@ -250,9 +250,9 @@ WasmBase::WasmBase(const std::shared_ptr &base_wasm_handle, Wasm wasm_vm_ = factory(); } if (!wasm_vm_) { - failed_ = true; + failed_ = FailState::UnableToCreateVM; } else { - wasm_vm_->setFailCallback([this] { failed_ = true; }); + wasm_vm_->setFailCallback([this](FailState fail_state) { failed_ = fail_state; }); } } @@ -261,9 +261,9 @@ WasmBase::WasmBase(std::unique_ptr wasm_vm, string_view vm_id, string_vi : vm_id_(std::string(vm_id)), vm_key_(std::string(vm_key)), wasm_vm_(std::move(wasm_vm)), vm_configuration_(std::string(vm_configuration)) { if (!wasm_vm_) { - failed_ = true; + failed_ = FailState::UnableToCreateVM; } else { - wasm_vm_->setFailCallback([this] { failed_ = true; }); + wasm_vm_->setFailCallback([this](FailState fail_state) { failed_ = fail_state; }); } } @@ -450,25 +450,26 @@ std::shared_ptr createWasm(std::string vm_key, std::string code, } if (!wasm_handle->wasm()->initialize(code, allow_precompiled)) { - wasm_handle->wasm()->fail("Failed to initialize Wasm code"); + wasm_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to initialize Wasm code"); return nullptr; } auto configuration_canary_handle = clone_factory(wasm_handle); if (!configuration_canary_handle) { - wasm_handle->wasm()->fail("Failed to clone Base Wasm"); + wasm_handle->wasm()->fail(FailState::UnableToCloneVM, "Failed to clone Base Wasm"); return nullptr; } if (!configuration_canary_handle->wasm()->initialize(code, allow_precompiled)) { - wasm_handle->wasm()->fail("Failed to initialize Wasm code"); + wasm_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to initialize Wasm code"); return nullptr; } auto root_context = configuration_canary_handle->wasm()->start(plugin); if (!root_context) { - configuration_canary_handle->wasm()->fail("Failed to start base Wasm"); + configuration_canary_handle->wasm()->fail(FailState::StartFailed, "Failed to start base Wasm"); return nullptr; } if (!configuration_canary_handle->wasm()->configure(root_context, plugin)) { - configuration_canary_handle->wasm()->fail("Failed to configure base Wasm plugin"); + configuration_canary_handle->wasm()->fail(FailState::ConfigureFailed, + "Failed to configure base Wasm plugin"); return nullptr; } configuration_canary_handle->kill(); @@ -484,16 +485,17 @@ createThreadLocalWasm(std::shared_ptr &base_wasm, } if (!wasm_handle->wasm()->initialize(wasm_handle->wasm()->code(), wasm_handle->wasm()->allow_precompiled())) { - wasm_handle->wasm()->fail("Failed to initialize Wasm code"); + wasm_handle->wasm()->fail(FailState::UnableToInitializeCode, "Failed to initialize Wasm code"); return nullptr; } ContextBase *root_context = wasm_handle->wasm()->start(plugin); if (!root_context) { - base_wasm->wasm()->fail("Failed to start thread-local Wasm"); + base_wasm->wasm()->fail(FailState::StartFailed, "Failed to start thread-local Wasm"); return nullptr; } if (!wasm_handle->wasm()->configure(root_context, plugin)) { - base_wasm->wasm()->fail("Failed to configure thread-local Wasm plugin"); + base_wasm->wasm()->fail(FailState::ConfigureFailed, + "Failed to configure thread-local Wasm plugin"); return nullptr; } local_wasms[std::string(wasm_handle->wasm()->vm_key())] = wasm_handle; @@ -519,7 +521,8 @@ getOrCreateThreadLocalWasm(std::shared_ptr base_wasm, if (wasm_handle) { auto root_context = wasm_handle->wasm()->getOrCreateRootContext(plugin); if (!wasm_handle->wasm()->configure(root_context, plugin)) { - base_wasm->wasm()->fail("Failed to configure thread-local Wasm code"); + base_wasm->wasm()->fail(FailState::ConfigureFailed, + "Failed to configure thread-local Wasm code"); return nullptr; } return wasm_handle;