wasmtime/runtime/memory.rs
1use crate::Trap;
2use crate::prelude::*;
3use crate::runtime::vm::{self, ExportMemory};
4use crate::store::{StoreInstanceId, StoreOpaque, StoreResourceLimiter};
5use crate::trampoline::generate_memory_export;
6#[cfg(feature = "async")]
7use crate::vm::VMStore;
8use crate::{AsContext, AsContextMut, Engine, MemoryType, StoreContext, StoreContextMut};
9use alloc::sync::Arc;
10use core::any::Any;
11use core::cell::UnsafeCell;
12use core::fmt;
13use core::slice;
14use core::time::Duration;
15use wasmtime_environ::{DefinedMemoryIndex, MemoryTunables};
16
17pub use crate::runtime::vm::WaitResult;
18
19/// Error for out of bounds [`Memory`] access.
20#[derive(Debug)]
21#[non_exhaustive]
22pub struct MemoryAccessError {
23 // Keep struct internals private for future extensibility.
24 _private: (),
25}
26
27impl fmt::Display for MemoryAccessError {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 write!(f, "out of bounds memory access")
30 }
31}
32
33impl core::error::Error for MemoryAccessError {}
34
35/// A WebAssembly linear memory.
36///
37/// WebAssembly memories represent a contiguous array of bytes that have a size
38/// that is always a multiple of the WebAssembly page size, currently 64
39/// kilobytes.
40///
41/// WebAssembly memory is used for global data (not to be confused with wasm
42/// `global` items), statics in C/C++/Rust, shadow stack memory, etc. Accessing
43/// wasm memory is generally quite fast.
44///
45/// Memories, like other wasm items, are owned by a [`Store`](crate::Store).
46///
47/// # `Memory` and Safety
48///
49/// Linear memory is a lynchpin of safety for WebAssembly. In Wasmtime there are
50/// safe methods of interacting with a [`Memory`]:
51///
52/// * [`Memory::read`]
53/// * [`Memory::write`]
54/// * [`Memory::data`]
55/// * [`Memory::data_mut`]
56///
57/// Note that all of these consider the entire store context as borrowed for the
58/// duration of the call or the duration of the returned slice. This largely
59/// means that while the function is running you'll be unable to borrow anything
60/// else from the store. This includes getting access to the `T` on
61/// [`Store<T>`](crate::Store), but it also means that you can't recursively
62/// call into WebAssembly for instance.
63///
64/// If you'd like to dip your toes into handling [`Memory`] in a more raw
65/// fashion (e.g. by using raw pointers or raw slices), then there's a few
66/// important points to consider when doing so:
67///
68/// * Any recursive calls into WebAssembly can possibly modify any byte of the
69/// entire memory. This means that whenever wasm is called Rust can't have any
70/// long-lived borrows live across the wasm function call. Slices like `&mut
71/// [u8]` will be violated because they're not actually exclusive at that
72/// point, and slices like `&[u8]` are also violated because their contents
73/// may be mutated.
74///
75/// * WebAssembly memories can grow, and growth may change the base pointer.
76/// This means that even holding a raw pointer to memory over a wasm function
77/// call is also incorrect. Anywhere in the function call the base address of
78/// memory may change. Note that growth can also be requested from the
79/// embedding API as well.
80///
81/// As a general rule of thumb it's recommended to stick to the safe methods of
82/// [`Memory`] if you can. It's not advised to use raw pointers or `unsafe`
83/// operations because of how easy it is to accidentally get things wrong.
84///
85/// Some examples of safely interacting with memory are:
86///
87/// ```rust
88/// use wasmtime::{Memory, Store, MemoryAccessError};
89///
90/// // Memory can be read and written safely with the `Memory::read` and
91/// // `Memory::write` methods.
92/// // An error is returned if the copy did not succeed.
93/// fn safe_examples(mem: Memory, store: &mut Store<()>) -> Result<(), MemoryAccessError> {
94/// let offset = 5;
95/// mem.write(&mut *store, offset, b"hello")?;
96/// let mut buffer = [0u8; 5];
97/// mem.read(&store, offset, &mut buffer)?;
98/// assert_eq!(b"hello", &buffer);
99///
100/// // Note that while this is safe care must be taken because the indexing
101/// // here may panic if the memory isn't large enough.
102/// assert_eq!(&mem.data(&store)[offset..offset + 5], b"hello");
103/// mem.data_mut(&mut *store)[offset..offset + 5].copy_from_slice(b"bye!!");
104///
105/// Ok(())
106/// }
107/// ```
108///
109/// It's worth also, however, covering some examples of **incorrect**,
110/// **unsafe** usages of `Memory`. Do not do these things!
111///
112/// ```rust
113/// use wasmtime::{Memory, Result, Store};
114///
115/// // NOTE: All code in this function is not safe to execute and may cause
116/// // segfaults/undefined behavior at runtime. Do not copy/paste these examples
117/// // into production code!
118/// unsafe fn unsafe_examples(mem: Memory, store: &mut Store<()>) -> Result<()> {
119/// // First and foremost, any borrow can be invalidated at any time via the
120/// // `Memory::grow` function. This can relocate memory which causes any
121/// // previous pointer to be possibly invalid now.
122/// unsafe {
123/// let pointer: &u8 = &*mem.data_ptr(&store);
124/// mem.grow(&mut *store, 1)?; // invalidates `pointer`!
125/// // println!("{}", *pointer); // FATAL: use-after-free
126/// }
127///
128/// // Note that the use-after-free also applies to slices, whether they're
129/// // slices of bytes or strings.
130/// unsafe {
131/// let mem_slice = std::slice::from_raw_parts(
132/// mem.data_ptr(&store),
133/// mem.data_size(&store),
134/// );
135/// let slice: &[u8] = &mem_slice[0x100..0x102];
136/// mem.grow(&mut *store, 1)?; // invalidates `slice`!
137/// // println!("{:?}", slice); // FATAL: use-after-free
138/// }
139///
140/// // The `Memory` type may be stored in other locations, so if you hand
141/// // off access to the `Store` then those locations may also call
142/// // `Memory::grow` or similar, so it's not enough to just audit code for
143/// // calls to `Memory::grow`.
144/// unsafe {
145/// let pointer: &u8 = &*mem.data_ptr(&store);
146/// some_other_function(store); // may invalidate `pointer` through use of `store`
147/// // println!("{:?}", pointer); // FATAL: maybe a use-after-free
148/// }
149///
150/// // An especially subtle aspect of accessing a wasm instance's memory is
151/// // that you need to be extremely careful about aliasing. Anyone at any
152/// // time can call `data_unchecked()` or `data_unchecked_mut()`, which
153/// // means you can easily have aliasing mutable references:
154/// unsafe {
155/// let ref1: &u8 = &*mem.data_ptr(&store).add(0x100);
156/// let ref2: &mut u8 = &mut *mem.data_ptr(&store).add(0x100);
157/// // *ref2 = *ref1; // FATAL: violates Rust's aliasing rules
158/// }
159///
160/// Ok(())
161/// }
162/// # fn some_other_function(store: &mut Store<()>) {}
163/// ```
164///
165/// Overall there's some general rules of thumb when unsafely working with
166/// `Memory` and getting raw pointers inside of it:
167///
168/// * If you never have a "long lived" pointer into memory, you're likely in the
169/// clear. Care still needs to be taken in threaded scenarios or when/where
170/// data is read, but you'll be shielded from many classes of issues.
171/// * Long-lived pointers must always respect Rust'a aliasing rules. It's ok for
172/// shared borrows to overlap with each other, but mutable borrows must
173/// overlap with nothing.
174/// * Long-lived pointers are only valid if they're not invalidated for their
175/// lifetime. This means that [`Store`](crate::Store) isn't used to reenter
176/// wasm or the memory itself is never grown or otherwise modified/aliased.
177///
178/// At this point it's worth reiterating again that unsafely working with
179/// `Memory` is pretty tricky and not recommended! It's highly recommended to
180/// use the safe methods to interact with [`Memory`] whenever possible.
181///
182/// ## `Memory` Safety and Threads
183///
184/// Currently the `wasmtime` crate does not implement the wasm threads proposal,
185/// but it is planned to do so. It may be interesting to readers to see how this
186/// affects memory safety and what was previously just discussed as well.
187///
188/// Once threads are added into the mix, all of the above rules still apply.
189/// There's an additional consideration that all reads and writes can happen
190/// concurrently, though. This effectively means that any borrow into wasm
191/// memory are virtually never safe to have.
192///
193/// Mutable pointers are fundamentally unsafe to have in a concurrent scenario
194/// in the face of arbitrary wasm code. Only if you dynamically know for sure
195/// that wasm won't access a region would it be safe to construct a mutable
196/// pointer. Additionally even shared pointers are largely unsafe because their
197/// underlying contents may change, so unless `UnsafeCell` in one form or
198/// another is used everywhere there's no safety.
199///
200/// One important point about concurrency is that while [`Memory::grow`] can
201/// happen concurrently it will never relocate the base pointer. Shared
202/// memories must always have a maximum size and they will be preallocated such
203/// that growth will never relocate the base pointer. The current size of the
204/// memory may still change over time though.
205///
206/// Overall the general rule of thumb for shared memories is that you must
207/// atomically read and write everything. Nothing can be borrowed and everything
208/// must be eagerly copied out. This means that [`Memory::data`] and
209/// [`Memory::data_mut`] won't work in the future (they'll probably return an
210/// error) for shared memories when they're implemented. When possible it's
211/// recommended to use [`Memory::read`] and [`Memory::write`] which will still
212/// be provided.
213#[derive(Copy, Clone, Debug)]
214#[repr(C)] // here for the C API
215pub struct Memory {
216 /// The internal store instance that this memory belongs to.
217 instance: StoreInstanceId,
218 /// The index of the memory, within `instance` above, that this memory
219 /// refers to.
220 index: DefinedMemoryIndex,
221}
222
223// Double-check that the C representation in `extern.h` matches our in-Rust
224// representation here in terms of size/alignment/etc.
225const _: () = {
226 #[repr(C)]
227 struct Tmp(u64, u32);
228 #[repr(C)]
229 struct C(Tmp, u32);
230 assert!(core::mem::size_of::<C>() == core::mem::size_of::<Memory>());
231 assert!(core::mem::align_of::<C>() == core::mem::align_of::<Memory>());
232 assert!(core::mem::offset_of!(Memory, instance) == 0);
233};
234
235impl Memory {
236 /// Creates a new WebAssembly memory given the configuration of `ty`.
237 ///
238 /// The `store` argument will be the owner of the returned [`Memory`]. All
239 /// WebAssembly memory is initialized to zero.
240 ///
241 /// # Panics
242 ///
243 /// This function will panic if the [`Store`](`crate::Store`) has a
244 /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`) (see also:
245 /// [`Store::limiter_async`](`crate::Store::limiter_async`)). When
246 /// using an async resource limiter, use [`Memory::new_async`] instead.
247 ///
248 /// # Examples
249 ///
250 /// ```
251 /// # use wasmtime::*;
252 /// # fn main() -> Result<()> {
253 /// let engine = Engine::default();
254 /// let mut store = Store::new(&engine, ());
255 ///
256 /// let memory_ty = MemoryType::new(1, None)?;
257 /// let memory = Memory::new(&mut store, memory_ty)?;
258 ///
259 /// let module = Module::new(&engine, "(module (memory (import \"\" \"\") 1))")?;
260 /// let instance = Instance::new(&mut store, &module, &[memory.into()])?;
261 /// // ...
262 /// # Ok(())
263 /// # }
264 /// ```
265 ///
266 /// # Errors
267 ///
268 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
269 /// memory allocation fails. See the `OutOfMemory` type's documentation for
270 /// details on Wasmtime's out-of-memory handling.
271 pub fn new(mut store: impl AsContextMut, ty: MemoryType) -> Result<Memory> {
272 let (mut limiter, store) = store
273 .as_context_mut()
274 .0
275 .validate_sync_resource_limiter_and_store_opaque()?;
276 vm::assert_ready(Self::_new(store, limiter.as_mut(), ty))
277 }
278
279 /// Async variant of [`Memory::new`]. You must use this variant with
280 /// [`Store`](`crate::Store`)s which have a
281 /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`).
282 ///
283 /// # Panics
284 ///
285 /// This function will panic when used with a non-async
286 /// [`Store`](`crate::Store`).
287 ///
288 /// # Errors
289 ///
290 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
291 /// memory allocation fails. See the `OutOfMemory` type's documentation for
292 /// details on Wasmtime's out-of-memory handling.
293 #[cfg(feature = "async")]
294 pub async fn new_async(mut store: impl AsContextMut, ty: MemoryType) -> Result<Memory> {
295 let (mut limiter, store) = store.as_context_mut().0.resource_limiter_and_store_opaque();
296 Self::_new(store, limiter.as_mut(), ty).await
297 }
298
299 /// Helper function for attaching the memory to a "frankenstein" instance
300 async fn _new(
301 store: &mut StoreOpaque,
302 limiter: Option<&mut StoreResourceLimiter<'_>>,
303 ty: MemoryType,
304 ) -> Result<Memory> {
305 if ty.is_shared() {
306 bail!("shared memories must be created through `SharedMemory`")
307 }
308 store.bump_memory_count()?;
309 Ok(generate_memory_export(store, limiter, &ty, None)
310 .await?
311 .unshared()
312 .unwrap())
313 }
314
315 /// Returns the underlying type of this memory.
316 ///
317 /// # Panics
318 ///
319 /// Panics if this memory doesn't belong to `store`.
320 ///
321 /// # Examples
322 ///
323 /// ```
324 /// # use wasmtime::*;
325 /// # fn main() -> Result<()> {
326 /// let engine = Engine::default();
327 /// let mut store = Store::new(&engine, ());
328 /// let module = Module::new(&engine, "(module (memory (export \"mem\") 1))")?;
329 /// let instance = Instance::new(&mut store, &module, &[])?;
330 /// let memory = instance.get_memory(&mut store, "mem").unwrap();
331 /// let ty = memory.ty(&store);
332 /// assert_eq!(ty.minimum(), 1);
333 /// # Ok(())
334 /// # }
335 /// ```
336 pub fn ty(&self, store: impl AsContext) -> MemoryType {
337 let store = store.as_context();
338 MemoryType::from_wasmtime_memory(self.wasmtime_ty(store.0))
339 }
340
341 /// Safely reads memory contents at the given offset into a buffer.
342 ///
343 /// The entire buffer will be filled.
344 ///
345 /// If `offset + buffer.len()` exceed the current memory capacity, then the
346 /// buffer is left untouched and a [`MemoryAccessError`] is returned.
347 ///
348 /// # Errors
349 ///
350 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
351 /// memory allocation fails. See the `OutOfMemory` type's documentation for
352 /// details on Wasmtime's out-of-memory handling.
353 ///
354 /// # Panics
355 ///
356 /// Panics if this memory doesn't belong to `store`.
357 pub fn read(
358 &self,
359 store: impl AsContext,
360 offset: usize,
361 buffer: &mut [u8],
362 ) -> Result<(), MemoryAccessError> {
363 let store = store.as_context();
364 let slice = self
365 .data(&store)
366 .get(offset..)
367 .and_then(|s| s.get(..buffer.len()))
368 .ok_or(MemoryAccessError { _private: () })?;
369 buffer.copy_from_slice(slice);
370 Ok(())
371 }
372
373 /// Safely writes contents of a buffer to this memory at the given offset.
374 ///
375 /// If the `offset + buffer.len()` exceeds the current memory capacity, then
376 /// none of the buffer is written to memory and a [`MemoryAccessError`] is
377 /// returned.
378 ///
379 /// # Errors
380 ///
381 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
382 /// memory allocation fails. See the `OutOfMemory` type's documentation for
383 /// details on Wasmtime's out-of-memory handling.
384 ///
385 /// # Panics
386 ///
387 /// Panics if this memory doesn't belong to `store`.
388 pub fn write(
389 &self,
390 mut store: impl AsContextMut,
391 offset: usize,
392 buffer: &[u8],
393 ) -> Result<(), MemoryAccessError> {
394 let mut context = store.as_context_mut();
395 self.data_mut(&mut context)
396 .get_mut(offset..)
397 .and_then(|s| s.get_mut(..buffer.len()))
398 .ok_or(MemoryAccessError { _private: () })?
399 .copy_from_slice(buffer);
400 Ok(())
401 }
402
403 /// Returns this memory as a native Rust slice.
404 ///
405 /// Note that this method will consider the entire store context provided as
406 /// borrowed for the duration of the lifetime of the returned slice.
407 ///
408 /// # Panics
409 ///
410 /// Panics if this memory doesn't belong to `store`.
411 pub fn data<'a, T: 'static>(&self, store: impl Into<StoreContext<'a, T>>) -> &'a [u8] {
412 unsafe {
413 let store = store.into();
414 let definition = store[self.instance].memory(self.index);
415 debug_assert!(!self.ty(store).is_shared());
416 slice::from_raw_parts(definition.base.as_ptr(), definition.current_length())
417 }
418 }
419
420 /// Returns this memory as a native Rust mutable slice.
421 ///
422 /// Note that this method will consider the entire store context provided as
423 /// borrowed for the duration of the lifetime of the returned slice.
424 ///
425 /// # Panics
426 ///
427 /// Panics if this memory doesn't belong to `store`.
428 pub fn data_mut<'a, T: 'static>(
429 &self,
430 store: impl Into<StoreContextMut<'a, T>>,
431 ) -> &'a mut [u8] {
432 unsafe {
433 let store = store.into();
434 let definition = store[self.instance].memory(self.index);
435 debug_assert!(!self.ty(store).is_shared());
436 slice::from_raw_parts_mut(definition.base.as_ptr(), definition.current_length())
437 }
438 }
439
440 /// Same as [`Memory::data_mut`], but also returns the `T` from the
441 /// [`StoreContextMut`].
442 ///
443 /// This method can be used when you want to simultaneously work with the
444 /// `T` in the store as well as the memory behind this [`Memory`]. Using
445 /// [`Memory::data_mut`] would consider the entire store borrowed, whereas
446 /// this method allows the Rust compiler to see that the borrow of this
447 /// memory and the borrow of `T` are disjoint.
448 ///
449 /// # Panics
450 ///
451 /// Panics if this memory doesn't belong to `store`.
452 pub fn data_and_store_mut<'a, T: 'static>(
453 &self,
454 store: impl Into<StoreContextMut<'a, T>>,
455 ) -> (&'a mut [u8], &'a mut T) {
456 // Note the unsafety here. Our goal is to simultaneously borrow the
457 // memory and custom data from `store`, and the store it's connected
458 // to. Rust will not let us do that, however, because we must call two
459 // separate methods (both of which borrow the whole `store`) and one of
460 // our borrows is mutable (the custom data).
461 //
462 // This operation, however, is safe because these borrows do not overlap
463 // and in the process of borrowing them mutability doesn't actually
464 // touch anything. This is akin to mutably borrowing two indices in an
465 // array, which is safe so long as the indices are separate.
466 unsafe {
467 let mut store = store.into();
468 let data = &mut *(store.data_mut() as *mut T);
469 (self.data_mut(store), data)
470 }
471 }
472
473 /// Returns the base pointer, in the host's address space, that the memory
474 /// is located at.
475 ///
476 /// For more information and examples see the documentation on the
477 /// [`Memory`] type.
478 ///
479 /// # Panics
480 ///
481 /// Panics if this memory doesn't belong to `store`.
482 pub fn data_ptr(&self, store: impl AsContext) -> *mut u8 {
483 store.as_context()[self.instance]
484 .memory(self.index)
485 .base
486 .as_ptr()
487 }
488
489 /// Returns the byte length of this memory.
490 ///
491 /// WebAssembly memories are made up of a whole number of pages, so the byte
492 /// size returned will always be a multiple of this memory's page size. Note
493 /// that different Wasm memories may have different page sizes. You can get
494 /// a memory's page size via the [`Memory::page_size`] method.
495 ///
496 /// By default the page size is 64KiB (aka `0x10000`, `2**16`, `1<<16`, or
497 /// `65536`) but [the custom-page-sizes proposal] allows a memory to opt
498 /// into a page size of `1`. Future extensions might allow any power of two
499 /// as a page size.
500 ///
501 /// [the custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes
502 ///
503 /// For more information and examples see the documentation on the
504 /// [`Memory`] type.
505 ///
506 /// # Panics
507 ///
508 /// Panics if this memory doesn't belong to `store`.
509 pub fn data_size(&self, store: impl AsContext) -> usize {
510 self.internal_data_size(store.as_context().0)
511 }
512
513 pub(crate) fn internal_data_size(&self, store: &StoreOpaque) -> usize {
514 store[self.instance].memory(self.index).current_length()
515 }
516
517 /// Returns the size, in units of pages, of this Wasm memory.
518 ///
519 /// WebAssembly memories are made up of a whole number of pages, so the byte
520 /// size returned will always be a multiple of this memory's page size. Note
521 /// that different Wasm memories may have different page sizes. You can get
522 /// a memory's page size via the [`Memory::page_size`] method.
523 ///
524 /// By default the page size is 64KiB (aka `0x10000`, `2**16`, `1<<16`, or
525 /// `65536`) but [the custom-page-sizes proposal] allows a memory to opt
526 /// into a page size of `1`. Future extensions might allow any power of two
527 /// as a page size.
528 ///
529 /// [the custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes
530 ///
531 /// # Panics
532 ///
533 /// Panics if this memory doesn't belong to `store`.
534 pub fn size(&self, store: impl AsContext) -> u64 {
535 self.internal_size(store.as_context().0)
536 }
537
538 pub(crate) fn internal_size(&self, store: &StoreOpaque) -> u64 {
539 let byte_size = self.internal_data_size(store);
540 let page_size = usize::try_from(self._page_size(store)).unwrap();
541 u64::try_from(byte_size / page_size).unwrap()
542 }
543
544 /// Returns the size of a page, in bytes, for this memory.
545 ///
546 /// WebAssembly memories are made up of a whole number of pages, so the byte
547 /// size (as returned by [`Memory::data_size`]) will always be a multiple of
548 /// their page size. Different Wasm memories may have different page sizes.
549 ///
550 /// By default this is 64KiB (aka `0x10000`, `2**16`, `1<<16`, or `65536`)
551 /// but [the custom-page-sizes proposal] allows opting into a page size of
552 /// `1`. Future extensions might allow any power of two as a page size.
553 ///
554 /// [the custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes
555 pub fn page_size(&self, store: impl AsContext) -> u64 {
556 self._page_size(store.as_context().0)
557 }
558
559 pub(crate) fn _page_size(&self, store: &StoreOpaque) -> u64 {
560 self.wasmtime_ty(store).page_size()
561 }
562
563 /// Returns the log2 of this memory's page size, in bytes.
564 ///
565 /// WebAssembly memories are made up of a whole number of pages, so the byte
566 /// size (as returned by [`Memory::data_size`]) will always be a multiple of
567 /// their page size. Different Wasm memories may have different page sizes.
568 ///
569 /// By default the page size is 64KiB (aka `0x10000`, `2**16`, `1<<16`, or
570 /// `65536`) but [the custom-page-sizes proposal] allows opting into a page
571 /// size of `1`. Future extensions might allow any power of two as a page
572 /// size.
573 ///
574 /// [the custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes
575 pub fn page_size_log2(&self, store: impl AsContext) -> u8 {
576 self._page_size_log2(store.as_context().0)
577 }
578
579 pub(crate) fn _page_size_log2(&self, store: &StoreOpaque) -> u8 {
580 self.wasmtime_ty(store).page_size_log2
581 }
582
583 /// Grows this WebAssembly memory by `delta` pages.
584 ///
585 /// This will attempt to add `delta` more pages of memory on to the end of
586 /// this `Memory` instance. If successful this may relocate the memory and
587 /// cause [`Memory::data_ptr`] to return a new value. Additionally any
588 /// unsafely constructed slices into this memory may no longer be valid.
589 ///
590 /// On success returns the number of pages this memory previously had
591 /// before the growth succeeded.
592 ///
593 /// Note that, by default, a WebAssembly memory's page size is 64KiB (aka
594 /// 65536 or 2<sup>16</sup>). The [custom-page-sizes proposal] allows Wasm
595 /// memories to opt into a page size of one byte (and this may be further
596 /// relaxed to any power of two in a future extension).
597 ///
598 /// [custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes
599 ///
600 /// # Errors
601 ///
602 /// Returns an error if memory could not be grown, for example if it exceeds
603 /// the maximum limits of this memory. A
604 /// [`ResourceLimiter`](crate::ResourceLimiter) is another example of
605 /// preventing a memory to grow.
606 ///
607 /// This function will return an error if the [`Store`](`crate::Store`) has
608 /// a [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`) (see also:
609 /// [`Store::limiter_async`](`crate::Store::limiter_async`). When using an
610 /// async resource limiter, use [`Memory::grow_async`] instead.
611 ///
612 /// This function will handle out-of-memory conditions and report an error
613 /// in such cases, see the `OutOfMemory` type's documentation for details on
614 /// Wasmtime's out-of-memory handling. Note that the `OutOfMemory` type may
615 /// not literally be returned for detecting this condition.
616 ///
617 /// # Panics
618 ///
619 /// Panics if this memory doesn't belong to `store`.
620 ///
621 /// # Examples
622 ///
623 /// ```
624 /// # use wasmtime::*;
625 /// # fn main() -> Result<()> {
626 /// let engine = Engine::default();
627 /// let mut store = Store::new(&engine, ());
628 /// let module = Module::new(&engine, "(module (memory (export \"mem\") 1 2))")?;
629 /// let instance = Instance::new(&mut store, &module, &[])?;
630 /// let memory = instance.get_memory(&mut store, "mem").unwrap();
631 ///
632 /// assert_eq!(memory.size(&store), 1);
633 /// assert_eq!(memory.grow(&mut store, 1)?, 1);
634 /// assert_eq!(memory.size(&store), 2);
635 /// assert!(memory.grow(&mut store, 1).is_err());
636 /// assert_eq!(memory.size(&store), 2);
637 /// assert_eq!(memory.grow(&mut store, 0)?, 2);
638 /// # Ok(())
639 /// # }
640 /// ```
641 pub fn grow(&self, mut store: impl AsContextMut, delta: u64) -> Result<u64> {
642 let store = store.as_context_mut().0;
643 let (mut limiter, store) = store.validate_sync_resource_limiter_and_store_opaque()?;
644 vm::assert_ready(self._grow(store, limiter.as_mut(), delta))
645 }
646
647 /// Async variant of [`Memory::grow`]. Required when using a
648 /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`).
649 ///
650 /// # Panics
651 ///
652 /// This function will panic when used with a non-async
653 /// [`Store`](`crate::Store`).
654 ///
655 /// # Errors
656 ///
657 /// This function will return errors for the same reasons as
658 /// [`Memory::grow`].
659 #[cfg(feature = "async")]
660 pub async fn grow_async(&self, mut store: impl AsContextMut, delta: u64) -> Result<u64> {
661 let store = store.as_context_mut();
662 let (mut limiter, store) = store.0.resource_limiter_and_store_opaque();
663 self._grow(store, limiter.as_mut(), delta).await
664 }
665
666 async fn _grow(
667 &self,
668 store: &mut StoreOpaque,
669 limiter: Option<&mut StoreResourceLimiter<'_>>,
670 delta: u64,
671 ) -> Result<u64> {
672 let result = self
673 .instance
674 .get_mut(store)
675 .memory_grow(limiter, self.index, delta)
676 .await?;
677 match result {
678 Some(size) => {
679 let page_size = self.wasmtime_ty(store).page_size();
680 Ok(u64::try_from(size).unwrap() / page_size)
681 }
682 None => bail!("failed to grow memory by `{delta}`"),
683 }
684 }
685
686 /// Creates a new memory from its raw component parts.
687 ///
688 /// # Safety
689 ///
690 /// The caller must ensure that the memory pointed to by `instance` and
691 /// `index` is not a shared memory. For that `SharedMemory` must be used
692 /// instead.
693 pub(crate) unsafe fn from_raw(instance: StoreInstanceId, index: DefinedMemoryIndex) -> Memory {
694 Memory { instance, index }
695 }
696
697 pub(crate) fn wasmtime_ty<'a>(&self, store: &'a StoreOpaque) -> &'a wasmtime_environ::Memory {
698 let module = store[self.instance].env_module();
699 let index = module.memory_index(self.index);
700 &module.memories[index]
701 }
702
703 pub(crate) fn vmimport(&self, store: &StoreOpaque) -> crate::runtime::vm::VMMemoryImport {
704 store[self.instance].get_defined_memory_vmimport(self.index)
705 }
706
707 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
708 store.id() == self.instance.store_id()
709 }
710
711 /// Returns a stable identifier for this memory within its store.
712 ///
713 /// This allows distinguishing memories when introspecting them
714 /// e.g. via debug APIs.
715 #[cfg(feature = "debug")]
716 pub fn debug_index_in_store(&self) -> u64 {
717 u64::from(self.instance.instance().as_u32()) << 32 | u64::from(self.index.as_u32())
718 }
719
720 /// Get a stable hash key for this memory.
721 ///
722 /// Even if the same underlying memory definition is added to the
723 /// `StoreData` multiple times and becomes multiple `wasmtime::Memory`s,
724 /// this hash key will be consistent across all of these memories.
725 #[cfg(feature = "coredump")]
726 pub(crate) fn hash_key(&self, store: &StoreOpaque) -> impl core::hash::Hash + Eq + use<> {
727 store[self.instance].memory_ptr(self.index).as_ptr().addr()
728 }
729}
730
731/// A linear memory. This trait provides an interface for raw memory buffers
732/// which are used by wasmtime, e.g. inside ['Memory']. Such buffers are in
733/// principle not thread safe. By implementing this trait together with
734/// MemoryCreator, one can supply wasmtime with custom allocated host managed
735/// memory.
736///
737/// Note that this is a relatively advanced feature and it is recommended to be
738/// familiar with wasmtime runtime code to use it.
739///
740/// In the following, `minimum`, `reserved_size_in_bytes`, and `guard_size_in_bytes` arguments are given to a
741/// [`MemoryCreator::new_memory`] implementation.
742///
743/// # Safety
744///
745/// Wasmtime's compiled code and runtime rely on the following invariants for memory safety.
746/// Note that while we strive to be thorough in this documentation, we do not guarantee that the
747/// following points are exhaustive.
748/// When using a custom memory backend in a security-sensitive context auditing just the external
749/// implementation of this trait is not sufficient.
750///
751/// - **Valid region.** From creation until the memory is dropped, the first
752/// [`byte_size`] bytes starting at the [`as_ptr`]
753/// memory location must be allocated, initialized, readable, and writeable.
754/// The pointer must be non-null.
755/// Nothing other than Wasmtime may read, write, unmap, or otherwise modify this region while the
756/// memory is in use by Wasmtime.
757/// If the memory moves (although see conditions on stability below), the previous region is no
758/// longer in use by Wasmtime.
759/// Moreover, be aware that Wasmtime currently has a soundness hole for shared memory,
760/// as multiple threads may access the same slice of memory mutably at the same time (aliasing) (see
761/// [issue #4203](https://github.com/bytecodealliance/wasmtime/issues/4203)).
762///
763/// - **Size.** [`byte_size`] must be at least `minimum` after creation
764/// and at least `new_size` after a successful call to [`grow_to`],
765/// and it must never decrease.
766///
767/// - **Base pointer stability.** A call to [`as_ptr`] must return the same
768/// address until the next successful call to [`grow_to`].
769/// Moreover, a successful [`grow_to(new_size)`][`grow_to`] call where `new_size` is at most the [`byte_capacity`](LinearMemory::byte_capacity)
770/// reported before the call must not change the result of [`as_ptr`].
771/// If static memory is forced (e.g. when using shared memory or when [`Config::memory_may_move`](crate::Config::memory_may_move) is disabled), Wasmtime will never ask the memory to grow beyond its [`byte_capacity`].
772///
773/// - **Base pointer alignment.** The base pointer returned by [`as_ptr`] must always be 8-byte aligned.
774/// Moreover, if `guard_size_in_bytes` is non-zero, or `reserved_size_in_bytes` is `Some` and non-zero, then [`as_ptr`] must be
775/// aligned to the host page size at all times.
776///
777/// - **Inaccessible region.** If: `guard_size_in_bytes` is non-zero, or `reserved_size_in_bytes` is `Some` and non-zero;
778/// then every byte from `as_ptr() + byte_size()`, rounded up to the next host page boundary, up to
779/// `as_ptr() + max(reserved_size_in_bytes, byte_size()) + guard_size_in_bytes` must be
780/// inaccessible, so that any access to it faults. This must hold at all times, including after growth.
781///
782/// Additionally, observe the safety requirements when the memory is accessed, as explained in [`Memory`].
783///
784/// # Correctness
785///
786/// The following constraints do not cause memory safety issues, but break WebAssembly semantics,
787/// or expose potentially unwanted data to WebAssembly programs:
788///
789/// - [`byte_size`] should be exactly `minimum` after creation and exactly `new_size` after a
790/// successful call to [`grow_to(new_size)`][`grow_to`]. Wasmtime only requests sizes that are
791/// multiples of the Wasm page size.
792///
793/// - The memory's contents must be zeroed at creation, and bytes made accessible by [`grow_to`] must
794/// be zeroed.
795///
796/// - If [`init_from_image`] returns `Ok(true)`, then the bytes at [`MemoryImage::linear_memory_offset`]
797/// must equal the image and all other bytes must be zero.
798///
799/// [`grow_to`]: LinearMemory::grow_to
800/// [`byte_size`]: LinearMemory::byte_size
801/// [`as_ptr`]: LinearMemory::as_ptr
802/// [`byte_capacity`]: LinearMemory::byte_capacity
803/// [`init_from_image`]: LinearMemory::init_from_image
804pub unsafe trait LinearMemory: Any + Send + Sync {
805 /// Returns the number of allocated bytes which are accessible at this time.
806 fn byte_size(&self) -> usize;
807
808 /// Returns byte capacity of this linear memory's current allocation.
809 ///
810 /// Growth up to this value should not relocate the linear memory base
811 /// pointer.
812 fn byte_capacity(&self) -> usize;
813
814 /// Grows this memory to have the `new_size`, in bytes, specified.
815 ///
816 /// Returns `Err` if memory can't be grown by the specified amount
817 /// of bytes. The error may be downcastable to `std::io::Error`.
818 /// Returns `Ok` if memory was grown successfully.
819 fn grow_to(&mut self, new_size: usize) -> Result<()>;
820
821 /// Return the allocated memory as a mutable pointer to u8.
822 fn as_ptr(&self) -> *mut u8;
823
824 /// Optionally initializes this memory's contents from a copy-on-write
825 /// [`MemoryImage`].
826 ///
827 /// When [copy-on-write memory initialization][cow_config] is enabled and a
828 /// module's data segments for this memory can be represented as an image,
829 /// Wasmtime calls this method once, right after the memory is created
830 /// and before anything else reads or writes it.
831 ///
832 /// If the function succeeds with `false`, the runtime assumes the memory was not initialized.
833 /// It then fully copies the module's data segments into the memory region.
834 /// This is always correct and is essentially equivalent to CoW being disabled.
835 ///
836 /// If the function succeeds with `true`, the runtime assumes the memory's contents match `image` exactly.
837 /// The bytes of the image must start at [`MemoryImage::linear_memory_offset`] and all other bytes must be zero.
838 ///
839 /// ## Shortcut for memory maps
840 ///
841 /// [`MemoryImage`] exposes a shortcut, [`MemoryImage::map_at`], which allows an implementation
842 /// backed by a memory map to replace a portion of its mapping with the pages of the image.
843 /// Consult that function's documentation for safety notes.
844 ///
845 /// Returning an error causes instantiation to fail with that error.
846 ///
847 /// [cow_config]: crate::Config::memory_init_cow
848 fn init_from_image(&mut self, image: &MemoryImage) -> Result<bool> {
849 let _ = image;
850 Ok(false)
851 }
852}
853
854/// A copy-on-write image of the initial contents of a linear memory.
855///
856/// When [`Config::memory_init_cow`](crate::Config::memory_init_cow) is enabled
857/// Wasmtime prepares, where possible, an image of a module's data segments for
858/// each of its linear memories that can be mapped into memory copy-on-write
859/// instead of being copied byte-by-byte. Such images are handed to
860/// [`LinearMemory::init_from_image`] for the specific memory implementation to map into its
861/// underlying representation.
862///
863/// An image covers [`len()`](MemoryImage::len) bytes of the linear memory starting at
864/// [`linear_memory_offset()`](MemoryImage::linear_memory_offset).
865/// Both values are multiples of the host page size, and the image always lies within
866/// the minimum size of the memory it was created for.
867/// All other bytes are expected to be zero.
868///
869/// Cloning a `MemoryImage` is cheap and keeps the underlying image alive.
870#[derive(Clone)]
871pub struct MemoryImage {
872 image: Arc<vm::MemoryImage>,
873}
874
875impl MemoryImage {
876 pub(crate) fn new(image: Arc<vm::MemoryImage>) -> MemoryImage {
877 MemoryImage { image }
878 }
879
880 /// This is a convenience method for the internal `MmapMemory` to access the underlying image
881 /// directly and use its [`map_at`](vm::MemoryImage::map_at) function.
882 #[cfg(has_virtual_memory)]
883 pub(crate) fn vm(&self) -> &vm::MemoryImage {
884 &self.image
885 }
886
887 /// Returns the offset, in bytes, within linear memory where this image
888 /// starts.
889 ///
890 /// This is guaranteed to be a multiple of the host page size.
891 pub fn linear_memory_offset(&self) -> usize {
892 self.image.linear_memory_offset()
893 }
894
895 /// Returns the length, in bytes, of this image.
896 ///
897 /// This is guaranteed to be a multiple of the host page size.
898 pub fn len(&self) -> usize {
899 self.image.len()
900 }
901
902 /// Returns whether this image is empty (length equal to zero).
903 pub fn is_empty(&self) -> bool {
904 self.len() == 0
905 }
906
907 /// Returns the bytes of this image.
908 ///
909 /// The returned slice is [`len()`](MemoryImage::len) bytes long and holds
910 /// the initial contents of linear memory starting at
911 /// [`linear_memory_offset()`](MemoryImage::linear_memory_offset). All
912 /// bytes of the memory outside of that range are initially zero.
913 pub fn data(&self) -> &[u8] {
914 self.image.data()
915 }
916
917 /// Maps this image copy-on-write into the linear memory starting at
918 /// `base`.
919 ///
920 /// The bytes `base + linear_memory_offset()` up to
921 /// `base + linear_memory_offset() + len()` are replaced with a private,
922 /// readable and writable copy-on-write mapping of the image. Nothing
923 /// outside of that range is modified.
924 ///
925 /// Returns an error if `base` is not aligned to the host page size or if
926 /// the underlying mapping operation fails.
927 ///
928 /// # Safety
929 ///
930 /// The caller must exclusively own the virtual memory range being mapped
931 /// over, nothing may hold references into it, and it must be valid for
932 /// its pages to be replaced by a new mapping (for example by `mmap` with
933 /// `MAP_FIXED` on Unix). Any previous contents and memory protections of
934 /// that range are lost. The mapping lives until the range is unmapped or
935 /// mapped over again by its owner. In particular, the runtime does not unmap the image by itself.
936 /// The owner of the virtual memory range must clean it up after usage.
937 ///
938 /// The typical usage is owning a memory-mapped region and requesting the image to be mapped
939 /// into a subrange of that mapping. Unmapping the entire region at the end of the memory's
940 /// lifetime takes care of the cleanup.
941 pub unsafe fn map_at(&self, base: *mut u8) -> Result<()> {
942 // SAFETY: forwarded to the caller.
943 unsafe { self.image.map_at_ptr(base) }
944 }
945}
946
947impl fmt::Debug for MemoryImage {
948 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
949 f.debug_struct("MemoryImage")
950 .field("linear_memory_offset", &self.linear_memory_offset())
951 .field("len", &self.len())
952 .finish_non_exhaustive()
953 }
954}
955
956impl PartialEq for MemoryImage {
957 fn eq(&self, other: &Self) -> bool {
958 Arc::ptr_eq(&self.image, &other.image)
959 }
960}
961
962impl Eq for MemoryImage {}
963
964impl core::hash::Hash for MemoryImage {
965 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
966 core::ptr::hash(Arc::as_ptr(&self.image), state)
967 }
968}
969
970/// A memory creator. Can be used to provide a memory creator
971/// to wasmtime which supplies host managed memory.
972///
973/// # Safety
974///
975/// This trait is unsafe, as the memory safety depends on proper implementation
976/// of memory management. Memories created by the MemoryCreator should always be
977/// treated as owned by wasmtime instance, and any modification of them outside
978/// of wasmtime invoked routines is unsafe and may lead to corruption.
979///
980/// Note that this is a relatively advanced feature and it is recommended to be
981/// familiar with Wasmtime runtime code to use it.
982pub unsafe trait MemoryCreator: Send + Sync {
983 /// Create a new [`LinearMemory`] object from the specified parameters.
984 ///
985 /// The returned memory must satisfy all of the properties of the [`MemoryRequest`]
986 /// and be zero filled.
987 fn new_memory(&self, request: &MemoryRequest<'_>) -> Result<Box<dyn LinearMemory>>;
988}
989
990/// The kind of memory that [`MemoryCreator`] is asked to create.
991#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
992#[non_exhaustive]
993pub enum MemoryKind {
994 /// A standard WebAssembly linear memory (module or host).
995 LinearMemory,
996 /// The memory backing a store's GC heap.
997 ///
998 /// It differs from standard linear memory:
999 /// - It is created lazily, at most once per store: when a module that needs a GC heap is
1000 /// instantiated or when the first GC object is allocated. This might happen in the middle of
1001 /// execution of WebAssembly code.
1002 /// - It grows as GC objects are allocated, independently of `memory.grow`.
1003 /// - Its contents are Wasmtime's internal representation of GC objects, not data of the guest
1004 /// program. They are only meaningful to the store that created the GC heap, so they should not
1005 /// be shared, persisted, copied to other memories, etc.
1006 GcHeap,
1007}
1008
1009impl From<wasmtime_environ::MemoryKind> for MemoryKind {
1010 fn from(value: wasmtime_environ::MemoryKind) -> Self {
1011 match value {
1012 wasmtime_environ::MemoryKind::LinearMemory => Self::LinearMemory,
1013 wasmtime_environ::MemoryKind::GcHeap => Self::GcHeap,
1014 }
1015 }
1016}
1017
1018/// A request to a [`MemoryCreator::new_memory`].
1019pub struct MemoryRequest<'a> {
1020 ty: &'a wasmtime_environ::Memory,
1021 tunables: &'a MemoryTunables<'a>,
1022 minimum: usize,
1023 maximum: Option<usize>,
1024}
1025
1026impl<'a> MemoryRequest<'a> {
1027 pub(crate) fn new(
1028 ty: &'a wasmtime_environ::Memory,
1029 tunables: &'a MemoryTunables<'a>,
1030 minimum: usize,
1031 maximum: Option<usize>,
1032 ) -> Self {
1033 Self {
1034 ty,
1035 tunables,
1036 minimum,
1037 maximum,
1038 }
1039 }
1040
1041 /// The type of memory being created. Indicates
1042 /// both the minimum and maximum size, in wasm pages. The minimum and
1043 /// maximum sizes, in bytes, are also specified as [`minimum`](Self::minimum) and [`maximum`](Self::maximum)
1044 /// to avoid integer conversion if desired.
1045 pub fn ty(&self) -> MemoryType {
1046 MemoryType::from_wasmtime_memory(self.ty)
1047 }
1048
1049 /// Minimum size of the memory in bytes.
1050 /// Same as the minimum of [`ty`](Self::ty), but in bytes.
1051 pub fn minimum(&self) -> usize {
1052 self.minimum
1053 }
1054
1055 /// Limit on the maximum size of the memory in bytes, if any.
1056 /// Same as the maximum of [`ty`](Self::ty), but in bytes.
1057 pub fn maximum(&self) -> Option<usize> {
1058 self.maximum
1059 }
1060
1061 /// Indicates the expected size of the reservation that is to be made for this memory.
1062 /// The implementation must reserve this many bytes for the memory's allocation, plus the guard
1063 /// size at the end. Note that this reservation need only be a virtual
1064 /// memory reservation, physical memory does not need to be allocated
1065 /// immediately.
1066 ///
1067 /// If this value is not zero, [`grow_to`](LinearMemory::grow_to) should never move the base pointer and
1068 /// the maximum size of [`ty`](Self::ty) is guaranteed to fit within `reserved_size_in_bytes`.
1069 ///
1070 /// This value is tuned from the various [`Config`](crate::Config) methods about
1071 /// memory sizes/guards. It is guaranteed to be a multiple of the system page size.
1072 pub fn reserved_size_in_bytes(&self) -> usize {
1073 usize::try_from(self.tunables.reservation()).unwrap()
1074 }
1075
1076 /// Indicates how many bytes of space after the memory allocation is expected to be unmapped. JIT code will
1077 /// elide bounds checks based on the `guard_size_in_bytes` provided, so for
1078 /// JIT code to work correctly the memory returned will need to be properly
1079 /// guarded with `guard_size_in_bytes` bytes left unmapped after the base
1080 /// allocation.
1081 ///
1082 /// This value is tuned from the various [`Config`](crate::Config) methods about
1083 /// memory sizes/guards. It is guaranteed to be a multiple of the system page size.
1084 pub fn guard_size_in_bytes(&self) -> usize {
1085 usize::try_from(self.tunables.guard_size()).unwrap()
1086 }
1087
1088 /// What kind of memory is requested.
1089 pub fn kind(&self) -> MemoryKind {
1090 self.tunables.kind().into()
1091 }
1092
1093 /// Internal parameter: detailed internal representation of the memory being created.
1094 pub(crate) fn wasmtime_memory(&self) -> &'a wasmtime_environ::Memory {
1095 self.ty
1096 }
1097
1098 /// Internal parameter: all the tunables, including those not exposed to the public API.
1099 pub(crate) fn tunables(&self) -> &'a MemoryTunables<'a> {
1100 self.tunables
1101 }
1102}
1103
1104impl fmt::Debug for MemoryRequest<'_> {
1105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1106 f.debug_struct("MemoryRequest")
1107 .field("ty", &self.ty())
1108 .field("minimum", &self.minimum)
1109 .field("maximum", &self.maximum)
1110 .field("reserved_size_in_bytes", &self.reserved_size_in_bytes())
1111 .field("guard_size_in_bytes", &self.guard_size_in_bytes())
1112 .field("kind", &self.kind())
1113 .finish()
1114 }
1115}
1116
1117/// A constructor for externally-created shared memory.
1118///
1119/// The [threads proposal] adds the concept of "shared memory" to WebAssembly.
1120/// This is much the same as a Wasm linear memory (i.e., [`Memory`]), but can be
1121/// used concurrently by multiple agents. Because these agents may execute in
1122/// different threads, [`SharedMemory`] must be thread-safe.
1123///
1124/// When the [threads proposal is enabled](crate::Config::wasm_threads) and the
1125/// [the creation of shared memories is enabled](crate::Config::shared_memory),
1126/// there are multiple ways to construct shared memory:
1127/// 1. for imported shared memory, e.g., `(import "env" "memory" (memory 1 1
1128/// shared))`, the user must supply a [`SharedMemory`] with the
1129/// externally-created memory as an import to the instance--e.g.,
1130/// `shared_memory.into()`.
1131/// 2. for private or exported shared memory, e.g., `(export "env" "memory"
1132/// (memory 1 1 shared))`, Wasmtime will create the memory internally during
1133/// instantiation--access using `Instance::get_shared_memory()`.
1134///
1135/// [threads proposal]:
1136/// https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md
1137///
1138/// # Examples
1139///
1140/// ```
1141/// # use wasmtime::*;
1142/// # fn main() -> Result<()> {
1143/// let mut config = Config::new();
1144/// config.wasm_threads(true);
1145/// config.shared_memory(true);
1146/// # if Engine::new(&config).is_err() { return Ok(()); }
1147/// let engine = Engine::new(&config)?;
1148/// let mut store = Store::new(&engine, ());
1149///
1150/// let shared_memory = SharedMemory::new(&engine, MemoryType::shared(1, 2)?)?;
1151/// let module = Module::new(&engine, r#"(module (memory (import "" "") 1 2 shared))"#)?;
1152/// let instance = Instance::new(&mut store, &module, &[shared_memory.into()])?;
1153/// // ...
1154/// # Ok(())
1155/// # }
1156/// ```
1157#[derive(Clone)]
1158pub struct SharedMemory {
1159 vm: crate::runtime::vm::SharedMemory,
1160 engine: Engine,
1161}
1162
1163impl SharedMemory {
1164 /// Construct a [`SharedMemory`] by providing both the `minimum` and
1165 /// `maximum` number of 64K-sized pages. This call allocates the necessary
1166 /// pages on the system.
1167 ///
1168 /// # Errors
1169 ///
1170 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
1171 /// memory allocation fails. See the `OutOfMemory` type's documentation for
1172 /// details on Wasmtime's out-of-memory handling.
1173 #[cfg(feature = "threads")]
1174 pub fn new(engine: &Engine, ty: MemoryType) -> Result<Self> {
1175 if !ty.is_shared() {
1176 bail!("shared memory must have the `shared` flag enabled on its memory type")
1177 }
1178 debug_assert!(ty.maximum().is_some());
1179
1180 let ty = ty.wasmtime_memory();
1181 let memory = crate::runtime::vm::SharedMemory::new(engine, ty)?;
1182
1183 Ok(Self {
1184 vm: memory,
1185 engine: engine.clone(),
1186 })
1187 }
1188
1189 /// Return the type of the shared memory.
1190 pub fn ty(&self) -> MemoryType {
1191 MemoryType::from_wasmtime_memory(&self.vm.ty())
1192 }
1193
1194 /// Returns the size, in WebAssembly pages, of this wasm memory.
1195 pub fn size(&self) -> u64 {
1196 let byte_size = u64::try_from(self.data_size()).unwrap();
1197 let page_size = self.page_size();
1198 byte_size / page_size
1199 }
1200
1201 /// Returns the size of a page, in bytes, for this memory.
1202 ///
1203 /// By default this is 64KiB (aka `0x10000`, `2**16`, `1<<16`, or `65536`)
1204 /// but [the custom-page-sizes proposal] allows opting into a page size of
1205 /// `1`. Future extensions might allow any power of two as a page size.
1206 ///
1207 /// [the custom-page-sizes proposal]: https://github.com/WebAssembly/custom-page-sizes
1208 pub fn page_size(&self) -> u64 {
1209 self.ty().page_size()
1210 }
1211
1212 /// Returns the byte length of this memory.
1213 ///
1214 /// The returned value will be a multiple of the wasm page size, 64k.
1215 ///
1216 /// For more information and examples see the documentation on the
1217 /// [`Memory`] type.
1218 pub fn data_size(&self) -> usize {
1219 self.vm.byte_size()
1220 }
1221
1222 /// Return access to the available portion of the shared memory.
1223 ///
1224 /// The slice returned represents the region of accessible memory at the
1225 /// time that this function was called. The contents of the returned slice
1226 /// will reflect concurrent modifications happening on other threads.
1227 ///
1228 /// # Safety
1229 ///
1230 /// The returned slice is valid for the entire duration of the lifetime of
1231 /// this instance of [`SharedMemory`]. The base pointer of a shared memory
1232 /// does not change. This [`SharedMemory`] may grow further after this
1233 /// function has been called, but the slice returned will not grow.
1234 ///
1235 /// Concurrent modifications may be happening to the data returned on other
1236 /// threads. The `UnsafeCell<u8>` represents that safe access to the
1237 /// contents of the slice is not possible through normal loads and stores.
1238 ///
1239 /// The memory returned must be accessed safely through the `Atomic*` types
1240 /// in the [`std::sync::atomic`] module. Casting to those types must
1241 /// currently be done unsafely.
1242 pub fn data(&self) -> &[UnsafeCell<u8>] {
1243 unsafe {
1244 let definition = self.vm.vmmemory_ptr().as_ref();
1245 slice::from_raw_parts(definition.base.as_ptr().cast(), definition.current_length())
1246 }
1247 }
1248
1249 /// Grows this WebAssembly memory by `delta` pages.
1250 ///
1251 /// This will attempt to add `delta` more pages of memory on to the end of
1252 /// this `Memory` instance. If successful this may relocate the memory and
1253 /// cause [`Memory::data_ptr`] to return a new value. Additionally any
1254 /// unsafely constructed slices into this memory may no longer be valid.
1255 ///
1256 /// On success returns the number of pages this memory previously had
1257 /// before the growth succeeded.
1258 ///
1259 /// # Errors
1260 ///
1261 /// This function will return errors for a similar reason as
1262 /// [`Memory::grow`].
1263 pub fn grow(&self, delta: u64) -> Result<u64> {
1264 match self.vm.grow(delta)? {
1265 Some((old_size, _new_size)) => {
1266 // For shared memory, the `VMMemoryDefinition` is updated inside
1267 // the locked region.
1268 Ok(u64::try_from(old_size).unwrap() / self.page_size())
1269 }
1270 None => bail!("failed to grow memory by `{delta}`"),
1271 }
1272 }
1273
1274 /// Returns a stable identifier for this shared memory when introspecting
1275 /// it through the debug APIs.
1276 #[cfg(feature = "debug")]
1277 pub fn debug_index_in_store(&self) -> u64 {
1278 u64::try_from(self.vm.vmmemory_ptr().as_ptr().addr()).unwrap()
1279 }
1280
1281 /// Equivalent of the WebAssembly `memory.atomic.notify` instruction for
1282 /// this shared memory.
1283 ///
1284 /// This method allows embedders to notify threads blocked on the specified
1285 /// `addr`, an index into wasm linear memory. Threads could include
1286 /// wasm threads blocked on a `memory.atomic.wait*` instruction or embedder
1287 /// threads blocked on [`SharedMemory::atomic_wait32`], for example.
1288 ///
1289 /// The `count` argument is the number of threads to wake up.
1290 ///
1291 /// This function returns the number of threads awoken.
1292 ///
1293 /// # Errors
1294 ///
1295 /// This function will return an error if `addr` is not within bounds or
1296 /// not aligned to a 4-byte boundary.
1297 pub fn atomic_notify(&self, addr: u64, count: u32) -> Result<u32, Trap> {
1298 self.vm.atomic_notify(addr, count)
1299 }
1300
1301 /// Equivalent of the WebAssembly `memory.atomic.wait32` instruction for
1302 /// this shared memory.
1303 ///
1304 /// This method allows embedders to block the current thread until notified
1305 /// via the `memory.atomic.notify` instruction or the
1306 /// [`SharedMemory::atomic_notify`] method, enabling synchronization with
1307 /// the wasm guest as desired.
1308 ///
1309 /// The `expected` argument is the expected 32-bit value to be stored at
1310 /// the byte address `addr` specified. The `addr` specified is an index
1311 /// into this linear memory.
1312 ///
1313 /// The optional `timeout` argument is the maximum amount of time to block
1314 /// the current thread. If not specified the thread may sleep indefinitely.
1315 ///
1316 /// This function returns one of three possible values:
1317 ///
1318 /// * `WaitResult::Ok` - this function, loaded the value at `addr`, found
1319 /// it was equal to `expected`, and then blocked (all as one atomic
1320 /// operation). The thread was then awoken with a `memory.atomic.notify`
1321 /// instruction or the [`SharedMemory::atomic_notify`] method.
1322 /// * `WaitResult::Mismatch` - the value at `addr` was loaded but was not
1323 /// equal to `expected` so the thread did not block and immediately
1324 /// returned.
1325 /// * `WaitResult::TimedOut` - all the steps of `Ok` happened, except this
1326 /// thread was woken up due to a timeout.
1327 ///
1328 /// This function will not return due to spurious wakeups.
1329 ///
1330 /// # Errors
1331 ///
1332 /// This function will return an error if `addr` is not within bounds or
1333 /// not aligned to a 4-byte boundary.
1334 pub fn atomic_wait32(
1335 &self,
1336 addr: u64,
1337 expected: u32,
1338 timeout: Option<Duration>,
1339 ) -> Result<WaitResult, Trap> {
1340 self.vm.atomic_wait32(addr, expected, timeout)
1341 }
1342
1343 /// Equivalent of the WebAssembly `memory.atomic.wait64` instruction for
1344 /// this shared memory.
1345 ///
1346 /// For more information see [`SharedMemory::atomic_wait32`].
1347 ///
1348 /// # Errors
1349 ///
1350 /// Returns the same error as [`SharedMemory::atomic_wait32`] except that
1351 /// the specified address must be 8-byte aligned instead of 4-byte aligned.
1352 pub fn atomic_wait64(
1353 &self,
1354 addr: u64,
1355 expected: u64,
1356 timeout: Option<Duration>,
1357 ) -> Result<WaitResult, Trap> {
1358 self.vm.atomic_wait64(addr, expected, timeout)
1359 }
1360
1361 /// Return a reference to the [`Engine`] used to configure the shared
1362 /// memory.
1363 pub(crate) fn engine(&self) -> &Engine {
1364 &self.engine
1365 }
1366
1367 /// Construct a single-memory instance to provide a way to import
1368 /// [`SharedMemory`] into other modules.
1369 pub(crate) fn vmimport(&self, store: &mut StoreOpaque) -> crate::runtime::vm::VMMemoryImport {
1370 // Note `vm::assert_ready` shouldn't panic here because this isn't
1371 // actually allocating any new memory (also no limiter), so resource
1372 // limiting shouldn't kick in.
1373 let memory = vm::assert_ready(generate_memory_export(
1374 store,
1375 None,
1376 &self.ty(),
1377 Some(&self.vm),
1378 ))
1379 .unwrap();
1380 match memory {
1381 ExportMemory::Unshared(_) => unreachable!(),
1382 ExportMemory::Shared(_shared, vmimport) => vmimport,
1383 }
1384 }
1385
1386 /// Creates a [`SharedMemory`] from its constituent parts.
1387 pub(crate) fn from_raw(vm: crate::runtime::vm::SharedMemory, engine: Engine) -> Self {
1388 SharedMemory { vm, engine }
1389 }
1390}
1391
1392impl fmt::Debug for SharedMemory {
1393 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1394 f.debug_struct("SharedMemory").finish_non_exhaustive()
1395 }
1396}
1397
1398#[cfg(test)]
1399mod tests {
1400 use crate::*;
1401
1402 // Assert that creating a memory via `Memory::new` respects the limits/tunables
1403 // in `Config`.
1404 #[test]
1405 fn respect_tunables() {
1406 let mut cfg = Config::new();
1407 cfg.memory_reservation(0).memory_guard_size(0);
1408 let mut store = Store::new(&Engine::new(&cfg).unwrap(), ());
1409 let ty = MemoryType::new(1, None).unwrap();
1410 let mem = Memory::new(&mut store, ty).unwrap();
1411 let store = store.as_context();
1412 let tunables = store.engine().tunables();
1413 assert_eq!(tunables.memory_guard_size, 0);
1414 assert!(!mem.wasmtime_ty(store.0).can_elide_bounds_check(
1415 &wasmtime_environ::MemoryTunables::new(
1416 tunables,
1417 wasmtime_environ::MemoryKind::LinearMemory,
1418 ),
1419 12,
1420 ));
1421 }
1422
1423 #[test]
1424 fn hash_key_is_stable_across_duplicate_store_data_entries() -> Result<()> {
1425 let mut store = Store::<()>::default();
1426 let module = Module::new(
1427 store.engine(),
1428 r#"
1429 (module
1430 (memory (export "m") 1 1)
1431 )
1432 "#,
1433 )?;
1434 let instance = Instance::new(&mut store, &module, &[])?;
1435
1436 // Each time we `get_memory`, we call `Memory::from_wasmtime` which adds
1437 // a new entry to `StoreData`, so `g1` and `g2` will have different
1438 // indices into `StoreData`.
1439 let m1 = instance.get_memory(&mut store, "m").unwrap();
1440 let m2 = instance.get_memory(&mut store, "m").unwrap();
1441
1442 // That said, they really point to the same memory.
1443 assert_eq!(m1.data(&store)[0], 0);
1444 assert_eq!(m2.data(&store)[0], 0);
1445 m1.data_mut(&mut store)[0] = 42;
1446 assert_eq!(m1.data(&mut store)[0], 42);
1447 assert_eq!(m2.data(&mut store)[0], 42);
1448
1449 // And therefore their hash keys are the same.
1450 assert!(m1.hash_key(&store.as_context().0) == m2.hash_key(&store.as_context().0));
1451
1452 // But the hash keys are different from different memories.
1453 let instance2 = Instance::new(&mut store, &module, &[])?;
1454 let m3 = instance2.get_memory(&mut store, "m").unwrap();
1455 assert!(m1.hash_key(&store.as_context().0) != m3.hash_key(&store.as_context().0));
1456
1457 Ok(())
1458 }
1459
1460 /// Offset of the data segment used by the `MemoryImage` tests: inside the
1461 /// second Wasm page, but not at the start of a host page.
1462 #[cfg(all(target_os = "linux", not(miri)))]
1463 const IMAGE_DATA_OFFSET: usize = 0x10000 + 8;
1464
1465 /// Compiles a module whose single memory is initialized by one data segment
1466 /// at `IMAGE_DATA_OFFSET` and returns the CoW image Wasmtime builds for it.
1467 /// The module is never instantiated, we just take the image of the memory.
1468 #[cfg(all(target_os = "linux", not(miri)))]
1469 fn memory_image_for_data(data: &str) -> Result<MemoryImage> {
1470 let mut config = Config::new();
1471 config.memory_init_cow(true);
1472 let engine = Engine::new(&config)?;
1473 let module = Module::new(
1474 &engine,
1475 // Module with (at least) 2 pages of memory with data written at IMAGE_DATA_OFFSET.
1476 format!("(module (memory 2) (data (i32.const {IMAGE_DATA_OFFSET}) \"{data}\"))"),
1477 )?;
1478 let images = module.memory_images()?.expect("module has memory images");
1479 let image = images
1480 .get_memory_image(wasmtime_environ::DefinedMemoryIndex::from_u32(0))
1481 .expect("memory 0 has an image");
1482 Ok(MemoryImage::new(image.clone()))
1483 }
1484
1485 /// The public accessors report the internal image's placement, and:
1486 /// - both values are multiples of the host page size; and
1487 /// - the image covers the module's data.
1488 #[test]
1489 #[cfg(all(target_os = "linux", not(miri)))]
1490 fn memory_image_accessors() -> Result<()> {
1491 let page_size = crate::runtime::vm::host_page_size();
1492 let image = memory_image_for_data("hello")?;
1493 let offset = image.linear_memory_offset();
1494 let len = image.len();
1495
1496 assert_eq!(offset, image.vm().linear_memory_offset());
1497 assert_eq!(len, image.vm().len());
1498 assert_eq!(offset % page_size, 0);
1499 assert_eq!(len % page_size, 0);
1500 assert!(!image.is_empty());
1501 // Image starts at or before the data...
1502 assert!(offset <= IMAGE_DATA_OFFSET);
1503 // ... and reaches past the end of the data.
1504 assert!(offset + len >= IMAGE_DATA_OFFSET + "hello".len());
1505
1506 let data = image.data();
1507 assert_eq!(data.len(), len);
1508 assert_eq!(data, image.vm().data());
1509 let data_start = IMAGE_DATA_OFFSET - offset;
1510 assert_eq!(&data[data_start..][..5], b"hello");
1511 assert!(data[..data_start].iter().all(|b| *b == 0));
1512 assert!(data[data_start + 5..].iter().all(|b| *b == 0));
1513
1514 // Clones share the same underlying image.
1515 let clone = image.clone();
1516 assert!(core::ptr::eq(clone.vm(), image.vm()));
1517 Ok(())
1518 }
1519
1520 #[test]
1521 #[cfg(all(target_os = "linux", not(miri)))]
1522 fn memory_image_identity() -> Result<()> {
1523 use std::hash::{BuildHasher, RandomState};
1524
1525 let mut config = Config::new();
1526 config.memory_init_cow(true);
1527 let engine = Engine::new(&config)?;
1528 let wat = r#"(module (memory 1) (data (i32.const 0) "hello"))"#;
1529 let image_of = |module: &Module| -> Result<MemoryImage> {
1530 let images = module.memory_images()?.expect("module has memory images");
1531 let image = images
1532 .get_memory_image(wasmtime_environ::DefinedMemoryIndex::from_u32(0))
1533 .expect("memory 0 has an image");
1534 Ok(MemoryImage::new(image.clone()))
1535 };
1536
1537 let module = Module::new(&engine, wat)?;
1538 let image = image_of(&module)?;
1539 let same = image_of(&module)?; // Same module instance gives the same image.
1540 let clone = image.clone(); // Clone just clones an Arc.
1541
1542 assert_eq!(image, same);
1543 assert_eq!(image, clone);
1544
1545 let hasher = RandomState::new();
1546 assert_eq!(hasher.hash_one(&image), hasher.hash_one(&same));
1547 assert_eq!(hasher.hash_one(&image), hasher.hash_one(&clone));
1548
1549 Ok(())
1550 }
1551
1552 /// `MemoryImage::map_at` places the image's bytes at
1553 /// `base + linear_memory_offset()` and zeroes the rest.
1554 #[test]
1555 #[cfg(all(target_os = "linux", not(miri)))]
1556 fn memory_image_map_at() -> Result<()> {
1557 use crate::runtime::vm::{HostAlignedByteCount, Mmap};
1558
1559 let image = memory_image_for_data("hello")?;
1560 let size =
1561 HostAlignedByteCount::new_rounded_up(image.linear_memory_offset() + image.len())?;
1562 let mmap = Mmap::accessible_reserved(HostAlignedByteCount::ZERO, size)?;
1563 let base = mmap.as_non_null().as_ptr();
1564
1565 // SAFETY: `mmap` was just created, is owned by this test and covers
1566 // the whole range the image is mapped into.
1567 unsafe { image.map_at(base)? };
1568
1569 // SAFETY: `map_at` made the image's range readable.
1570 let mapped = unsafe {
1571 core::slice::from_raw_parts(base.add(image.linear_memory_offset()), image.len())
1572 };
1573 let data_start = IMAGE_DATA_OFFSET - image.linear_memory_offset();
1574
1575 assert_eq!(mapped, image.data());
1576 assert_eq!(&mapped[data_start..][..5], b"hello");
1577 assert!(mapped[..data_start].iter().all(|b| *b == 0));
1578 assert!(mapped[data_start + 5..].iter().all(|b| *b == 0));
1579
1580 Ok(())
1581 }
1582}