diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5d311c81..76f9c724 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -113,6 +113,12 @@ jobs: arch: x86_64 action: test flags: --config=gcc + - name: 'DynVM on Linux/x86_64' + engine: 'dyn' + os: ubuntu-20.04 + arch: x86_64 + action: test + flags: --config=gcc - name: 'NullVM on Linux/x86_64 with ASan' engine: 'null' os: ubuntu-20.04 diff --git a/BUILD b/BUILD index e19a7e36..a1b9d6d6 100644 --- a/BUILD +++ b/BUILD @@ -132,6 +132,7 @@ cc_library( "src/dyn/dyn_vm_plugin.cc", ], hdrs = [ + "include/proxy-wasm/dyn.h", "include/proxy-wasm/dyn_vm.h", "include/proxy-wasm/dyn_vm_plugin.h", "include/proxy-wasm/wasm_api_impl.h", diff --git a/bazel/wasm.bzl b/bazel/wasm.bzl index 9b3a5f73..16fabe95 100644 --- a/bazel/wasm.bzl +++ b/bazel/wasm.bzl @@ -13,6 +13,7 @@ # limitations under the License. load("@rules_rust//rust:defs.bzl", "rust_binary") +load("@rules_rust//rust:defs.bzl", "rust_shared_library") def _wasm_rust_transition_impl(settings, attr): return { @@ -59,6 +60,17 @@ def _wasm_binary_impl(ctx): return [DefaultInfo(files = depset([out]), runfiles = ctx.runfiles([out]))] +def _dyn_binary_impl(ctx): + out = ctx.actions.declare_file(ctx.label.name) + ctx.actions.run( + executable = "cp", + arguments = [ctx.files.binary[0].path, out.path], + outputs = [out], + inputs = ctx.files.binary, + ) + + return [DefaultInfo(files = depset([out]), runfiles = ctx.runfiles([out]))] + def _wasm_attrs(transition): return { "binary": attr.label(mandatory = True, cfg = transition), @@ -67,6 +79,11 @@ def _wasm_attrs(transition): "_whitelist_function_transition": attr.label(default = "@bazel_tools//tools/whitelists/function_transition_whitelist"), } +def _dyn_attrs(): + return { + "binary": attr.label(mandatory = True), + } + wasm_rust_binary_rule = rule( implementation = _wasm_binary_impl, attrs = _wasm_attrs(wasm_rust_transition), @@ -77,6 +94,11 @@ wasi_rust_binary_rule = rule( attrs = _wasm_attrs(wasi_rust_transition), ) +dyn_rust_binary_rule = rule( + implementation = _dyn_binary_impl, + attrs = _dyn_attrs(), +) + def wasm_rust_binary(name, tags = [], wasi = False, signing_key = [], **kwargs): wasm_name = "_wasm_" + name.replace(".", "_") kwargs.setdefault("visibility", ["//visibility:public"]) @@ -100,3 +122,20 @@ def wasm_rust_binary(name, tags = [], wasi = False, signing_key = [], **kwargs): signing_key = signing_key, tags = tags + ["manual"], ) + +def dyn_rust_library(name, tags = [], **kwargs): + dyn_name = "_dyn_" + name.replace(".", "_") + kwargs.setdefault("visibility", ["//visibility:public"]) + + rust_shared_library( + name = dyn_name, + edition = "2018", + tags = ["manual"], + **kwargs + ) + + dyn_rust_binary_rule( + name = name, + binary = ":" + dyn_name, + tags = tags + ["manual"], + ) diff --git a/include/proxy-wasm/dyn_vm.h b/include/proxy-wasm/dyn_vm.h index bd9b72a4..3ce190fd 100644 --- a/include/proxy-wasm/dyn_vm.h +++ b/include/proxy-wasm/dyn_vm.h @@ -24,9 +24,6 @@ namespace proxy_wasm { -class WasmVm; -std::unique_ptr createDynVm(); - // The DynVm wraps a C++ Wasm plugin which has been compiled with the Wasm API // and dynamically linked into the proxy. struct DynVm : public WasmVm { diff --git a/src/dyn/dyn.cc b/src/dyn/dyn.cc index cba231af..8c6b1e9d 100644 --- a/src/dyn/dyn.cc +++ b/src/dyn/dyn.cc @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "include/proxy-wasm/dyn.h" #include "include/proxy-wasm/dyn_vm.h" namespace proxy_wasm { diff --git a/src/dyn/dyn_vm.cc b/src/dyn/dyn_vm.cc index a62d78e5..85a8e32e 100644 --- a/src/dyn/dyn_vm.cc +++ b/src/dyn/dyn_vm.cc @@ -16,16 +16,15 @@ #include "include/proxy-wasm/dyn_vm.h" #include - +#include #include #include +#include +#include +#include #include #include #include -#include -#include -#include -#include namespace proxy_wasm { @@ -42,7 +41,7 @@ std::unique_ptr DynVm::clone() { } // "Load" the plugin by obtaining a pointer to it from the factory. -bool DynVm::load(std::string_view shared_lib, std::string_view /*precompiled*/, +bool DynVm::load(std::string_view plugin_name, std::string_view /*precompiled*/, const std::unordered_map & /*function_names*/) { plugin_ = std::make_unique(); plugin_->source = std::make_shared(); @@ -59,13 +58,14 @@ bool DynVm::load(std::string_view shared_lib, std::string_view /*precompiled*/, size_t written = 0; ssize_t wrote; - const char *data = shared_lib.data(); - while (written < shared_lib.size()) { - wrote = write(plugin_->source->memfd, data + written, shared_lib.length() - written); + const char *data = plugin_name.data(); + while (written < plugin_name.size()) { + wrote = write(plugin_->source->memfd, data + written, plugin_name.length() - written); if (wrote < 0) { integration()->error("failed to write to memfd: " + std::string(strerror(errno))); return false; - } else if (wrote == 0) { + } + if (wrote == 0) { integration()->error("failed to write to memfd, EOF on write"); return false; } diff --git a/src/dyn/dyn_vm_plugin.cc b/src/dyn/dyn_vm_plugin.cc index 52964f65..84e01656 100644 --- a/src/dyn/dyn_vm_plugin.cc +++ b/src/dyn/dyn_vm_plugin.cc @@ -16,14 +16,14 @@ #include "include/proxy-wasm/wasm_vm.h" #include "include/proxy-wasm/dyn_vm_plugin.h" -#include +#include #include -#include +#include #include -#include #include +#include +#include #include -#include namespace proxy_wasm { @@ -61,16 +61,16 @@ DynVmPluginSource::~DynVmPluginSource() { } void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCallVoid<0> *f) { - if (source->dl_handle == NULL) { + if (source->dl_handle == nullptr) { *f = nullptr; return; } void *target = dlsym(source->dl_handle, std::string(function_name).c_str()); - if (target == NULL) { + if (target == nullptr) { *f = nullptr; return; } - void (*target_func)() = reinterpret_cast(target); + auto target_func = reinterpret_cast(target); *f = [this, target_func, function_name](proxy_wasm::ContextBase *context) { proxy_wasm::SaveRestoreContext saved_context(context); wasm_vm_->integration()->trace(call_format(function_name, 0)); @@ -79,16 +79,16 @@ void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCa } void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCallVoid<1> *f) { - if (source->dl_handle == NULL) { + if (source->dl_handle == nullptr) { *f = nullptr; return; } void *target = dlsym(source->dl_handle, std::string(function_name).c_str()); - if (target == NULL) { + if (target == nullptr) { *f = nullptr; return; } - void (*target_func)(uint64_t) = reinterpret_cast(target); + auto target_func = reinterpret_cast(target); *f = [this, target_func, function_name](proxy_wasm::ContextBase *context, proxy_wasm::Word w1) { proxy_wasm::SaveRestoreContext saved_context(context); wasm_vm_->integration()->trace(call_format(function_name, 1, w1)); @@ -97,16 +97,16 @@ void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCa } void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCallVoid<2> *f) { - if (source->dl_handle == NULL) { + if (source->dl_handle == nullptr) { *f = nullptr; return; } void *target = dlsym(source->dl_handle, std::string(function_name).c_str()); - if (target == NULL) { + if (target == nullptr) { *f = nullptr; return; } - void (*target_func)(uint64_t, uint64_t) = reinterpret_cast(target); + auto target_func = reinterpret_cast(target); *f = [this, target_func, function_name](proxy_wasm::ContextBase *context, proxy_wasm::Word w1, proxy_wasm::Word w2) { proxy_wasm::SaveRestoreContext saved_context(context); @@ -116,16 +116,16 @@ void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCa } void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCallVoid<3> *f) { - if (source->dl_handle == NULL) { + if (source->dl_handle == nullptr) { *f = nullptr; return; } void *target = dlsym(source->dl_handle, std::string(function_name).c_str()); - if (target == NULL) { + if (target == nullptr) { *f = nullptr; return; } - void (*target_func)(uint64_t, uint64_t, uint64_t) = + auto target_func = reinterpret_cast(target); *f = [this, target_func, function_name](proxy_wasm::ContextBase *context, proxy_wasm::Word w1, proxy_wasm::Word w2, proxy_wasm::Word w3) { @@ -136,16 +136,16 @@ void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCa } void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCallVoid<5> *f) { - if (source->dl_handle == NULL) { + if (source->dl_handle == nullptr) { *f = nullptr; return; } void *target = dlsym(source->dl_handle, std::string(function_name).c_str()); - if (target == NULL) { + if (target == nullptr) { *f = nullptr; return; } - void (*target_func)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t) = + auto target_func = reinterpret_cast(target); *f = [this, target_func, function_name](proxy_wasm::ContextBase *context, proxy_wasm::Word w1, proxy_wasm::Word w2, proxy_wasm::Word w3, @@ -157,16 +157,16 @@ void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCa } void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCallWord<1> *f) { - if (source->dl_handle == NULL || function_name == "malloc") { + if (source->dl_handle == nullptr || function_name == "malloc") { *f = nullptr; return; } void *target = dlsym(source->dl_handle, std::string(function_name).c_str()); - if (target == NULL) { + if (target == nullptr) { *f = nullptr; return; } - uint64_t (*target_func)(uint64_t) = reinterpret_cast(target); + auto target_func = reinterpret_cast(target); *f = [this, target_func, function_name](proxy_wasm::ContextBase *context, proxy_wasm::Word w1) { proxy_wasm::SaveRestoreContext saved_context(context); wasm_vm_->integration()->trace(call_format(function_name, 1, w1)); @@ -175,16 +175,16 @@ void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCa } void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCallWord<2> *f) { - if (source->dl_handle == NULL) { + if (source->dl_handle == nullptr) { *f = nullptr; return; } void *target = dlsym(source->dl_handle, std::string(function_name).c_str()); - if (target == NULL) { + if (target == nullptr) { *f = nullptr; return; } - uint64_t (*target_func)(uint64_t, uint64_t) = + auto target_func = reinterpret_cast(target); *f = [this, target_func, function_name](proxy_wasm::ContextBase *context, proxy_wasm::Word w1, proxy_wasm::Word w2) { @@ -195,16 +195,16 @@ void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCa } void DynVmPlugin::getFunction(std::string_view function_name, proxy_wasm::WasmCallWord<3> *f) { - if (source->dl_handle == NULL) { + if (source->dl_handle == nullptr) { *f = nullptr; return; } void *target = dlsym(source->dl_handle, std::string(function_name).c_str()); - if (target == NULL) { + if (target == nullptr) { *f = nullptr; return; } - uint64_t (*target_func)(uint64_t, uint64_t, uint64_t) = + auto target_func = reinterpret_cast(target); *f = [this, target_func, function_name](proxy_wasm::ContextBase *context, proxy_wasm::Word w1, proxy_wasm::Word w2, proxy_wasm::Word w3) { diff --git a/test/BUILD b/test/BUILD index 61973ce1..83f33d66 100644 --- a/test/BUILD +++ b/test/BUILD @@ -180,6 +180,21 @@ cc_test( ], ) +cc_test( + name = "dyn_vm_test", + srcs = ["dyn_vm_test.cc"], + data = [ + "//test/test_data:abi_export.so", + ], + linkstatic = 1, + deps = [ + ":utility_lib", + "//:lib", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "wasm_vm_test", timeout = "long", diff --git a/test/test_data/BUILD b/test/test_data/BUILD index bd70b8eb..39d959e6 100644 --- a/test/test_data/BUILD +++ b/test/test_data/BUILD @@ -13,6 +13,7 @@ # limitations under the License. load("@proxy_wasm_cpp_host//bazel:wasm.bzl", "wasm_rust_binary") +load("@proxy_wasm_cpp_host//bazel:wasm.bzl", "dyn_rust_library") load("@proxy_wasm_cpp_sdk//bazel:defs.bzl", "proxy_wasm_cc_binary") licenses(["notice"]) # Apache 2 @@ -24,6 +25,11 @@ wasm_rust_binary( srcs = ["abi_export.rs"], ) +dyn_rust_library( + name = "abi_export.so", + srcs = ["abi_export.rs"], +) + wasm_rust_binary( name = "abi_export.signed.with.key1.wasm", srcs = ["abi_export.rs"], diff --git a/test/utility.cc b/test/utility.cc index ee6f2b95..d17424fe 100644 --- a/test/utility.cc +++ b/test/utility.cc @@ -41,6 +41,17 @@ std::vector getWasmEngines() { return engines; } +std::vector getDynEngines() { + std::vector engines = { +#if defined(PROXY_WASM_HOST_ENGINE_DYN) + "dyn", +#endif + "" + }; + engines.pop_back(); + return engines; +} + std::string readTestWasmFile(const std::string &filename) { auto path = "test/test_data/" + filename; std::ifstream file(path, std::ios::binary); diff --git a/test/utility.h b/test/utility.h index 27b3b049..01f165af 100644 --- a/test/utility.h +++ b/test/utility.h @@ -39,6 +39,9 @@ #if defined(PROXY_WASM_HOST_ENGINE_WAMR) #include "include/proxy-wasm/wamr.h" #endif +#if defined(PROXY_WASM_HOST_ENGINE_DYN) +#include "include/proxy-wasm/dyn.h" +#endif namespace proxy_wasm { @@ -185,6 +188,10 @@ class TestVm : public testing::TestWithParam { #if defined(PROXY_WASM_HOST_ENGINE_WAMR) } else if (engine == "wamr") { vm = proxy_wasm::createWamrVm(); +#endif +#if defined(PROXY_WASM_HOST_ENGINE_DYN) + } else if (engine == "dyn") { + vm = proxy_wasm::createDynVm(); #endif } else { ADD_FAILURE() << "compiled without support for the requested \"" << engine << "\" engine";