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}