#Uninit Box
33 messages · Page 1 of 1 (latest)
On nightly, there's https://doc.rust-lang.org/std/boxed/struct.Box.html#method.new_uninit
On stable, you have to:
- make sure the type isn't a ZST
- call https://doc.rust-lang.org/std/alloc/fn.alloc.html
- call https://doc.rust-lang.org/std/boxed/struct.Box.html#method.from_raw
there's also things like https://docs.rs/bytemuck/latest/bytemuck/allocation/fn.zeroed_box.html which you may be able to use depending on what T is
As try_zeroed_box, but unwraps for you.
Huh. Seems like the unstable method is likely to be stable in the version after next (1.82). It just finished FCP.
pub unsafe fn uninit_box<T>() -> Box<T> {
let layout = Layout::new::<T>();
let ptr = alloc(layout) as *mut T;
if ptr.is_null() {
handle_alloc_error(layout);
}
Box::from_raw(ptr)
}```
Aside from T being uninitialized, is there any other safety concern? (asking because I'm not sure if this deallocates)
that's a pretty huge "aside"
I know, that's why I marked the fn as unsafe, but I meant if there are other issues I'm oblivious to
it being uninitialized is a much bigger problem than you seem to think
you are not handling zero sized types correctly
it's also insta ub if you call it for types like u8 for example
anything that needs initializing
the ub happens inside the function, not in whatever the caller does with it next
that is because it's UB to have uninitialized values, not just when you use them
if you don't want to switch to nightly, you could just copy what std is doing
Source of the Rust file library/alloc/src/boxed.rs.
thanks, I might also give a deeper look to the unsafe docs
use std::alloc::{alloc, Layout};
use std::mem::MaybeUninit;
use std::ptr::NonNull;
pub fn uninit_box<T>() -> Box<MaybeUninit<T>> {
unsafe {
Box::from_raw(if size_of::<T>() == 0 {
NonNull::dangling().as_ptr()
} else {
let layout = Layout::new::<T>();
let ptr = alloc(layout).cast::<MaybeUninit<T>>();
if ptr.is_null() {
panic!("allocation failed");
}
ptr
})
}
}
This post is about uninitialized memory, but also about the semantics of highly optimized “low-level” languages in general. I will try to convince you that reasoning by “what the hardware d...
you can also just.. Box::new(MaybeUninit::uninit())
I don't think it's insta ub? you don't have a uninitialized value. you have a pointer to uninitialized memory, which is fine.
it will of course still blow up the second you are using the box, but the creation itself is fine
He wanted to not store it on the stack first
?eval Box::new(std::mem::MaybeUninit::<[i128; 10000000]>::uninit())
thread 'main' has overflowed its stack
fatal runtime error: stack overflow```
I think it's instant UB, just like MaybeUninit::<u8>::uninit().assume_init() is insta UB
because the compiler is allowed to read the value at any point (even if it probably won't)
its kinda undecided what happens if there's indirection
Maybe the implementation of Vec::with_capacity will be useful for this case.
?eval ```rust
Vec::<i128>::with_capacity(10000000)
[]```
for context: they are basically implementing a simplified Vec as an exercise in unsafe code
so using Vec is correct, but against the spirit ;)
I don't mean using Vec, but seeing how with_capacity allocates (it seems to use the allocator directly) without exploding the stack might be useful.