Skip to main content

wasmtime_internal_core/
alloc.rs

1//! Low-level allocation and OOM-handling utilities.
2
3mod arc;
4mod boxed;
5mod string;
6mod try_clone;
7mod try_collect;
8mod try_cow;
9mod try_new;
10mod vec;
11
12pub use boxed::{
13    BoxedSliceFromFallibleIterError, TooFewItemsOrOom, boxed_slice_write_iter,
14    new_boxed_slice_from_fallible_iter, new_boxed_slice_from_iter,
15    new_boxed_slice_from_iter_with_len, new_uninit_boxed_slice,
16};
17pub use string::TryString;
18pub use try_clone::TryClone;
19pub use try_collect::{TryCollect, TryExtend, TryFromIterator};
20pub use try_cow::{TryCow, TryToOwned};
21pub use try_new::{TryNew, try_new};
22pub use vec::Vec;
23
24use crate::error::OutOfMemory;
25use core::{alloc::Layout, ptr::NonNull};
26
27/// Try to allocate a block of memory that fits the given layout, or return an
28/// `OutOfMemory` error.
29///
30/// # Safety
31///
32/// Same as `alloc::alloc::alloc`: layout must have non-zero size.
33#[inline]
34unsafe fn try_alloc(layout: Layout) -> Result<NonNull<u8>, OutOfMemory> {
35    // Safety: same as our safety conditions.
36    debug_assert!(layout.size() > 0);
37    let ptr = unsafe { std_alloc::alloc::alloc(layout) };
38
39    if let Some(ptr) = NonNull::new(ptr) {
40        Ok(ptr)
41    } else {
42        Err(OutOfMemory::new(layout.size()))
43    }
44}
45
46/// Tries to reallocate a block of memory, returning `OutOfMemory` on failure.
47///
48/// Analogue of [`alloc::alloc::realloc`].
49///
50/// # Safety
51///
52/// Same as `alloc::alloc::realloc`: `ptr` must be allocated with `layout`,
53/// `layout` must be nonzero in size, and `new_size` must be nonzero and valid.
54#[inline]
55unsafe fn try_realloc(
56    ptr: *mut u8,
57    layout: Layout,
58    new_size: usize,
59) -> Result<NonNull<u8>, OutOfMemory> {
60    // Safety: same as our safety conditions.
61    debug_assert!(layout.size() > 0);
62    debug_assert!(new_size > 0);
63    let ptr = unsafe { std_alloc::alloc::realloc(ptr, layout, new_size) };
64
65    if let Some(ptr) = NonNull::new(ptr) {
66        Ok(ptr)
67    } else {
68        Err(OutOfMemory::new(new_size))
69    }
70}
71
72/// An extension trait for ignoring `OutOfMemory` errors.
73///
74/// Use this to unwrap a `Result<T, OutOfMemory>` into its inner `T` or
75/// otherwise panic, leveraging the type system to be sure that you aren't ever
76/// accidentally unwrapping non-`OutOfMemory` errors.
77pub trait PanicOnOom {
78    /// The non-`OutOfMemory` result of calling `panic_on_oom`.
79    type Result;
80
81    /// Panic on `OutOfMemory` errors, returning the non-`OutOfMemory` result.
82    fn panic_on_oom(self) -> Self::Result;
83}
84
85impl<T> PanicOnOom for Result<T, OutOfMemory> {
86    type Result = T;
87
88    #[track_caller]
89    fn panic_on_oom(self) -> Self::Result {
90        match self {
91            Ok(x) => x,
92            Err(oom) => panic!("unhandled out-of-memory error: {oom}"),
93        }
94    }
95}
96
97/// Create a `*mut str` from a pointer and length pair.
98///
99/// NB: This function is safe, but dereferencing it or otherwise using the
100/// resulting `str` pointer's contents is unsafe and requires that the pointer
101/// be valid for accessing and points to a valid utf8 sequence of `len` bytes.
102fn str_ptr_from_raw_parts(ptr: *mut u8, len: usize) -> *mut str {
103    let ptr: *mut [u8] = core::ptr::slice_from_raw_parts_mut(ptr, len);
104    str_ptr_from_slice_ptr(ptr)
105}
106
107/// Create a `*mut str` from a slice pointer.
108///
109/// NB: This function is safe, but dereferencing it or otherwise using the
110/// resulting `str` pointer's contents is unsafe and requires that the pointer
111/// be valid for accessing and points to a valid utf8 sequence of `len` bytes.
112fn str_ptr_from_slice_ptr(ptr: *mut [u8]) -> *mut str {
113    // SAFETY: `str` is a newtype of `[u8]`.
114    let ptr: *mut str = unsafe { core::mem::transmute(ptr) };
115    ptr
116}