xref: /linux/rust/kernel/alloc/box_ext.rs (revision 1a371190a375f98c9b106f758ea41558c3f92556)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! Extensions to [`Box`] for fallible allocations.
4 
5 use super::{AllocError, Flags};
6 use alloc::boxed::Box;
7 use core::mem::MaybeUninit;
8 
9 /// Extensions to [`Box`].
10 pub trait BoxExt<T>: Sized {
11     /// Allocates a new box.
12     ///
13     /// The allocation may fail, in which case an error is returned.
new(x: T, flags: Flags) -> Result<Self, AllocError>14     fn new(x: T, flags: Flags) -> Result<Self, AllocError>;
15 
16     /// Allocates a new uninitialised box.
17     ///
18     /// The allocation may fail, in which case an error is returned.
new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>19     fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>;
20 }
21 
22 impl<T> BoxExt<T> for Box<T> {
new(x: T, flags: Flags) -> Result<Self, AllocError>23     fn new(x: T, flags: Flags) -> Result<Self, AllocError> {
24         let mut b = <Self as BoxExt<_>>::new_uninit(flags)?;
25         b.write(x);
26         // SAFETY: We just wrote to it.
27         Ok(unsafe { b.assume_init() })
28     }
29 
30     #[cfg(any(test, testlib))]
new_uninit(_flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>31     fn new_uninit(_flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> {
32         Ok(Box::new_uninit())
33     }
34 
35     #[cfg(not(any(test, testlib)))]
new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>36     fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> {
37         let ptr = if core::mem::size_of::<MaybeUninit<T>>() == 0 {
38             core::ptr::NonNull::<_>::dangling().as_ptr()
39         } else {
40             let layout = core::alloc::Layout::new::<MaybeUninit<T>>();
41 
42             // SAFETY: Memory is being allocated (first arg is null). The only other source of
43             // safety issues is sleeping on atomic context, which is addressed by klint. Lastly,
44             // the type is not a SZT (checked above).
45             let ptr =
46                 unsafe { super::allocator::krealloc_aligned(core::ptr::null_mut(), layout, flags) };
47             if ptr.is_null() {
48                 return Err(AllocError);
49             }
50 
51             ptr.cast::<MaybeUninit<T>>()
52         };
53 
54         // SAFETY: For non-zero-sized types, we allocate above using the global allocator. For
55         // zero-sized types, we use `NonNull::dangling`.
56         Ok(unsafe { Box::from_raw(ptr) })
57     }
58 }
59