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]
166 pub fn new(view: &'a MemoryView, offset: u64, len: u64) -> Result<Self, MemoryAccessError> {
167 let total_len = len
168 .checked_mul(mem::size_of::<T>() as u64)
169 .ok_or(MemoryAccessError::Overflow)?;
170 let end = offset
171 .checked_add(total_len)
172 .ok_or(MemoryAccessError::Overflow)?;
173 if end > view.data_size() {
174 return Err(MemoryAccessError::HeapOutOfBounds);
175 }
176 Ok(Self {
177 buffer: view.buffer(),
178 offset,
179 len,
180 marker: PhantomData,
181 })
182 }
183
184 #[inline]
186 pub fn offset(self) -> u64 {
187 self.offset
188 }
189
190 #[inline]
192 pub fn as_ptr32(self) -> WasmPtr<T, Memory32> {
193 WasmPtr::new(self.offset as u32)
194 }
195
196 #[inline]
198 pub fn as_ptr64(self) -> WasmPtr<T, Memory64> {
199 WasmPtr::new(self.offset)
200 }
201
202 #[inline]
204 pub fn len(self) -> u64 {
205 self.len
206 }
207
208 #[inline]
210 pub fn is_empty(self) -> bool {
211 self.len == 0
212 }
213
214 #[inline]
216 pub fn is_owned(self) -> bool {
217 self.buffer.is_owned()
218 }
219
220 #[inline]
222 pub fn index(self, idx: u64) -> WasmRef<'a, T> {
223 if idx >= self.len {
224 panic!("WasmSlice out of bounds");
225 }
226 let offset = self.offset + idx * mem::size_of::<T>() as u64;
227 WasmRef {
228 buffer: self.buffer,
229 offset,
230 marker: PhantomData,
231 }
232 }
233
234 #[inline]
236 pub fn subslice(self, range: Range<u64>) -> Self {
237 if range.start > range.end || range.end > self.len {
238 panic!("WasmSlice out of bounds");
239 }
240 let offset = self.offset + range.start * mem::size_of::<T>() as u64;
241 Self {
242 buffer: self.buffer,
243 offset,
244 len: range.end - range.start,
245 marker: PhantomData,
246 }
247 }
248
249 #[inline]
251 pub fn iter(self) -> WasmSliceIter<'a, T> {
252 WasmSliceIter { slice: self }
253 }
254
255 #[inline]
257 pub fn access(self) -> Result<WasmSliceAccess<'a, T>, MemoryAccessError> {
258 WasmSliceAccess::new(self, self.buffer.is_owned())
259 }
260
261 #[inline]
263 pub fn read(self, idx: u64) -> Result<T, MemoryAccessError> {
264 self.index(idx).read()
265 }
266
267 #[inline]
269 pub fn write(self, idx: u64, val: T) -> Result<(), MemoryAccessError> {
270 self.index(idx).write(val)
271 }
272
273 #[inline]
277 pub fn read_slice(self, buf: &mut [T]) -> Result<(), MemoryAccessError> {
278 assert_eq!(
279 buf.len() as u64,
280 self.len,
281 "slice length doesn't match WasmSlice length"
282 );
283 let size = std::mem::size_of_val(buf);
284 let bytes =
285 unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut MaybeUninit<u8>, size) };
286 self.buffer.read_uninit(self.offset, bytes)?;
287 Ok(())
288 }
289
290 #[inline]
296 pub fn read_slice_uninit(
297 self,
298 buf: &mut [MaybeUninit<T>],
299 ) -> Result<&mut [T], MemoryAccessError> {
300 assert_eq!(
301 buf.len() as u64,
302 self.len,
303 "slice length doesn't match WasmSlice length"
304 );
305 let bytes = unsafe {
306 slice::from_raw_parts_mut(
307 buf.as_mut_ptr() as *mut MaybeUninit<u8>,
308 buf.len() * mem::size_of::<T>(),
309 )
310 };
311 self.buffer.read_uninit(self.offset, bytes)?;
312 Ok(unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut T, buf.len()) })
313 }
314
315 #[inline]
319 pub fn write_slice(self, data: &[T]) -> Result<(), MemoryAccessError> {
320 assert_eq!(
321 data.len() as u64,
322 self.len,
323 "slice length doesn't match WasmSlice length"
324 );
325 let size = std::mem::size_of_val(data);
326 let bytes = unsafe { slice::from_raw_parts(data.as_ptr() as *const u8, size) };
327 self.buffer.write(self.offset, bytes)
328 }
329
330 #[inline]
332 pub fn read_to_slice(self, buf: &mut [MaybeUninit<u8>]) -> Result<usize, MemoryAccessError> {
333 let len = self.len.try_into().expect("WasmSlice length overflow");
334 self.buffer.read_uninit(self.offset, buf)?;
335 Ok(len)
336 }
337
338 #[inline]
340 pub fn read_to_vec(self) -> Result<Vec<T>, MemoryAccessError> {
341 let len = self.len.try_into().expect("WasmSlice length overflow");
342 let mut vec = Vec::with_capacity(len);
343 let bytes = unsafe {
344 slice::from_raw_parts_mut(
345 vec.as_mut_ptr() as *mut MaybeUninit<u8>,
346 len * mem::size_of::<T>(),
347 )
348 };
349 self.buffer.read_uninit(self.offset, bytes)?;
350 unsafe {
351 vec.set_len(len);
352 }
353 Ok(vec)
354 }
355
356 #[inline]
358 pub fn read_to_bytes(self) -> Result<bytes::BytesMut, MemoryAccessError> {
359 let len = self.len.try_into().expect("WasmSlice length overflow");
360 let mut ret = bytes::BytesMut::with_capacity(len);
361 let bytes = unsafe {
362 slice::from_raw_parts_mut(
363 ret.as_mut_ptr() as *mut MaybeUninit<u8>,
364 len * mem::size_of::<T>(),
365 )
366 };
367 self.buffer.read_uninit(self.offset, bytes)?;
368 unsafe {
369 ret.set_len(len);
370 }
371 Ok(ret)
372 }
373}
374
375impl<T: ValueType> std::fmt::Debug for WasmSlice<'_, T> {
376 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
377 write!(
378 f,
379 "WasmSlice(offset: {}, len: {}, pointer: {:#x})",
380 self.offset, self.len, self.offset
381 )
382 }
383}
384
385pub struct WasmSliceIter<'a, T: ValueType> {
387 slice: WasmSlice<'a, T>,
388}
389
390impl<'a, T: ValueType> Iterator for WasmSliceIter<'a, T> {
391 type Item = WasmRef<'a, T>;
392
393 fn next(&mut self) -> Option<Self::Item> {
394 if !self.slice.is_empty() {
395 let elem = self.slice.index(0);
396 self.slice = self.slice.subslice(1..self.slice.len());
397 Some(elem)
398 } else {
399 None
400 }
401 }
402
403 fn size_hint(&self) -> (usize, Option<usize>) {
404 (0..self.slice.len()).size_hint()
405 }
406}
407
408impl<T: ValueType> DoubleEndedIterator for WasmSliceIter<'_, T> {
409 fn next_back(&mut self) -> Option<Self::Item> {
410 if !self.slice.is_empty() {
411 let elem = self.slice.index(self.slice.len() - 1);
412 self.slice = self.slice.subslice(0..self.slice.len() - 1);
413 Some(elem)
414 } else {
415 None
416 }
417 }
418}
419
420impl<T: ValueType> ExactSizeIterator for WasmSliceIter<'_, T> {}