diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e759f960..fb13b2d3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#442](https://github.com/wasmerio/wasmer/pull/442) Misc. WASI FS fixes and implement readdir +- [#440](https://github.com/wasmerio/wasmer/pull/440) Fix type mismatch between `wasmer_instance_call` and `wasmer_export_func_*_arity` functions in the runtime C API. +- [#269](https://github.com/wasmerio/wasmer/pull/269) Add better runtime docs +- [#432](https://github.com/wasmerio/wasmer/pull/432) Fix returned value of `wasmer_last_error_message` in the runtime C API - [#429](https://github.com/wasmerio/wasmer/pull/429) Get wasi::path_filestat_get working for some programs; misc. minor WASI FS improvements - [#413](https://github.com/wasmerio/wasmer/pull/413) Update LLVM backend to use new parser codegen traits diff --git a/Makefile b/Makefile index 2a1bfa138..06e66e735 100644 --- a/Makefile +++ b/Makefile @@ -49,11 +49,13 @@ test: # cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs) cargo test --manifest-path lib/spectests/Cargo.toml --features clif cargo test --manifest-path lib/spectests/Cargo.toml --features llvm + cargo test --manifest-path lib/runtime/Cargo.toml --features llvm cargo build -p wasmer-runtime-c-api cargo test -p wasmer-runtime-c-api -- --nocapture test-singlepass: cargo test --manifest-path lib/spectests/Cargo.toml --features singlepass + cargo test --manifest-path lib/runtime/Cargo.toml --features singlepass test-emscripten-llvm: cargo test --manifest-path lib/emscripten/Cargo.toml --features llvm -- --test-threads=1 $(runargs) diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index a8cd0f448..0ae4e9a59 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] mod cache; mod code; diff --git a/lib/clif-backend/src/signal/unix.rs b/lib/clif-backend/src/signal/unix.rs index a56613384..2f12713fa 100644 --- a/lib/clif-backend/src/signal/unix.rs +++ b/lib/clif-backend/src/signal/unix.rs @@ -1,5 +1,5 @@ //! Installing signal handlers allows us to handle traps and out-of-bounds memory -//! accesses that occur when runniing webassembly. +//! accesses that occur when running WebAssembly. //! //! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622 //! diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index e996fe58b..6b0340513 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] #[macro_use] extern crate wasmer_runtime_core; diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index c8bc50318..6d8816af8 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] #![cfg_attr(nightly, feature(unwind_attributes))] mod backend; diff --git a/lib/middleware-common/src/lib.rs b/lib/middleware-common/src/lib.rs index 83b1ee35d..e09d9ee03 100644 --- a/lib/middleware-common/src/lib.rs +++ b/lib/middleware-common/src/lib.rs @@ -1,3 +1,3 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] pub mod call_trace; diff --git a/lib/runtime-abi/src/lib.rs b/lib/runtime-abi/src/lib.rs index f4b51b1f0..d1c9e2326 100644 --- a/lib/runtime-abi/src/lib.rs +++ b/lib/runtime-abi/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] #[cfg(not(target_os = "windows"))] #[macro_use] diff --git a/lib/runtime-c-api/src/error.rs b/lib/runtime-c-api/src/error.rs index 5980c79a9..1a9322df8 100644 --- a/lib/runtime-c-api/src/error.rs +++ b/lib/runtime-c-api/src/error.rs @@ -1,4 +1,4 @@ -//! Errors. +//! Read runtime errors. use libc::{c_char, c_int}; use std::cell::RefCell; @@ -61,20 +61,20 @@ pub unsafe extern "C" fn wasmer_last_error_message(buffer: *mut c_char, length: return -1; } - let last_error = match take_last_error() { - Some(err) => err, + let error_message = match take_last_error() { + Some(err) => err.to_string(), None => return 0, }; - let error_message = last_error.to_string(); + let length = length as usize; - let buffer = slice::from_raw_parts_mut(buffer as *mut u8, length as usize); - - if error_message.len() >= buffer.len() { - // buffer to small for err message + if error_message.len() >= length { + // buffer is too small to hold the error message return -1; } + let buffer = slice::from_raw_parts_mut(buffer as *mut u8, length); + ptr::copy_nonoverlapping( error_message.as_ptr(), buffer.as_mut_ptr(), @@ -85,7 +85,7 @@ pub unsafe extern "C" fn wasmer_last_error_message(buffer: *mut c_char, length: // accidentally read into garbage. buffer[error_message.len()] = 0; - error_message.len() as c_int + error_message.len() as c_int + 1 } #[derive(Debug)] diff --git a/lib/runtime-c-api/src/export.rs b/lib/runtime-c-api/src/export.rs index 6bcae32f2..cd9f69b66 100644 --- a/lib/runtime-c-api/src/export.rs +++ b/lib/runtime-c-api/src/export.rs @@ -1,4 +1,5 @@ -//! Wasm exports. +//! Create, read, destroy export definitions (function, global, memory +//! and table) on an instance. use crate::{ error::{update_last_error, CApiError}, @@ -221,7 +222,7 @@ pub unsafe extern "C" fn wasmer_export_func_params_arity( pub unsafe extern "C" fn wasmer_export_func_params( func: *const wasmer_export_func_t, params: *mut wasmer_value_tag, - params_len: c_int, + params_len: uint32_t, ) -> wasmer_result_t { let named_export = &*(func as *const NamedExport); let export = &named_export.export; @@ -251,7 +252,7 @@ pub unsafe extern "C" fn wasmer_export_func_params( pub unsafe extern "C" fn wasmer_export_func_returns( func: *const wasmer_export_func_t, returns: *mut wasmer_value_tag, - returns_len: c_int, + returns_len: uint32_t, ) -> wasmer_result_t { let named_export = &*(func as *const NamedExport); let export = &named_export.export; diff --git a/lib/runtime-c-api/src/global.rs b/lib/runtime-c-api/src/global.rs index 2e4ea645f..dc3910330 100644 --- a/lib/runtime-c-api/src/global.rs +++ b/lib/runtime-c-api/src/global.rs @@ -1,4 +1,4 @@ -//! Wasm global. +//! Create, set, get and destroy global variables of an instance. use crate::value::{wasmer_value_t, wasmer_value_tag}; use wasmer_runtime::Global; diff --git a/lib/runtime-c-api/src/import.rs b/lib/runtime-c-api/src/import.rs index cc3598078..a22b7f245 100644 --- a/lib/runtime-c-api/src/import.rs +++ b/lib/runtime-c-api/src/import.rs @@ -1,4 +1,5 @@ -//! Wasm imports. +//! Create, read, destroy import definitions (function, global, memory +//! and table) on an instance. use crate::{ error::{update_last_error, CApiError}, diff --git a/lib/runtime-c-api/src/instance.rs b/lib/runtime-c-api/src/instance.rs index a9d7d5555..dfd7f2a14 100644 --- a/lib/runtime-c-api/src/instance.rs +++ b/lib/runtime-c-api/src/instance.rs @@ -1,4 +1,4 @@ -//! Wasm instance. +//! Instantiate a module, call functions, and read exports. use crate::{ error::{update_last_error, CApiError}, @@ -125,9 +125,9 @@ pub unsafe extern "C" fn wasmer_instance_call( instance: *mut wasmer_instance_t, name: *const c_char, params: *const wasmer_value_t, - params_len: c_int, + params_len: uint32_t, results: *mut wasmer_value_t, - results_len: c_int, + results_len: uint32_t, ) -> wasmer_result_t { if instance.is_null() { update_last_error(CApiError { diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 6a26d6027..054cd14e1 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -1,4 +1,86 @@ -#![deny(unused_imports, unused_variables)] +//! # Wasmer Runtime C API +//! +//! Wasmer is a standalone JIT WebAssembly runtime, aiming to be fully +//! compatible with Emscripten, Rust and Go. [Learn +//! more](https://github.com/wasmerio/wasmer). +//! +//! This crate exposes a C and C++ API for the Wasmer runtime. +//! +//! # Usage +//! +//! The C and C++ header files can be found in the source tree of this +//! crate, respectively [`wasmer.h`][wasmer_h] and +//! [`wasmer.hh`][wasmer_hh]. They are automatically generated, and always +//! up-to-date in this repository. +//! +//! Here is a simple example to use the C API: +//! +//! ```c +//! #include +//! #include "wasmer.h" +//! #include +//! #include +//! +//! int main() +//! { +//! // Read the Wasm file bytes. +//! FILE *file = fopen("sum.wasm", "r"); +//! fseek(file, 0, SEEK_END); +//! long len = ftell(file); +//! uint8_t *bytes = malloc(len); +//! fseek(file, 0, SEEK_SET); +//! fread(bytes, 1, len, file); +//! fclose(file); +//! +//! // Prepare the imports. +//! wasmer_import_t imports[] = {}; +//! +//! // Instantiate! +//! wasmer_instance_t *instance = NULL; +//! wasmer_result_t instantiation_result = wasmer_instantiate(&instance, bytes, len, imports, 0); +//! +//! assert(instantiation_result == WASMER_OK); +//! +//! // Let's call a function. +//! // Start by preparing the arguments. +//! +//! // Value of argument #1 is `7i32`. +//! wasmer_value_t argument_one; +//! argument_one.tag = WASM_I32; +//! argument_one.value.I32 = 7; +//! +//! // Value of argument #2 is `8i32`. +//! wasmer_value_t argument_two; +//! argument_two.tag = WASM_I32; +//! argument_two.value.I32 = 8; +//! +//! // Prepare the arguments. +//! wasmer_value_t arguments[] = {argument_one, argument_two}; +//! +//! // Prepare the return value. +//! wasmer_value_t result_one; +//! wasmer_value_t results[] = {result_one}; +//! +//! // Call the `sum` function with the prepared arguments and the return value. +//! wasmer_result_t call_result = wasmer_instance_call(instance, "sum", arguments, 2, results, 1); +//! +//! // Let's display the result. +//! printf("Call result: %d\n", call_result); +//! printf("Result: %d\n", results[0].value.I32); +//! +//! // `sum(7, 8) == 15`. +//! assert(results[0].value.I32 == 15); +//! assert(call_result == WASMER_OK); +//! +//! wasmer_instance_destroy(instance); +//! +//! return 0; +//! } +//! ``` +//! +//! [wasmer_h]: ./wasmer.h +//! [wasmer_hh]: ./wasmer.hh +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] extern crate wasmer_runtime; extern crate wasmer_runtime_core; diff --git a/lib/runtime-c-api/src/memory.rs b/lib/runtime-c-api/src/memory.rs index f90965586..5927bee5e 100644 --- a/lib/runtime-c-api/src/memory.rs +++ b/lib/runtime-c-api/src/memory.rs @@ -1,4 +1,4 @@ -//! Wasm memory.o +//! Create, read, write, grow, destroy memory of an instance. use crate::{error::update_last_error, wasmer_limits_t, wasmer_result_t}; use libc::{uint32_t, uint8_t}; diff --git a/lib/runtime-c-api/src/module.rs b/lib/runtime-c-api/src/module.rs index 42d9815a6..dbd676f10 100644 --- a/lib/runtime-c-api/src/module.rs +++ b/lib/runtime-c-api/src/module.rs @@ -1,4 +1,4 @@ -//! Wasm module. +//! Compile, validate, instantiate, serialize, and destroy modules. use crate::{ error::{update_last_error, CApiError}, @@ -247,7 +247,7 @@ pub unsafe extern "C" fn wasmer_module_deserialize( let serialized_module: &[u8] = &*(serialized_module as *const &[u8]); match Artifact::deserialize(serialized_module) { - Ok(artifact) => match load_cache_with(artifact, default_compiler()) { + Ok(artifact) => match load_cache_with(artifact, &default_compiler()) { Ok(deserialized_module) => { *module = Box::into_raw(Box::new(deserialized_module)) as _; wasmer_result_t::WASMER_OK diff --git a/lib/runtime-c-api/src/table.rs b/lib/runtime-c-api/src/table.rs index 84d3b794f..cd382912f 100644 --- a/lib/runtime-c-api/src/table.rs +++ b/lib/runtime-c-api/src/table.rs @@ -1,4 +1,4 @@ -//! Wasm tables. +//! Create, grow, destroy tables of an instance. use crate::{error::update_last_error, wasmer_limits_t, wasmer_result_t}; use libc::uint32_t; diff --git a/lib/runtime-c-api/src/value.rs b/lib/runtime-c-api/src/value.rs index c0a3e64d8..e5547bfa6 100644 --- a/lib/runtime-c-api/src/value.rs +++ b/lib/runtime-c-api/src/value.rs @@ -1,4 +1,4 @@ -//! Wasm values. +//! Create and map Rust to WebAssembly values. use libc::{int32_t, int64_t}; use wasmer_runtime::Value; diff --git a/lib/runtime-c-api/tests/test-exports.c b/lib/runtime-c-api/tests/test-exports.c index 951c4f3a4..77ff6683b 100644 --- a/lib/runtime-c-api/tests/test-exports.c +++ b/lib/runtime-c-api/tests/test-exports.c @@ -60,7 +60,6 @@ int main() assert(returns_sig[0] == WASM_I32); free(returns_sig); - wasmer_value_t param_one; param_one.tag = WASM_I32; param_one.value.I32 = 7; @@ -71,7 +70,7 @@ int main() wasmer_value_t result_one; wasmer_value_t results[] = {result_one}; - wasmer_result_t call_result = wasmer_export_func_call(func, params, 2, results, 1); + wasmer_result_t call_result = wasmer_export_func_call(func, params, params_arity, results, returns_arity); printf("Call result: %d\n", call_result); printf("Result: %d\n", results[0].value.I32); assert(results[0].value.I32 == 15); diff --git a/lib/runtime-c-api/tests/test-instantiate.c b/lib/runtime-c-api/tests/test-instantiate.c index 20332623e..8a7c2610e 100644 --- a/lib/runtime-c-api/tests/test-instantiate.c +++ b/lib/runtime-c-api/tests/test-instantiate.c @@ -46,7 +46,8 @@ int main() int error_len = wasmer_last_error_length(); printf("Error len: `%d`\n", error_len); char *error_str = malloc(error_len); - wasmer_last_error_message(error_str, error_len); + int error_result = wasmer_last_error_message(error_str, error_len); + assert(error_len == error_result); printf("Error str: `%s`\n", error_str); assert(0 == strcmp(error_str, "Call error: Parameters of type [I32] did not match signature [I32, I32] -> [I32]")); free(error_str); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index d11deab11..1e4941d36 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -197,7 +197,7 @@ wasmer_result_t wasmer_export_func_call(const wasmer_export_func_t *func, */ wasmer_result_t wasmer_export_func_params(const wasmer_export_func_t *func, wasmer_value_tag *params, - int params_len); + uint32_t params_len); /** * Sets the result parameter to the arity of the params of the wasmer_export_func_t @@ -215,7 +215,7 @@ wasmer_result_t wasmer_export_func_params_arity(const wasmer_export_func_t *func */ wasmer_result_t wasmer_export_func_returns(const wasmer_export_func_t *func, wasmer_value_tag *returns, - int returns_len); + uint32_t returns_len); /** * Sets the result parameter to the arity of the returns of the wasmer_export_func_t @@ -390,9 +390,9 @@ wasmer_result_t wasmer_import_func_returns_arity(const wasmer_import_func_t *fun wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance, const char *name, const wasmer_value_t *params, - int params_len, + uint32_t params_len, wasmer_value_t *results, - int results_len); + uint32_t results_len); /** * Gets the `data` field within the context. diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 7b22732d0..12b5b0c70 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -178,7 +178,7 @@ wasmer_result_t wasmer_export_func_call(const wasmer_export_func_t *func, /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_export_func_params(const wasmer_export_func_t *func, wasmer_value_tag *params, - int params_len); + uint32_t params_len); /// Sets the result parameter to the arity of the params of the wasmer_export_func_t /// Returns `wasmer_result_t::WASMER_OK` upon success. @@ -192,7 +192,7 @@ wasmer_result_t wasmer_export_func_params_arity(const wasmer_export_func_t *func /// and `wasmer_last_error_message` to get an error message. wasmer_result_t wasmer_export_func_returns(const wasmer_export_func_t *func, wasmer_value_tag *returns, - int returns_len); + uint32_t returns_len); /// Sets the result parameter to the arity of the returns of the wasmer_export_func_t /// Returns `wasmer_result_t::WASMER_OK` upon success. @@ -313,9 +313,9 @@ wasmer_result_t wasmer_import_func_returns_arity(const wasmer_import_func_t *fun wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance, const char *name, const wasmer_value_t *params, - int params_len, + uint32_t params_len, wasmer_value_t *results, - int results_len); + uint32_t results_len); /// Gets the `data` field within the context. void *wasmer_instance_context_data_get(const wasmer_instance_context_t *ctx); diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index b79180ad6..b3d529460 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -17,30 +17,31 @@ use crate::{ }; use std::slice; +/// The `LocalBacking` "owns" the memory used by all the local resources of an Instance. +/// That is, local memories, tables, and globals (as well as some additional +/// data for the virtual call machinery). #[derive(Debug)] pub struct LocalBacking { + /// This is a map from the local resource index to actual memory, + /// table, and globals. pub(crate) memories: BoxedMap, pub(crate) tables: BoxedMap, pub(crate) globals: BoxedMap, + /// This own the memory containing the pointers to the local memories. + /// While simplifying implementation, this adds indirection and may hurt + /// performance, especially on cache-starved systems. pub(crate) vm_memories: BoxedMap, pub(crate) vm_tables: BoxedMap, pub(crate) vm_globals: BoxedMap, + /// The dynamic sigindices are used to efficiently support caching and + /// the `call_indirect` wasm instruction. This field (and local_functions + /// as well) are subject to change. pub(crate) dynamic_sigindices: BoxedMap, pub(crate) local_functions: BoxedMap, } -// impl LocalBacking { -// pub fn memory(&mut self, local_memory_index: LocalMemoryIndex) -> &mut Memory { -// &mut self.memories[local_memory_index] -// } - -// pub fn table(&mut self, local_table_index: LocalTableIndex) -> &mut TableBacking { -// &mut self.tables[local_table_index] -// } -// } - impl LocalBacking { pub(crate) fn new(module: &ModuleInner, imports: &ImportBacking, vmctx: *mut vm::Ctx) -> Self { let mut memories = Self::generate_memories(module); @@ -102,6 +103,9 @@ impl LocalBacking { memories.into_boxed_map() } + /// Initialize each locally-defined memory in the Module. + /// + /// This involves copying in the data initializers. fn finalize_memories( module: &ModuleInner, imports: &ImportBacking, @@ -174,6 +178,9 @@ impl LocalBacking { tables.into_boxed_map() } + /// This initializes all of the locally-defined tables in the Module, e.g. + /// putting all the table elements (function pointers) + /// in the right places. #[allow(clippy::cast_ptr_alignment)] fn finalize_tables( module: &ModuleInner, diff --git a/lib/runtime-core/src/codegen.rs b/lib/runtime-core/src/codegen.rs index 296d1a740..b61ce58bb 100644 --- a/lib/runtime-core/src/codegen.rs +++ b/lib/runtime-core/src/codegen.rs @@ -35,7 +35,6 @@ impl fmt::Debug for InternalEvent { InternalEvent::Breakpoint(_) => write!(f, "Breakpoint"), InternalEvent::SetInternal(_) => write!(f, "SetInternal"), InternalEvent::GetInternal(_) => write!(f, "GetInternal"), - _ => panic!("unknown event"), } } } diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index fb25acdb8..c93115d14 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -11,7 +11,7 @@ pub type ResolveResult = std::result::Result; pub type ParseResult = std::result::Result; /// This is returned when the chosen compiler is unable to -/// successfully compile the provided webassembly module into +/// successfully compile the provided WebAssembly module into /// a `Module`. /// /// Comparing two `CompileError`s always evaluates to false. @@ -114,7 +114,7 @@ impl std::fmt::Display for LinkError { impl std::error::Error for LinkError {} /// This is the error type returned when calling -/// a webassembly function. +/// a WebAssembly function. /// /// The main way to do this is `Instance.call`. /// @@ -270,7 +270,7 @@ impl std::error::Error for CreationError {} /// The amalgamation of all errors that can occur /// during the compilation, instantiation, or execution -/// of a webassembly module. +/// of a WebAssembly module. /// /// Comparing two `Error`s always evaluates to false. #[derive(Debug)] diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index 14d7a0146..d5f84acc2 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -262,7 +262,7 @@ impl Instance { } } - /// Call an exported webassembly function given the export name. + /// Call an exported WebAssembly function given the export name. /// Pass arguments by wrapping each one in the [`Value`] enum. /// The returned values are also each wrapped in a [`Value`]. /// @@ -270,7 +270,7 @@ impl Instance { /// /// # Note: /// This returns `CallResult>` in order to support - /// the future multi-value returns webassembly feature. + /// the future multi-value returns WebAssembly feature. /// /// # Usage: /// ``` @@ -601,7 +601,7 @@ pub struct DynFunc<'a> { } impl<'a> DynFunc<'a> { - /// Call an exported webassembly function safely. + /// Call an exported WebAssembly function safely. /// /// Pass arguments by wrapping each one in the [`Value`] enum. /// The returned values are also each wrapped in a [`Value`]. @@ -610,7 +610,7 @@ impl<'a> DynFunc<'a> { /// /// # Note: /// This returns `CallResult>` in order to support - /// the future multi-value returns webassembly feature. + /// the future multi-value returns WebAssembly feature. /// /// # Usage: /// ``` diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 2a0cca431..da9144a2b 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] #![cfg_attr(nightly, feature(unwind_attributes))] #[cfg(test)] diff --git a/lib/runtime-core/src/memory/static_/unshared.rs b/lib/runtime-core/src/memory/static_/unshared.rs index b9e66de0a..602a02bac 100644 --- a/lib/runtime-core/src/memory/static_/unshared.rs +++ b/lib/runtime-core/src/memory/static_/unshared.rs @@ -11,7 +11,7 @@ use crate::{ /// This is an internal-only api. /// /// A static memory allocates 6GB of *virtual* memory when created -/// in order to allow the webassembly module to contain no bounds-checks. +/// in order to allow the WebAssembly module to contain no bounds-checks. /// /// Additionally, static memories stay at a single virtual address, so there is no need /// to reload its address on each use. diff --git a/lib/runtime-core/src/sig_registry.rs b/lib/runtime-core/src/sig_registry.rs index 1f6d87b4f..653294f32 100644 --- a/lib/runtime-core/src/sig_registry.rs +++ b/lib/runtime-core/src/sig_registry.rs @@ -23,10 +23,18 @@ struct GlobalSigRegistry { sig_assoc: Map>, } +/// The `SigRegistry` represents a process-global map of function signatures +/// to signature indexes and vice versa (the map goes both ways). +/// +/// This exists for two reasons: +/// 1. The `call_indirect` wasm instruction can compare two signature indices +/// to do signature validation very quickly. +/// 2. To intern function signatures, which may be expensive to create. #[derive(Debug)] pub struct SigRegistry; impl SigRegistry { + /// Map a `FuncSig` to a global `SigIndex`. pub fn lookup_sig_index(&self, func_sig: Sig) -> SigIndex where Sig: Into>, @@ -45,11 +53,15 @@ impl SigRegistry { sig_index } + /// Map a global `SigIndex` to an interned `FuncSig`. pub fn lookup_signature(&self, sig_index: SigIndex) -> Arc { let global = (*GLOBAL_SIG_REGISTRY).read(); Arc::clone(&global.sig_assoc[sig_index]) } + /// Register a function signature with the global signature registry. + /// + /// This will return an interned `FuncSig`. pub fn lookup_signature_ref(&self, func_sig: &FuncSig) -> Arc { let mut global = (*GLOBAL_SIG_REGISTRY).write(); let global = &mut *global; diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 23a848738..0a9bc8c2f 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -247,7 +247,7 @@ impl WasmTypeList for (A,) { type CStruct = S1; type RetArray = [u64; 1]; fn from_ret_array(array: Self::RetArray) -> Self { - (WasmExternType::from_native(NativeWasmType::from_bits( + (WasmExternType::from_native(NativeWasmType::from_binary( array[0], )),) } @@ -274,7 +274,7 @@ impl WasmTypeList for (A,) { ctx: *mut Ctx, ) -> Result { let (a,) = self; - let args = [a.to_native().to_bits()]; + let args = [a.to_native().to_binary()]; let mut rets = Rets::empty_ret_array(); let mut trap = WasmTrapInfo::Unknown; let mut user_error = None; @@ -322,7 +322,7 @@ macro_rules! impl_traits { fn from_ret_array(array: Self::RetArray) -> Self { #[allow(non_snake_case)] let [ $( $x ),* ] = array; - ( $( WasmExternType::from_native(NativeWasmType::from_bits($x)) ),* ) + ( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* ) } fn empty_ret_array() -> Self::RetArray { [0; count_idents!( $( $x ),* )] @@ -344,7 +344,7 @@ macro_rules! impl_traits { unsafe fn call(self, f: NonNull, wasm: Wasm, ctx: *mut Ctx) -> Result { #[allow(unused_parens)] let ( $( $x ),* ) = self; - let args = [ $( $x.to_native().to_bits() ),* ]; + let args = [ $( $x.to_native().to_binary()),* ]; let mut rets = Rets::empty_ret_array(); let mut trap = WasmTrapInfo::Unknown; let mut user_error = None; diff --git a/lib/runtime-core/src/types.rs b/lib/runtime-core/src/types.rs index 23a1c8379..975b5cfba 100644 --- a/lib/runtime-core/src/types.rs +++ b/lib/runtime-core/src/types.rs @@ -76,44 +76,44 @@ where Self: Sized, { const TYPE: Type; - fn from_bits(bits: u64) -> Self; - fn to_bits(self) -> u64; + fn from_binary(bits: u64) -> Self; + fn to_binary(self) -> u64; } unsafe impl NativeWasmType for i32 { const TYPE: Type = Type::I32; - fn from_bits(bits: u64) -> Self { + fn from_binary(bits: u64) -> Self { bits as _ } - fn to_bits(self) -> u64 { + fn to_binary(self) -> u64 { self as _ } } unsafe impl NativeWasmType for i64 { const TYPE: Type = Type::I64; - fn from_bits(bits: u64) -> Self { + fn from_binary(bits: u64) -> Self { bits as _ } - fn to_bits(self) -> u64 { + fn to_binary(self) -> u64 { self as _ } } unsafe impl NativeWasmType for f32 { const TYPE: Type = Type::F32; - fn from_bits(bits: u64) -> Self { - bits as _ + fn from_binary(bits: u64) -> Self { + f32::from_bits(bits as u32) } - fn to_bits(self) -> u64 { - self as _ + fn to_binary(self) -> u64 { + self.to_bits() as _ } } unsafe impl NativeWasmType for f64 { const TYPE: Type = Type::F64; - fn from_bits(bits: u64) -> Self { - bits as _ + fn from_binary(bits: u64) -> Self { + f64::from_bits(bits) } - fn to_bits(self) -> u64 { - self as _ + fn to_binary(self) -> u64 { + self.to_bits() } } @@ -516,3 +516,58 @@ where } } } + +#[cfg(test)] +mod tests { + use crate::types::NativeWasmType; + use crate::types::WasmExternType; + + #[test] + fn test_native_types_round_trip() { + assert_eq!( + 42i32, + i32::from_native(i32::from_binary((42i32).to_native().to_binary())) + ); + + assert_eq!( + -42i32, + i32::from_native(i32::from_binary((-42i32).to_native().to_binary())) + ); + + use std::i64; + let xi64 = i64::MAX; + assert_eq!( + xi64, + i64::from_native(i64::from_binary((xi64).to_native().to_binary())) + ); + let yi64 = i64::MIN; + assert_eq!( + yi64, + i64::from_native(i64::from_binary((yi64).to_native().to_binary())) + ); + + assert_eq!( + 16.5f32, + f32::from_native(f32::from_binary((16.5f32).to_native().to_binary())) + ); + + assert_eq!( + -16.5f32, + f32::from_native(f32::from_binary((-16.5f32).to_native().to_binary())) + ); + + use std::f64; + let xf64: f64 = f64::MAX; + assert_eq!( + xf64, + f64::from_native(f64::from_binary((xf64).to_native().to_binary())) + ); + + let yf64: f64 = f64::MIN; + assert_eq!( + yf64, + f64::from_native(f64::from_binary((yf64).to_native().to_binary())) + ); + } + +} diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index 7d9039b7d..6649b6a59 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -11,7 +11,16 @@ use hashbrown::HashMap; /// The context of the currently running WebAssembly instance. /// +/// This is implicitly passed to every WebAssembly function. +/// Since this is per-instance, each field has a statically +/// (as in after compiling the wasm) known size, so no +/// runtime checks are necessary. /// +/// While the runtime currently just passes this around +/// as the first, implicit parameter of every function, +/// it may someday be pinned to a register (especially +/// on arm, which has a ton of registers) to reduce +/// register shuffling. #[derive(Debug)] #[repr(C)] pub struct Ctx { @@ -20,11 +29,25 @@ pub struct Ctx { pub(crate) local_functions: *const *const Func, + /// These are pointers to things that are known to be owned + /// by the owning `Instance`. local_backing: *mut LocalBacking, import_backing: *mut ImportBacking, pub module: *const ModuleInner, + //// This is intended to be user-supplied, per-instance + /// contextual data. There are currently some issue with it, + /// notably that it cannot be set before running the `start` + /// function in a WebAssembly module. + /// + /// [#219](https://github.com/wasmerio/wasmer/pull/219) fixes that + /// issue, as well as allowing the user to have *per-function* + /// context, instead of just per-instance. pub data: *mut c_void, + + /// If there's a function set in this field, it gets called + /// when the context is destructed, e.g. when an `Instance` + /// is dropped. pub data_finalizer: Option, } diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index 4b2768bc6..967d9a8d8 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -94,7 +94,9 @@ impl Cache for FileSystemCache { let mmap = unsafe { Mmap::map(&file)? }; let serialized_cache = Artifact::deserialize(&mmap[..])?; - unsafe { wasmer_runtime_core::load_cache_with(serialized_cache, super::default_compiler()) } + unsafe { + wasmer_runtime_core::load_cache_with(serialized_cache, &super::default_compiler()) + } } fn store(&mut self, key: WasmHash, module: Module) -> Result<(), CacheError> { diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index ba7f4440b..421181ba8 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] //! Wasmer-runtime is a library that makes embedding WebAssembly //! in your application easy, efficient, and safe. @@ -131,7 +131,7 @@ use wasmer_runtime_core::backend::{Compiler, CompilerConfig}; /// # Errors: /// If the operation fails, the function returns `Err(error::CompileError::...)`. pub fn compile(wasm: &[u8]) -> error::CompileResult { - wasmer_runtime_core::compile_with(&wasm[..], default_compiler()) + wasmer_runtime_core::compile_with(&wasm[..], &default_compiler()) } /// The same as `compile` but takes a `CompilerConfig` for the purpose of @@ -140,7 +140,7 @@ pub fn compile_with_config( wasm: &[u8], compiler_config: CompilerConfig, ) -> error::CompileResult { - wasmer_runtime_core::compile_with_config(&wasm[..], default_compiler(), compiler_config) + wasmer_runtime_core::compile_with_config(&wasm[..], &default_compiler(), compiler_config) } /// The same as `compile_with_config` but takes a `Compiler` for the purpose of @@ -177,9 +177,7 @@ pub fn instantiate(wasm: &[u8], import_object: &ImportObject) -> error::Result &'static dyn Compiler { - use lazy_static::lazy_static; - +pub fn default_compiler() -> impl Compiler { #[cfg(feature = "llvm")] use wasmer_llvm_backend::LLVMCompiler as DefaultCompiler; @@ -189,11 +187,7 @@ pub fn default_compiler() -> &'static dyn Compiler { #[cfg(not(any(feature = "llvm", feature = "singlepass")))] use wasmer_clif_backend::CraneliftCompiler as DefaultCompiler; - lazy_static! { - static ref DEFAULT_COMPILER: DefaultCompiler = { DefaultCompiler::new() }; - } - - &*DEFAULT_COMPILER as &dyn Compiler + DefaultCompiler::new() } /// The current version of this crate diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index f7868bc53..9aa6c9151 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -212,10 +212,10 @@ impl RunnableModule for X64ExecutionContext { user_error: *mut Option>, num_params_plus_one: Option>, ) -> bool { - let rm: &Box = &unsafe { &*(*ctx).module }.runnable_module; - let execution_context = unsafe { - ::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm) - }; + let rm: &Box = &(&*(*ctx).module).runnable_module; + let execution_context = + ::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm); + let args = ::std::slice::from_raw_parts( args, num_params_plus_one.unwrap().as_ptr() as usize - 1, diff --git a/lib/singlepass-backend/src/lib.rs b/lib/singlepass-backend/src/lib.rs index eec02cbfd..f1011591d 100644 --- a/lib/singlepass-backend/src/lib.rs +++ b/lib/singlepass-backend/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] #![feature(proc_macro_hygiene)] #[cfg(not(any( diff --git a/lib/singlepass-backend/src/protect_unix.rs b/lib/singlepass-backend/src/protect_unix.rs index 83ba42c79..6204134a7 100644 --- a/lib/singlepass-backend/src/protect_unix.rs +++ b/lib/singlepass-backend/src/protect_unix.rs @@ -1,5 +1,5 @@ //! Installing signal handlers allows us to handle traps and out-of-bounds memory -//! accesses that occur when runniing webassembly. +//! accesses that occur when runniing WebAssembly. //! //! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622 //! diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 241cc607c..86f9ceaac 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] #[macro_use] extern crate log; diff --git a/lib/wasi/src/state.rs b/lib/wasi/src/state.rs index f1608e768..ff1374517 100644 --- a/lib/wasi/src/state.rs +++ b/lib/wasi/src/state.rs @@ -139,8 +139,10 @@ pub enum Kind { handle: WasiFile, }, Dir { - // TODO: wrap it like WasiFile + /// Parent directory + parent: Option, /// The path on the host system where the directory is located + // TODO: wrap it like WasiFile path: PathBuf, /// The entries of a directory are lazily filled. entries: HashMap, @@ -196,6 +198,7 @@ impl WasiFs { let cur_dir_metadata = cur_dir.metadata().expect("Could not find directory"); let kind = if cur_dir_metadata.is_dir() { Kind::Dir { + parent: None, path: cur_dir.clone(), entries: Default::default(), } @@ -414,6 +417,32 @@ impl WasiFs { ); Ok(idx) } + + pub fn get_base_path_for_directory(&self, directory: Inode) -> Option { + let mut path_segments = vec![]; + let mut cur_inode = directory; + loop { + path_segments.push(self.inodes[cur_inode].name.clone()); + + if let Kind::Dir { parent, .. } = &self.inodes[cur_inode].kind { + if let Some(p_inode) = parent { + cur_inode = *p_inode; + } else { + break; + } + } else { + return None; + } + } + + path_segments.reverse(); + Some( + path_segments + .iter() + .skip(1) + .fold(path_segments.first()?.clone(), |a, b| a + "/" + b), + ) + } } #[derive(Debug)] diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 0389273fc..ace1f1c8e 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -767,14 +767,74 @@ pub fn fd_readdir( ) -> __wasi_errno_t { debug!("wasi::fd_readdir"); let memory = ctx.memory(0); + let state = get_wasi_state(ctx); + // TODO: figure out how this is supposed to work; + // is it supposed to pack the buffer full every time until it can't? or do one at a time? - if let (Ok(buf_arr_cell), Ok(bufused_cell)) = - (buf.deref(memory, 0, buf_len), bufused.deref(memory)) - { - unimplemented!("wasi::fd_readdir") + let buf_arr_cell = wasi_try!(buf.deref(memory, 0, buf_len)); + let bufused_cell = wasi_try!(bufused.deref(memory)); + let working_dir = wasi_try!(state.fs.fd_map.get(&fd).ok_or(__WASI_EBADF)); + let mut cur_cookie = cookie; + let mut buf_idx = 0; + + if let Kind::Dir { path, .. } = &state.fs.inodes[working_dir.inode].kind { + // we need to support multiple calls, + // simple and obviously correct implementation for now: + // maintain consistent order via lexacographic sorting + let mut entries = wasi_try!(wasi_try!(std::fs::read_dir(path).map_err(|_| __WASI_EIO)) + .collect::, _>>() + .map_err(|_| __WASI_EIO)); + entries.sort_by(|a, b| a.file_name().cmp(&b.file_name())); + + for entry in entries.iter().skip(cookie as usize) { + cur_cookie += 1; + let entry_path = entry.path(); + let entry_path_str = entry_path.to_string_lossy(); + let namlen = entry_path_str.len(); + let dirent = __wasi_dirent_t { + d_next: cur_cookie, + d_ino: 0, // TODO: inode + d_namlen: namlen as u32, + d_type: { + let file_type = wasi_try!(entry.file_type().map_err(|_| __WASI_EIO)); + // TODO: handle other file types + if file_type.is_dir() { + __WASI_FILETYPE_DIRECTORY + } else if file_type.is_file() { + __WASI_FILETYPE_REGULAR_FILE + } else if file_type.is_symlink() { + __WASI_FILETYPE_SYMBOLIC_LINK + } else { + __WASI_FILETYPE_UNKNOWN + } + }, + }; + let dirent_bytes = dirent_to_le_bytes(&dirent); + let upper_limit = std::cmp::min( + buf_len as usize - buf_idx, + std::mem::size_of::<__wasi_dirent_t>(), + ); + for i in 0..upper_limit { + buf_arr_cell[i + buf_idx].set(dirent_bytes[i]); + } + buf_idx += upper_limit; + if upper_limit != std::mem::size_of::<__wasi_dirent_t>() { + break; + } + let upper_limit = std::cmp::min(buf_len as usize - buf_idx, namlen); + for (i, b) in entry_path_str.bytes().take(upper_limit).enumerate() { + buf_arr_cell[i + buf_idx].set(b); + } + buf_idx += upper_limit; + if upper_limit != namlen { + break; + } + } } else { - __WASI_EFAULT + return __WASI_ENOTDIR; } + bufused_cell.set(buf_idx as u32); + __WASI_ESUCCESS } /// ### `fd_renumber()` @@ -788,15 +848,14 @@ pub fn fd_renumber(ctx: &mut Ctx, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_ debug!("wasi::fd_renumber: from={}, to={}", from, to); let state = get_wasi_state(ctx); let fd_entry = wasi_try!(state.fs.fd_map.get(&from).ok_or(__WASI_EBADF)); + let new_fd_entry = Fd { + // TODO: verify this is correct + rights: fd_entry.rights_inheriting, + ..*fd_entry + }; - state.fs.fd_map.insert( - to, - Fd { - // TODO: verify this is correct - rights: fd_entry.rights_inheriting, - ..*fd_entry - }, - ); + state.fs.fd_map.insert(to, new_fd_entry); + state.fs.fd_map.remove(&from); __WASI_ESUCCESS } @@ -1025,7 +1084,7 @@ pub fn path_create_directory( wasi_try!(std::fs::create_dir(&path).map_err(|_| __WASI_EIO)); let kind = Kind::Dir { - //parent: Some(working_dir.inode), + parent: Some(working_dir.inode), path: path.clone(), entries: Default::default(), }; @@ -1118,6 +1177,7 @@ pub fn path_filestat_get( return __WASI_ENOTDIR; } let kind = Kind::Dir { + parent: Some(inode), path: std::path::PathBuf::from(&segment), entries: Default::default(), }; @@ -1177,6 +1237,7 @@ pub fn path_filestat_get( is_preopened: false, // is this correct? name: last_segment.clone(), kind: Kind::Dir { + parent: Some(inode), path: std::path::PathBuf::from(&last_segment), entries: Default::default(), }, @@ -1361,7 +1422,10 @@ pub fn path_open( } let mut cur_dir_inode = working_dir.inode; - let mut cumulative_path = std::path::PathBuf::from("."); + let mut cumulative_path = std::path::PathBuf::from(wasi_try!(state + .fs + .get_base_path_for_directory(working_dir.inode) + .ok_or(__WASI_EIO))); // traverse path if path_vec.len() > 1 { @@ -1391,11 +1455,13 @@ pub fn path_open( }; // TODO: handle __WASI_O_TRUNC on directories + dbg!(&cumulative_path); // TODO: refactor and reuse let cur_file_metadata = wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_EINVAL)); let kind = if cur_file_metadata.is_dir() { Kind::Dir { + parent: Some(cur_dir_inode), path: cumulative_path.clone(), entries: Default::default(), } @@ -1457,41 +1523,57 @@ pub fn path_open( .fs .create_fd(fs_rights_base, fs_rights_inheriting, fs_flags, child)) } else { + let file_metadata = wasi_try!(file_path.metadata().map_err(|_| __WASI_ENOENT)); // if entry does not exist in parent directory, try to lazily // load it; possibly creating or truncating it if flags set - let real_opened_file = { - let mut open_options = std::fs::OpenOptions::new(); - let open_options = open_options.read(true).write(true); - let open_options = if o_flags & __WASI_O_CREAT != 0 { - debug!( - "File {} may be created when opened if it does not exist", - &path_string - ); - open_options.create(true) - } else { - open_options - }; - let open_options = if o_flags & __WASI_O_TRUNC != 0 { - debug!("File {} will be truncated when opened", &path_string); - open_options.truncate(true) - } else { - open_options - }; - let real_open_file = - wasi_try!(open_options.open(&file_path).map_err(|_| __WASI_EIO)); - debug!("Opening host file {}", &path_string); + let kind = if file_metadata.is_dir() { + // special dir logic + Kind::Dir { + parent: Some(cur_dir_inode), + path: file_path.clone(), + entries: Default::default(), + } + } else { + // file is not a dir + let real_opened_file = { + let mut open_options = std::fs::OpenOptions::new(); + let open_options = open_options.read(true).write(true); + let open_options = if o_flags & __WASI_O_CREAT != 0 { + debug!( + "File {:?} may be created when opened if it does not exist", + &file_path + ); + open_options.create(true) + } else { + open_options + }; + let open_options = if o_flags & __WASI_O_TRUNC != 0 { + debug!("File {:?} will be truncated when opened", &file_path); + open_options.truncate(true) + } else { + open_options + }; + debug!("Opening host file {:?}", &file_path); + let real_open_file = wasi_try!(open_options.open(&file_path).map_err(|e| { + dbg!(e); + __WASI_EIO + })); - real_open_file + real_open_file + }; + Kind::File { + handle: WasiFile::HostFile(real_opened_file), + } }; + // record lazily loaded or newly created fd let new_inode = state.fs.inodes.insert(InodeVal { stat: __wasi_filestat_t::default(), is_preopened: false, name: file_name.clone(), - kind: Kind::File { - handle: WasiFile::HostFile(real_opened_file), - }, + kind, }); + // reborrow to insert entry if let Kind::Dir { entries, .. } = &mut state.fs.inodes[working_dir.inode].kind { entries.insert(file_name.clone(), new_inode); diff --git a/lib/wasi/src/syscalls/types.rs b/lib/wasi/src/syscalls/types.rs index 636e1858e..d484db08b 100644 --- a/lib/wasi/src/syscalls/types.rs +++ b/lib/wasi/src/syscalls/types.rs @@ -43,6 +43,31 @@ pub struct __wasi_dirent_t { pub d_type: __wasi_filetype_t, } +unsafe impl ValueType for __wasi_dirent_t {} + +pub fn dirent_to_le_bytes(ent: &__wasi_dirent_t) -> Vec { + use std::mem::transmute; + let mut out = Vec::with_capacity(std::mem::size_of::<__wasi_dirent_t>()); + let bytes: [u8; 8] = unsafe { transmute(ent.d_next.to_le()) }; + for &b in &bytes { + out.push(b); + } + let bytes: [u8; 8] = unsafe { transmute(ent.d_ino.to_le()) }; + for &b in &bytes { + out.push(b); + } + let bytes: [u8; 4] = unsafe { transmute(ent.d_namlen.to_le()) }; + for &b in &bytes { + out.push(b); + } + out.push(ent.d_type); + out.push(0); + out.push(0); + out.push(0); + assert_eq!(out.len(), std::mem::size_of::<__wasi_dirent_t>()); + out +} + pub type __wasi_errno_t = u16; pub const __WASI_ESUCCESS: u16 = 0; pub const __WASI_E2BIG: u16 = 1; diff --git a/lib/win-exception-handler/src/lib.rs b/lib/win-exception-handler/src/lib.rs index dfb95d0e1..5329e1cc0 100644 --- a/lib/win-exception-handler/src/lib.rs +++ b/lib/win-exception-handler/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] #[cfg(windows)] mod exception_handling; diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index cd36651a5..14386d1b1 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] extern crate structopt; diff --git a/src/lib.rs b/src/lib.rs index 9105e278e..78d6dae28 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(unused_imports, unused_variables)] +#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)] #[macro_use] extern crate wasmer_runtime_core;