Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions include/proxy-wasm/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_; }
Expand Down
9 changes: 5 additions & 4 deletions include/proxy-wasm/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
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;
Expand Down Expand Up @@ -115,9 +116,9 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {

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"); }
Expand Down Expand Up @@ -236,7 +237,7 @@ class WasmBase : public std::enable_shared_from_this<WasmBase> {
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;
Expand Down
29 changes: 21 additions & 8 deletions include/proxy-wasm/wasm_vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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<void()> fail_callback) { fail_callback_ = fail_callback; }
void setFailCallback(std::function<void(FailState)> fail_callback) {
fail_callback_ = fail_callback;
}

// Integrator operations.
std::unique_ptr<WasmVmIntegration> &integration() { return integration_; }
void error(string_view message) { integration()->error(message); }

private:
protected:
std::unique_ptr<WasmVmIntegration> integration_;
bool failed_ = false;
std::function<void()> fail_callback_;
FailState failed_ = FailState::Ok;
std::function<void(FailState)> fail_callback_;
};

// Thread local state set during a call into a WASM VM so that calls coming out of the
Expand Down
43 changes: 24 additions & 19 deletions src/v8/v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint32_t>(-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<uint32_t>(-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) {
Expand Down Expand Up @@ -382,28 +382,31 @@ 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);
} break;

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: {
Expand Down Expand Up @@ -565,7 +568,8 @@ void V8::getModuleFunctionImpl(string_view function_name,
const wasm::Func *func = it->second.get();
if (!equalValTypes(func->type()->params(), convertArgsTupleToValTypes<std::tuple<Args...>>()) ||
!equalValTypes(func->type()->results(), convertArgsTupleToValTypes<std::tuple<>>())) {
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;
}
Expand All @@ -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()));
}
};
}
Expand All @@ -591,7 +595,8 @@ void V8::getModuleFunctionImpl(string_view function_name,
const wasm::Func *func = it->second.get();
if (!equalValTypes(func->type()->params(), convertArgsTupleToValTypes<std::tuple<Args...>>()) ||
!equalValTypes(func->type()->results(), convertArgsTupleToValTypes<std::tuple<R>>())) {
fail("Bad function signature for: " + std::string(function_name));
fail(FailState::UnableToInitializeCode,
"Bad function signature for: " + std::string(function_name));
*function = nullptr;
return;
}
Expand All @@ -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<typename ConvertWordTypeToUint32<R>::type>();
Expand Down
31 changes: 17 additions & 14 deletions src/wasm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ void WasmBase::getFunctions() {
#undef _GET_PROXY

if (!malloc_) {
fail("Wasm missing malloc");
fail(FailState::MissingFunction, "Wasm missing malloc");
}
}

Expand All @@ -250,9 +250,9 @@ WasmBase::WasmBase(const std::shared_ptr<WasmHandleBase> &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; });
}
}

Expand All @@ -261,9 +261,9 @@ WasmBase::WasmBase(std::unique_ptr<WasmVm> 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; });
}
}

Expand Down Expand Up @@ -450,25 +450,26 @@ std::shared_ptr<WasmHandleBase> 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();
Expand All @@ -484,16 +485,17 @@ createThreadLocalWasm(std::shared_ptr<WasmHandleBase> &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;
Expand All @@ -519,7 +521,8 @@ getOrCreateThreadLocalWasm(std::shared_ptr<WasmHandleBase> 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;
Expand Down