wasmer_types/
value.rs

1use core::{fmt, marker::PhantomData, mem::MaybeUninit};
2
3/// Raw representation of a WebAssembly value.
4///
5/// In most cases you will want to use the type-safe `Value` wrapper instead.
6#[allow(missing_docs)]
7#[repr(C)]
8#[derive(Copy, Clone)]
9pub union RawValue {
10    pub i32: i32,
11    pub i64: i64,
12    pub u32: u32,
13    pub u64: u64,
14    pub f32: f32,
15    pub f64: f64,
16    pub i128: i128,
17    pub u128: u128,
18    pub funcref: usize,
19    pub externref: usize,
20    pub exnref: u32,
21    pub bytes: [u8; 16],
22}
23
24impl From<i32> for RawValue {
25    fn from(value: i32) -> Self {
26        Self { i32: value }
27    }
28}
29
30impl From<i64> for RawValue {
31    fn from(value: i64) -> Self {
32        Self { i64: value }
33    }
34}
35
36impl From<f32> for RawValue {
37    fn from(value: f32) -> Self {
38        Self { f32: value }
39    }
40}
41
42impl From<f64> for RawValue {
43    fn from(value: f64) -> Self {
44        Self { f64: value }
45    }
46}
47
48impl Default for RawValue {
49    fn default() -> Self {
50        Self { bytes: [0; 16] }
51    }
52}
53
54impl fmt::Debug for RawValue {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        f.debug_struct("RawValue")
57            .field("bytes", unsafe { &self.bytes })
58            .finish()
59    }
60}
61
62macro_rules! partial_eq {
63    ($($t:ty => $f:tt),*) => ($(
64        impl PartialEq<$t> for RawValue {
65            fn eq(&self, o: &$t) -> bool {
66                unsafe { self.$f == *o }
67            }
68        }
69    )*)
70}
71
72partial_eq! {
73    i32 => i32,
74    u32 => u32,
75    i64 => i64,
76    u64 => u64,
77    f32 => f32,
78    f64 => f64,
79    i128 => i128,
80    u128 => u128
81}
82
83impl PartialEq for RawValue {
84    fn eq(&self, o: &Self) -> bool {
85        unsafe { self.u128 == o.u128 }
86    }
87}
88
89/// Trait for a Value type. A Value type is a type that is always valid and may
90/// be safely copied.
91///
92/// # Safety
93///
94/// To maintain safety, types which implement this trait must be valid for all
95/// bit patterns. This means that it cannot contain enums, `bool`, references,
96/// etc.
97///
98/// Concretely a `u32` is a Value type because every combination of 32 bits is
99/// a valid `u32`. However a `bool` is _not_ a Value type because any bit patterns
100/// other than `0` and `1` are invalid in Rust and may cause undefined behavior if
101/// a `bool` is constructed from those bytes.
102///
103/// Additionally this trait has a method which zeros out any uninitializes bytes
104/// prior to writing them to Wasm memory, which prevents information leaks into
105/// the sandbox.
106pub unsafe trait ValueType: Copy {
107    /// This method is passed a byte slice which contains the byte
108    /// representation of `self`. It must zero out any bytes which are
109    /// uninitialized (e.g. padding bytes).
110    fn zero_padding_bytes(&self, bytes: &mut [MaybeUninit<u8>]);
111}
112
113// Trivial implementations for primitive types and arrays of them.
114macro_rules! primitives {
115    ($($t:ident)*) => ($(
116        unsafe impl ValueType for $t {
117            #[inline]
118            fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
119        }
120        unsafe impl<const N: usize> ValueType for [$t; N] {
121            #[inline]
122            fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
123        }
124    )*)
125}
126primitives! {
127    bool
128    i8 u8
129    i16 u16
130    i32 u32
131    i64 u64
132    i128 u128
133    isize usize
134    f32 f64
135}
136
137// This impl for PhantomData allows #[derive(ValueType)] to work with types
138// that contain a PhantomData.
139unsafe impl<T: ?Sized> ValueType for PhantomData<T> {
140    #[inline]
141    fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {}
142}