diff --git a/lib/runtime-c-api/src/export.rs b/lib/runtime-c-api/src/export.rs index d6dfa5d97..3112b6178 100644 --- a/lib/runtime-c-api/src/export.rs +++ b/lib/runtime-c-api/src/export.rs @@ -85,12 +85,39 @@ pub union wasmer_import_export_value { /// List of export/import kinds. #[allow(non_camel_case_types)] #[repr(u32)] -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] +// ================ +// ! DANGER ! +// ================ +// Do not modify these values without updating the `TryFrom` implementation below pub enum wasmer_import_export_kind { - WASM_FUNCTION, - WASM_GLOBAL, - WASM_MEMORY, - WASM_TABLE, + WASM_FUNCTION = 0, + WASM_GLOBAL = 1, + WASM_MEMORY = 2, + WASM_TABLE = 3, +} + +impl wasmer_import_export_kind { + pub fn to_str(&self) -> &'static str { + match self { + Self::WASM_FUNCTION => "function", + Self::WASM_GLOBAL => "global", + Self::WASM_MEMORY => "memory", + Self::WASM_TABLE => "table", + } + } +} + +impl std::convert::TryFrom for wasmer_import_export_kind { + type Error = (); + + fn try_from(value: u32) -> Result { + if value > 3 { + Err(()) + } else { + Ok(unsafe { std::mem::transmute(value) }) + } + } } /// Gets export descriptors for the given module diff --git a/lib/runtime-c-api/src/import.rs b/lib/runtime-c-api/src/import.rs index 19f415722..52d196dd0 100644 --- a/lib/runtime-c-api/src/import.rs +++ b/lib/runtime-c-api/src/import.rs @@ -9,7 +9,7 @@ use crate::{ wasmer_byte_array, wasmer_result_t, }; use libc::c_uint; -use std::{ffi::c_void, ptr, slice, sync::Arc}; +use std::{convert::TryFrom, ffi::c_void, ptr, slice, sync::Arc}; use wasmer_runtime::{Global, Memory, Module, Table}; use wasmer_runtime_core::{ export::{Context, Export, FuncPointer}, @@ -159,6 +159,118 @@ mod wasi { #[cfg(feature = "wasi")] pub use self::wasi::*; +/// Gets an entry from an ImportObject at the name and namespace. +/// Stores an immutable reference to `name` and `namespace` in `import`. +/// +/// The caller owns all data involved. +/// `import_export_value` will be written to based on `tag`, `import_export_value` must be +/// initialized to point to the type specified by `tag`. Failure to do so may result +/// in data corruption or undefined behavior. +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_object_get_import( + import_object: *const wasmer_import_object_t, + namespace: wasmer_byte_array, + name: wasmer_byte_array, + import: *mut wasmer_import_t, + import_export_value: *mut wasmer_import_export_value, + tag: u32, +) -> wasmer_result_t { + let tag: wasmer_import_export_kind = if let Ok(t) = TryFrom::try_from(tag) { + t + } else { + update_last_error(CApiError { + msg: "wasmer_import_export_tag out of range".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject); + let namespace_str = if let Ok(ns) = namespace.as_str() { + ns + } else { + update_last_error(CApiError { + msg: "error converting namespace to UTF-8 string".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + let name_str = if let Ok(name) = name.as_str() { + name + } else { + update_last_error(CApiError { + msg: "error converting name to UTF-8 string".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + if import.is_null() || import_export_value.is_null() { + update_last_error(CApiError { + msg: "pointer to import and import_export_value must not be null".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + } + let import_out = &mut *import; + let import_export_value_out = &mut *import_export_value; + if let Some(export) = + import_object.maybe_with_namespace(namespace_str, |ns| ns.get_export(name_str)) + { + match export { + Export::Function { .. } => { + if tag != wasmer_import_export_kind::WASM_FUNCTION { + update_last_error(CApiError { + msg: format!("Found function, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_FUNCTION; + let writer = import_export_value_out.func as *mut Export; + *writer = export.clone(); + } + Export::Memory(memory) => { + if tag != wasmer_import_export_kind::WASM_MEMORY { + update_last_error(CApiError { + msg: format!("Found memory, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_MEMORY; + let writer = import_export_value_out.func as *mut Memory; + *writer = memory.clone(); + } + Export::Table(table) => { + if tag != wasmer_import_export_kind::WASM_TABLE { + update_last_error(CApiError { + msg: format!("Found table, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_TABLE; + let writer = import_export_value_out.func as *mut Table; + *writer = table.clone(); + } + Export::Global(global) => { + if tag != wasmer_import_export_kind::WASM_GLOBAL { + update_last_error(CApiError { + msg: format!("Found global, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_GLOBAL; + let writer = import_export_value_out.func as *mut Global; + *writer = global.clone(); + } + } + + import_out.value = *import_export_value; + import_out.module_name = namespace; + import_out.import_name = name; + + wasmer_result_t::WASMER_OK + } else { + update_last_error(CApiError { + msg: format!("Export {} {} not found", namespace_str, name_str), + }); + wasmer_result_t::WASMER_ERROR + } +} + /// Extends an existing import object with new imports #[allow(clippy::cast_ptr_alignment)] #[no_mangle] diff --git a/lib/runtime-c-api/src/instance.rs b/lib/runtime-c-api/src/instance.rs index 69fa0131a..b39e52d7e 100644 --- a/lib/runtime-c-api/src/instance.rs +++ b/lib/runtime-c-api/src/instance.rs @@ -75,6 +75,7 @@ pub unsafe extern "C" fn wasmer_instantiate( let namespace = namespaces.entry(module_name).or_insert_with(Namespace::new); + // TODO check that tag is actually in bounds here let export = match import.tag { wasmer_import_export_kind::WASM_MEMORY => { let mem = import.value.memory as *mut Memory; diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 23caa54cc..dda77d7c4 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -10,10 +10,10 @@ * List of export/import kinds. */ enum wasmer_import_export_kind { - WASM_FUNCTION, - WASM_GLOBAL, - WASM_MEMORY, - WASM_TABLE, + WASM_FUNCTION = 0, + WASM_GLOBAL = 1, + WASM_MEMORY = 2, + WASM_TABLE = 3, }; typedef uint32_t wasmer_import_export_kind; @@ -469,6 +469,22 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec wasmer_import_t *imports, unsigned int imports_len); +/** + * Gets an entry from an ImportObject at the name and namespace. + * Stores an immutable reference to `name` and `namespace` in `import`. + * + * The caller owns all data involved. + * `import_export_value` will be written to based on `tag`, `import_export_value` must be + * initialized to point to the type specified by `tag`. Failure to do so may result + * in data corruption or undefined behavior. + */ +wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *import_object, + wasmer_byte_array namespace_, + wasmer_byte_array name, + wasmer_import_t *import, + wasmer_import_export_value *import_export_value, + uint32_t tag); + /** * Creates a new empty import object. * See also `wasmer_import_object_append` diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index da8e39118..39bc12c69 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -8,10 +8,10 @@ /// List of export/import kinds. enum class wasmer_import_export_kind : uint32_t { - WASM_FUNCTION, - WASM_GLOBAL, - WASM_MEMORY, - WASM_TABLE, + WASM_FUNCTION = 0, + WASM_GLOBAL = 1, + WASM_MEMORY = 2, + WASM_TABLE = 3, }; enum class wasmer_result_t { @@ -371,6 +371,20 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec wasmer_import_t *imports, unsigned int imports_len); +/// Gets an entry from an ImportObject at the name and namespace. +/// Stores an immutable reference to `name` and `namespace` in `import`. +/// +/// The caller owns all data involved. +/// `import_export_value` will be written to based on `tag`, `import_export_value` must be +/// initialized to point to the type specified by `tag`. Failure to do so may result +/// in data corruption or undefined behavior. +wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *import_object, + wasmer_byte_array namespace_, + wasmer_byte_array name, + wasmer_import_t *import, + wasmer_import_export_value *import_export_value, + uint32_t tag); + /// Creates a new empty import object. /// See also `wasmer_import_object_append` wasmer_import_object_t *wasmer_import_object_new();