wasmer/backend/sys/entities/memory/
view.rs

1use crate::MemoryAccessError;
2use crate::store::AsStoreRef;
3use std::marker::PhantomData;
4use std::mem::MaybeUninit;
5use std::slice;
6use std::{convert::TryInto, ops::Range};
7use wasmer_types::Pages;
8use wasmer_vm::LinearMemory;
9
10use super::{Memory, MemoryBuffer};
11
12/// A WebAssembly `memory` view.
13///
14/// A memory view is used to read and write to the linear memory.
15///
16/// After a memory is grown a view must not be used anymore. Views are
17/// created using the Memory.grow() method.
18#[derive(Debug)]
19pub struct MemoryView<'a> {
20    pub(crate) buffer: MemoryBuffer<'a>,
21    pub(crate) size: Pages,
22}
23
24impl<'a> MemoryView<'a> {
25    pub(crate) fn new(memory: &Memory, store: &'a (impl AsStoreRef + ?Sized)) -> Self {
26        let size = memory
27            .handle
28            .get(store.as_store_ref().objects().as_sys())
29            .size();
30
31        let definition = memory
32            .handle
33            .get(store.as_store_ref().objects().as_sys())
34            .vmmemory();
35        let def = unsafe { definition.as_ref() };
36
37        Self {
38            buffer: MemoryBuffer {
39                base: def.base,
40                len: def.current_length,
41                marker: PhantomData,
42            },
43            size,
44        }
45    }
46
47    /// Returns the pointer to the raw bytes of the `Memory`.
48    //
49    // This used by wasmer-c-api, but should be treated
50    // as deprecated and not used in future code.
51    #[doc(hidden)]
52    pub fn data_ptr(&self) -> *mut u8 {
53        self.buffer.base
54    }
55
56    /// Returns the size (in bytes) of the `Memory`.
57    pub fn data_size(&self) -> u64 {
58        self.buffer.len.try_into().unwrap()
59    }
60
61    /// Retrieve a slice of the memory contents.
62    ///
63    /// # Safety
64    ///
65    /// Until the returned slice is dropped, it is undefined behaviour to
66    /// modify the memory contents in any way including by calling a wasm
67    /// function that writes to the memory or by resizing the memory.
68    #[doc(hidden)]
69    pub unsafe fn data_unchecked(&self) -> &[u8] {
70        unsafe { self.data_unchecked_mut() }
71    }
72
73    /// Retrieve a mutable slice of the memory contents.
74    ///
75    /// # Safety
76    ///
77    /// This method provides interior mutability without an UnsafeCell. Until
78    /// the returned value is dropped, it is undefined behaviour to read or
79    /// write to the pointed-to memory in any way except through this slice,
80    /// including by calling a wasm function that reads the memory contents or
81    /// by resizing this Memory.
82    #[allow(clippy::mut_from_ref)]
83    #[doc(hidden)]
84    pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] {
85        unsafe { slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) }
86    }
87
88    /// Returns the size (in [`Pages`]) of the `Memory`.
89    ///
90    /// # Example
91    ///
92    /// ```
93    /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
94    /// # let mut store = Store::default();
95    /// #
96    /// let m = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap();
97    ///
98    /// assert_eq!(m.view(&mut store).size(), Pages(1));
99    /// ```
100    pub fn size(&self) -> Pages {
101        self.size
102    }
103
104    #[inline]
105    pub(crate) fn buffer(&'a self) -> MemoryBuffer<'a> {
106        self.buffer
107    }
108
109    /// Safely reads bytes from the memory at the given offset.
110    ///
111    /// The full buffer will be filled, otherwise a `MemoryAccessError` is returned
112    /// to indicate an out-of-bounds access.
113    ///
114    /// This method is guaranteed to be safe (from the host side) in the face of
115    /// concurrent writes.
116    pub fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), MemoryAccessError> {
117        self.buffer.read(offset, buf)
118    }
119
120    /// Safely reads a single byte from memory at the given offset
121    ///
122    /// This method is guaranteed to be safe (from the host side) in the face of
123    /// concurrent writes.
124    pub fn read_u8(&self, offset: u64) -> Result<u8, MemoryAccessError> {
125        let mut buf = [0u8; 1];
126        self.read(offset, &mut buf)?;
127        Ok(buf[0])
128    }
129
130    /// Safely reads bytes from the memory at the given offset.
131    ///
132    /// This method is similar to `read` but allows reading into an
133    /// uninitialized buffer. An initialized view of the buffer is returned.
134    ///
135    /// The full buffer will be filled, otherwise a `MemoryAccessError` is returned
136    /// to indicate an out-of-bounds access.
137    ///
138    /// This method is guaranteed to be safe (from the host side) in the face of
139    /// concurrent writes.
140    pub fn read_uninit<'b>(
141        &self,
142        offset: u64,
143        buf: &'b mut [MaybeUninit<u8>],
144    ) -> Result<&'b mut [u8], MemoryAccessError> {
145        self.buffer.read_uninit(offset, buf)
146    }
147
148    /// Safely writes bytes to the memory at the given offset.
149    ///
150    /// If the write exceeds the bounds of the memory then a `MemoryAccessError` is
151    /// returned.
152    ///
153    /// This method is guaranteed to be safe (from the host side) in the face of
154    /// concurrent reads/writes.
155    pub fn write(&self, offset: u64, data: &[u8]) -> Result<(), MemoryAccessError> {
156        self.buffer.write(offset, data)
157    }
158
159    /// Safely reads a single byte from memory at the given offset
160    ///
161    /// This method is guaranteed to be safe (from the host side) in the face of
162    /// concurrent writes.
163    pub fn write_u8(&self, offset: u64, val: u8) -> Result<(), MemoryAccessError> {
164        let buf = [val];
165        self.write(offset, &buf)?;
166        Ok(())
167    }
168
169    #[allow(unused)]
170    /// Copies the memory and returns it as a vector of bytes
171    pub fn copy_to_vec(&self) -> Result<Vec<u8>, MemoryAccessError> {
172        self.copy_range_to_vec(0..self.data_size())
173    }
174
175    #[allow(unused)]
176    /// Copies a range of the memory and returns it as a vector of bytes
177    pub fn copy_range_to_vec(&self, range: Range<u64>) -> Result<Vec<u8>, MemoryAccessError> {
178        let mut new_memory = Vec::new();
179        let mut offset = range.start;
180        let end = range.end.min(self.data_size());
181        let mut chunk = [0u8; 40960];
182        while offset < end {
183            let remaining = end - offset;
184            let sublen = remaining.min(chunk.len() as u64) as usize;
185            self.read(offset, &mut chunk[..sublen])?;
186            new_memory.extend_from_slice(&chunk[..sublen]);
187            offset += sublen as u64;
188        }
189        Ok(new_memory)
190    }
191
192    #[allow(unused)]
193    /// Copies the memory to another new memory object
194    pub fn copy_to_memory(&self, amount: u64, new_memory: &Self) -> Result<(), MemoryAccessError> {
195        let mut offset = 0;
196        let mut chunk = [0u8; 40960];
197        while offset < amount {
198            let remaining = amount - offset;
199            let sublen = remaining.min(chunk.len() as u64) as usize;
200            self.read(offset, &mut chunk[..sublen])?;
201
202            new_memory.write(offset, &chunk[..sublen])?;
203
204            offset += sublen as u64;
205        }
206        Ok(())
207    }
208}