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