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. 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. 19 fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>; 20 } 21 22 impl<T> BoxExt<T> for Box<T> { 23 fn new(x: T, flags: Flags) -> Result<Self, AllocError> { 24 let b = <Self as BoxExt<_>>::new_uninit(flags)?; 25 Ok(Box::write(b, x)) 26 } 27 28 #[cfg(any(test, testlib))] 29 fn new_uninit(_flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> { 30 Ok(Box::new_uninit()) 31 } 32 33 #[cfg(not(any(test, testlib)))] 34 fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> { 35 let ptr = if core::mem::size_of::<MaybeUninit<T>>() == 0 { 36 core::ptr::NonNull::<_>::dangling().as_ptr() 37 } else { 38 let layout = core::alloc::Layout::new::<MaybeUninit<T>>(); 39 40 // SAFETY: Memory is being allocated (first arg is null). The only other source of 41 // safety issues is sleeping on atomic context, which is addressed by klint. Lastly, 42 // the type is not a SZT (checked above). 43 let ptr = 44 unsafe { super::allocator::krealloc_aligned(core::ptr::null_mut(), layout, flags) }; 45 if ptr.is_null() { 46 return Err(AllocError); 47 } 48 49 ptr.cast::<MaybeUninit<T>>() 50 }; 51 52 // SAFETY: For non-zero-sized types, we allocate above using the global allocator. For 53 // zero-sized types, we use `NonNull::dangling`. 54 Ok(unsafe { Box::from_raw(ptr) }) 55 } 56 } 57