#![doc(html_favicon_url = "https://dev.namada.net/master/favicon.png")]
#![doc(html_logo_url = "https://dev.namada.net/master/rustdoc-logo.png")]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(rustdoc::private_intra_doc_links)]
#![warn(
missing_docs,
rust_2018_idioms,
clippy::cast_sign_loss,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_lossless,
clippy::arithmetic_side_effects,
clippy::dbg_macro,
clippy::print_stdout,
clippy::print_stderr
)]
use std::marker::PhantomData;
use std::ptr::NonNull;
use wasmparser::{Validator, WasmFeatures};
pub mod host_env;
pub mod memory;
pub mod types;
#[cfg(feature = "wasm-runtime")]
pub mod wasm;
use thiserror::Error;
const UNTRUSTED_WASM_FEATURES: WasmFeatures = WasmFeatures {
mutable_global: false,
saturating_float_to_int: false,
sign_extension: true,
reference_types: false,
multi_value: false,
bulk_memory: false,
simd: false,
relaxed_simd: false,
threads: false,
tail_call: false,
floats: true,
multi_memory: false,
exceptions: false,
memory64: false,
extended_const: false,
component_model: false,
component_model_nested_names: false,
component_model_values: false,
function_references: false,
memory_control: false,
gc: false,
};
#[allow(missing_docs)]
#[derive(Error, Debug, Clone)]
pub enum WasmValidationError {
#[error(
"Invalid WASM using forbidden features: {0}. Expected: \
{UNTRUSTED_WASM_FEATURES:?}"
)]
ForbiddenWasmFeatures(wasmparser::BinaryReaderError),
}
pub trait WasmCacheAccess: Clone + std::fmt::Debug + Default {
fn is_read_write() -> bool;
}
#[derive(Debug, Clone, Default)]
pub struct WasmCacheRwAccess;
impl WasmCacheAccess for WasmCacheRwAccess {
fn is_read_write() -> bool {
true
}
}
#[derive(Debug, Clone, Default)]
pub struct WasmCacheRoAccess;
impl WasmCacheAccess for WasmCacheRoAccess {
fn is_read_write() -> bool {
false
}
}
#[derive(Debug)]
pub enum RoAccess {}
#[derive(Debug)]
pub enum RwAccess {}
#[derive(Debug)]
pub struct HostRef<ACCESS, T> {
data: NonNull<T>,
_access: PhantomData<*const ACCESS>,
}
impl<ACCESS, T> Clone for HostRef<ACCESS, T> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<ACCESS, T> Copy for HostRef<ACCESS, T> {}
pub type RwHostRef<T> = HostRef<RwAccess, T>;
pub type RoHostRef<T> = HostRef<RoAccess, T>;
unsafe impl<ACCESS, T> Send for HostRef<ACCESS, T> {}
unsafe impl<ACCESS, T> Sync for HostRef<ACCESS, T> {}
impl<T> HostRef<RoAccess, T> {
pub unsafe fn new(host_structure: &T) -> Self {
Self {
data: NonNull::new_unchecked(host_structure as *const _ as *mut _),
_access: PhantomData,
}
}
pub unsafe fn get<'a>(&self) -> &'a T {
self.data.as_ref()
}
}
impl<T> HostRef<RwAccess, T> {
pub unsafe fn new(host_structure: &mut T) -> Self {
Self {
data: NonNull::new_unchecked(host_structure as *mut _),
_access: PhantomData,
}
}
pub unsafe fn get<'a>(&self) -> &'a T {
self.data.as_ref()
}
pub unsafe fn get_mut<'a>(&self) -> &'a mut T {
&mut *self.data.as_ptr()
}
}
pub fn validate_untrusted_wasm(
wasm_code: impl AsRef<[u8]>,
) -> Result<(), WasmValidationError> {
let mut validator = Validator::new_with_features(UNTRUSTED_WASM_FEATURES);
let _types = validator
.validate_all(wasm_code.as_ref())
.map_err(WasmValidationError::ForbiddenWasmFeatures)?;
Ok(())
}