Skip to main content

wasmtime_internal_core/error/
oom.rs

1use crate::error::{Error, OomOrDynError};
2use core::{fmt, mem, ptr::NonNull};
3
4/// Out-of-memory error.
5///
6/// This error is the sentinel for allocation failure due to memory exhaustion.
7///
8/// Constructing an [`Error`] from an `OutOfMemory` does not
9/// allocate.
10///
11/// Allocation failure inside any `Error` method that must allocate
12/// (e.g. [`Error::context`]) will propagate an `OutOfMemory` error.
13#[derive(Clone, Copy)]
14// NB: `OutOfMemory`'s representation must be the same as `OomOrDynError`
15// (and therefore also `Error`).
16#[repr(transparent)]
17pub struct OutOfMemory {
18    inner: NonNull<u8>,
19}
20
21// Safety: The `inner` pointer is not a real pointer, it is just bitpacked size
22// data.
23unsafe impl Send for OutOfMemory {}
24
25// Safety: The `inner` pointer is not a real pointer, it is just bitpacked size
26// data.
27unsafe impl Sync for OutOfMemory {}
28
29impl fmt::Debug for OutOfMemory {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        f.debug_struct("OutOfMemory")
32            .field(
33                "requested_allocation_size",
34                &self.requested_allocation_size(),
35            )
36            .finish()
37    }
38}
39
40impl fmt::Display for OutOfMemory {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        write!(
43            f,
44            "out of memory (failed to allocate {} bytes)",
45            self.requested_allocation_size()
46        )
47    }
48}
49
50impl core::error::Error for OutOfMemory {
51    #[inline]
52    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
53        None
54    }
55}
56
57impl OutOfMemory {
58    // NB: `OutOfMemory`'s representation must be the same as `OomOrDynError`
59    // (and therefore also `Error`).
60    const _SAME_SIZE_AS_OOM_OR_DYN_ERROR: () =
61        assert!(mem::size_of::<OutOfMemory>() == mem::size_of::<OomOrDynError>());
62    const _SAME_ALIGN_AS_OOM_OR_DYN_ERROR: () =
63        assert!(mem::align_of::<OutOfMemory>() == mem::align_of::<OomOrDynError>());
64    const _SAME_SIZE_AS_ERROR: () =
65        assert!(mem::size_of::<OutOfMemory>() == mem::size_of::<Error>());
66    const _SAME_ALIGN_AS_ERROR: () =
67        assert!(mem::align_of::<OutOfMemory>() == mem::align_of::<Error>());
68
69    /// Construct a new `OutOfMemory` error.
70    ///
71    /// The `requested_allocation_size` argument should be the size (in bytes)
72    /// of the associated allocation that was attempted and failed.
73    ///
74    /// This operation does not allocate.
75    ///
76    /// # Example
77    ///
78    /// ```rust
79    /// # use wasmtime_internal_core::error::OutOfMemory;
80    /// # extern crate alloc;
81    /// use alloc::alloc::{Layout, alloc};
82    /// use core::ptr::NonNull;
83    ///
84    /// /// Attempt to allocate a block of memory from the global allocator,
85    /// /// returning an `OutOfMemory` error on failure.
86    /// fn try_global_alloc(layout: Layout) -> Result<NonNull<u8>, OutOfMemory> {
87    ///     if layout.size() == 0 {
88    ///         return Ok(NonNull::dangling());
89    ///     }
90    ///
91    ///     // Safety: the layout's size is non-zero.
92    ///     let ptr = unsafe { alloc(layout) };
93    ///
94    ///     if let Some(ptr) = NonNull::new(ptr) {
95    ///         Ok(ptr)
96    ///     } else {
97    ///         // The allocation failed, so return an `OutOfMemory` error,
98    ///         // passing the attempted allocation's size into the `OutOfMemory`
99    ///         // constructor.
100    ///         Err(OutOfMemory::new(layout.size()))
101    ///     }
102    /// }
103    /// ```
104    #[inline]
105    pub const fn new(requested_allocation_size: usize) -> Self {
106        Self {
107            inner: OomOrDynError::new_oom_ptr(requested_allocation_size),
108        }
109    }
110
111    /// Get the size (in bytes) of the associated allocation that was attempted
112    /// and which failed.
113    ///
114    /// Very large allocation sizes (near `isize::MAX` and larger) may be capped
115    /// to a maximum value.
116    ///
117    /// # Example
118    ///
119    /// ```rust
120    /// # use wasmtime_internal_core::error::OutOfMemory;
121    /// let oom = OutOfMemory::new(8192);
122    /// assert_eq!(oom.requested_allocation_size(), 8192);
123    /// ```
124    #[inline]
125    pub fn requested_allocation_size(&self) -> usize {
126        OomOrDynError::oom_size(self.inner)
127    }
128}
129
130impl From<OutOfMemory> for OomOrDynError {
131    fn from(oom: OutOfMemory) -> Self {
132        OomOrDynError::new_oom(oom.inner)
133    }
134}