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