1pub(crate) mod access;
2pub(crate) mod ptr;
3pub use ptr::*;
4
5use std::{
6 marker::PhantomData,
7 mem::{self, MaybeUninit},
8 ops::Range,
9 slice,
10 string::FromUtf8Error,
11};
12
13use crate::{buffer::MemoryBuffer, error::RuntimeError, view::MemoryView};
14use access::{WasmRefAccess, WasmSliceAccess};
15use thiserror::Error;
16pub use wasmer_types::{Memory32, Memory64, MemorySize, ValueType};
17
18#[derive(Clone, Copy, Debug, Error)]
20#[non_exhaustive]
21pub enum MemoryAccessError {
22 #[error("memory access out of bounds")]
24 HeapOutOfBounds,
25 #[error("address calculation overflow")]
27 Overflow,
28 #[error("string is not valid utf-8")]
30 NonUtf8String,
31 #[error("unaligned pointer read")]
33 UnalignedPointerRead,
34}
35
36impl From<MemoryAccessError> for RuntimeError {
37 fn from(err: MemoryAccessError) -> Self {
38 Self::new(err.to_string())
39 }
40}
41impl From<FromUtf8Error> for MemoryAccessError {
42 fn from(_err: FromUtf8Error) -> Self {
43 Self::NonUtf8String
44 }
45}
46
47#[derive(Clone, Copy)]
58pub struct WasmRef<'a, T: ValueType> {
59 #[allow(unused)]
60 pub(crate) buffer: MemoryBuffer<'a>,
61 pub(crate) offset: u64,
62 marker: PhantomData<*mut T>,
63}
64
65impl<'a, T: ValueType> WasmRef<'a, T> {
66 #[inline]
68 pub fn new(view: &'a MemoryView, offset: u64) -> Self {
69 Self {
70 buffer: view.buffer(),
71 offset,
72 marker: PhantomData,
73 }
74 }
75
76 #[inline]
78 pub fn offset(self) -> u64 {
79 self.offset
80 }
81
82 #[inline]
84 pub fn as_ptr32(self) -> WasmPtr<T, Memory32> {
85 WasmPtr::new(self.offset as u32)
86 }
87
88 #[inline]
90 pub fn as_ptr64(self) -> WasmPtr<T, Memory64> {
91 WasmPtr::new(self.offset)
92 }
93
94 #[inline]
96 pub fn as_ptr<M: MemorySize>(self) -> WasmPtr<T, M> {
97 let offset: M::Offset = self
98 .offset
99 .try_into()
100 .map_err(|_| "invalid offset into memory")
101 .unwrap();
102 WasmPtr::<T, M>::new(offset)
103 }
104
105 #[inline]
107 pub fn read(self) -> Result<T, MemoryAccessError> {
108 let mut out = MaybeUninit::uninit();
109 let buf =
110 unsafe { slice::from_raw_parts_mut(out.as_mut_ptr() as *mut u8, mem::size_of::<T>()) };
111 self.buffer.read(self.offset, buf)?;
112 Ok(unsafe { out.assume_init() })
113 }
115
116 #[inline]
118 pub fn write(self, val: T) -> Result<(), MemoryAccessError> {
119 self.access()?.write(val);
120 Ok(())
121 }
122
123 #[inline]
125 pub fn access(self) -> Result<WasmRefAccess<'a, T>, MemoryAccessError> {
126 WasmRefAccess::new(self, self.buffer.is_owned())
127 }
128}
129
130impl<T: ValueType> std::fmt::Debug for WasmRef<'_, T> {
131 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
132 write!(
133 f,
134 "WasmRef(offset: {}, pointer: {:#x})",
135 self.offset, self.offset
136 )
137 }
138}
139
140#[derive(Clone, Copy)]
152pub struct WasmSlice<'a, T: ValueType> {
153 pub(crate) buffer: MemoryBuffer<'a>,
154 pub(crate) offset: u64,
155 pub(crate) len: u64,
156 marker: PhantomData<*mut T>,
157}
158
159impl<'a, T: ValueType> WasmSlice<'a, T> {
160 #[inline]
165 pub fn new(view: &'a MemoryView, offset: u64, len: u64) -> Result<Self, MemoryAccessError> {
166 let total_len = len
167 .checked_mul(mem::size_of::<T>() as u64)
168 .ok_or(MemoryAccessError::Overflow)?;
169 offset
170 .checked_add(total_len)
171 .ok_or(MemoryAccessError::Overflow)?;
172 Ok(Self {
173 buffer: view.buffer(),
174 offset,
175 len,
176 marker: PhantomData,
177 })
178 }
179
180 #[inline]
182 pub fn offset(self) -> u64 {
183 self.offset
184 }
185
186 #[inline]
188 pub fn as_ptr32(self) -> WasmPtr<T, Memory32> {
189 WasmPtr::new(self.offset as u32)
190 }
191
192 #[inline]
194 pub fn as_ptr64(self) -> WasmPtr<T, Memory64> {
195 WasmPtr::new(self.offset)
196 }
197
198 #[inline]
200 pub fn len(self) -> u64 {
201 self.len
202 }
203
204 #[inline]
206 pub fn is_empty(self) -> bool {
207 self.len == 0
208 }
209
210 #[inline]
212 pub fn index(self, idx: u64) -> WasmRef<'a, T> {
213 if idx >= self.len {
214 panic!("WasmSlice out of bounds");
215 }
216 let offset = self.offset + idx * mem::size_of::<T>() as u64;
217 WasmRef {
218 buffer: self.buffer,
219 offset,
220 marker: PhantomData,
221 }
222 }
223
224 #[inline]
226 pub fn subslice(self, range: Range<u64>) -> Self {
227 if range.start > range.end || range.end > self.len {
228 panic!("WasmSlice out of bounds");
229 }
230 let offset = self.offset + range.start * mem::size_of::<T>() as u64;
231 Self {
232 buffer: self.buffer,
233 offset,
234 len: range.end - range.start,
235 marker: PhantomData,
236 }
237 }
238
239 #[inline]
241 pub fn iter(self) -> WasmSliceIter<'a, T> {
242 WasmSliceIter { slice: self }
243 }
244
245 #[inline]
247 pub fn access(self) -> Result<WasmSliceAccess<'a, T>, MemoryAccessError> {
248 WasmSliceAccess::new(self, self.buffer.is_owned())
249 }
250
251 #[inline]
253 pub fn read(self, idx: u64) -> Result<T, MemoryAccessError> {
254 self.index(idx).read()
255 }
256
257 #[inline]
259 pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> {
260 self.index(idx).write(val)
261 }
262
263 #[inline]
267 pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> {
268 assert_eq!(
269 buf.len() as u64,
270 self.len,
271 "slice length doesn't match WasmSlice length"
272 );
273 let size = std::mem::size_of_val(buf);
274 let bytes =
275 unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut MaybeUninit<u8>, size) };
276 self.buffer.read_uninit(self.offset, bytes)?;
277 Ok(())
278 }
279
280 #[inline]
286 pub fn read_slice_uninit(
287 self,
288 buf: &mut [MaybeUninit<T>],
289 ) -> Result<&mut [T], MemoryAccessError> {
290 assert_eq!(
291 buf.len() as u64,
292 self.len,
293 "slice length doesn't match WasmSlice length"
294 );
295 let bytes = unsafe {
296 slice::from_raw_parts_mut(
297 buf.as_mut_ptr() as *mut MaybeUninit<u8>,
298 buf.len() * mem::size_of::<T>(),
299 )
300 };
301 self.buffer.read_uninit(self.offset, bytes)?;
302 Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) })
303 }
304
305 #[inline]
309 pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> {
310 assert_eq!(
311 data.len() as u64,
312 self.len,
313 "slice length doesn't match WasmSlice length"
314 );
315 let size = std::mem::size_of_val(data);
316 let bytes = unsafe { slice::from_raw_parts(data.as_ptr() as *const u8, size) };
317 self.buffer.write(self.offset, bytes)
318 }
319
320 #[inline]
322 pub fn read_to_slice(self, buf: &mut [MaybeUninit<u8>]) -> Result<usize, MemoryAccessError> {
323 let len = self.len.try_into().expect("WasmSlice length overflow");
324 self.buffer.read_uninit(self.offset, buf)?;
325 Ok(len)
326 }
327
328 #[inline]
330 pub fn read_to_vec(self) -> Result<Vec<T>, MemoryAccessError> {
331 let len = self.len.try_into().expect("WasmSlice length overflow");
332 let mut vec = Vec::with_capacity(len);
333 let bytes = unsafe {
334 slice::from_raw_parts_mut(
335 vec.as_mut_ptr() as *mut MaybeUninit<u8>,
336 len * mem::size_of::<T>(),
337 )
338 };
339 self.buffer.read_uninit(self.offset, bytes)?;
340 unsafe {
341 vec.set_len(len);
342 }
343 Ok(vec)
344 }
345
346 #[inline]
348 pub fn read_to_bytes(self) -> Result<bytes::BytesMut, MemoryAccessError> {
349 let len = self.len.try_into().expect("WasmSlice length overflow");
350 let mut ret = bytes::BytesMut::with_capacity(len);
351 let bytes = unsafe {
352 slice::from_raw_parts_mut(
353 ret.as_mut_ptr() as *mut MaybeUninit<u8>,
354 len * mem::size_of::<T>(),
355 )
356 };
357 self.buffer.read_uninit(self.offset, bytes)?;
358 unsafe {
359 ret.set_len(len);
360 }
361 Ok(ret)
362 }
363}
364
365impl<T: ValueType> std::fmt::Debug for WasmSlice<'_, T> {
366 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
367 write!(
368 f,
369 "WasmSlice(offset: {}, len: {}, pointer: {:#x})",
370 self.offset, self.len, self.offset
371 )
372 }
373}
374
375pub struct WasmSliceIter<'a, T: ValueType> {
377 slice: WasmSlice<'a, T>,
378}
379
380impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> {
381 type Item = WasmRef<'a, T>;
382
383 fn next(&mut self) -> Option<Self::Item> {
384 if !self.slice.is_empty() {
385 let elem = self.slice.index(0);
386 self.slice = self.slice.subslice(1..self.slice.len());
387 Some(elem)
388 } else {
389 None
390 }
391 }
392
393 fn size_hint(&self) -> (usize, Option<usize>) {
394 (0..self.slice.len()).size_hint()
395 }
396}
397
398impl<T: ValueType> DoubleEndedIterator for WasmSliceIter<'_, T> {
399 fn next_back(&mut self) -> Option<Self::Item> {
400 if !self.slice.is_empty() {
401 let elem = self.slice.index(self.slice.len() - 1);
402 self.slice = self.slice.subslice(0..self.slice.len() - 1);
403 Some(elem)
404 } else {
405 None
406 }
407 }
408}
409
410impl<T: ValueType> ExactSizeIterator for WasmSliceIter<'_, T> {}