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