Tracking Issue for `Box::from_raw` as const_fn
Opened this issue · 17 comments
Hi,I think that Box::from_raw(raw: *mut T)
must be a const fn because it's implemented as Box(Unique::new_unchecked(raw))
and Unique::new_unchecked
it's a const fn.
It's very important for types that lazily allocate that trust in Box<T>
for their backing storage to have this line Box::from_raw(slice_from_raw_parts(align_of::<T>() as *mut T, 0))
constant safe for being able to mark their constructor as const.
concrete line: https://github.com/rust-lang/rust/blob/master/src/liballoc/boxed.rs#L393.
I opened this Issue as part of: #57563
How is this useful without having heap allocations in constants (rust-lang/const-eval#20)?
I do not think that's relevant to this,my point was that when you're reusing an allocation or creating a dangling pointer thought Box::from_raw
you should be able to mark that as constant.
There's no way to use Box at all yet, so you can't reuse an allocation. (Though I guess an empty boxed slice would be possible, but super niche)
You're wrong. There's no way for dropping or creating Box
es but any other context it is valid,like calling a constant method in a datastructure with a Box
in one field.
Althought the unique use case will be replacing a ManuallyDrop
with a dangling Box
,or creating a dangling one.
a dangling Box
It is UB to create a dangling Box
, so I am not sure what it is you want to do.
Giving a concrete and self-contained example of the kind of code you need this for would be helpful.
It is UB if the Box contains a Non-ZST that needs dropping,but as long the type either not needs dropping and does not get used or it is zero-sized there's no problem.
It is UB if the Box contains a Non-ZST that needs dropping
No, this is not correct.
It's UB for any non-ZST, no matter the dropping. As in, this is UB:
fn main() {
let x: Box<i32> = unsafe { Box::from_raw(16 as *mut i32) };
std::mem::forget(x);
}
If you run this in Miri on the playground, it will tell you as much. (This is why I asked for concrete code.)
For ZSTs, the pointer must be aligned and there are some further subtle restrictions.
You can tell me where the value got dereferenced? Miri says that this happen in the call to Box::from_raw
but it only stores a pointer inside a Unique
.
miri probably inserts a dereference to check for the UB. It's UB due to both the Rust reference stating that it's UB and the Box::from_raw function stating:
For this to be safe, the memory must have been allocated in accordance with the memory layout used by Box .
and
For non-zero-sized values, a Box will use the Global allocator for its allocation.
which is violated here.
The error message is not great. The UB clause that is being violated is
Producing an invalid value, even in private fields and locals.
and specifically
A reference or Box that is dangling, unaligned, or points to an invalid value.
Isn't there at least some mismatch in the Box documentation and the reference then? Because the reference lets you point the Box to random data that is valid but isn't allocated with the proper allocator, while the Box documentation says it needs to be allocated with the global allocator. Seems like miri doesn't detect this either. (Although I guess the Box documentation only says what's allowed, not what isn't)
Creating a Box
with the wrong allocator is unsound but not UB. The UB comes later, when/if the Box
is deallocated.
So it is considered an invalid value a dangling pointer for a Non-zero-sized Box
but does not trigger particularly dangerous UB unless it is used or deallocated.
An invalid value is UB. It is as much UB as dereferencing a NULL pointer. There is no "harmless UB". There are just programs with UB that currently, coincidentally, behave as expected, but that might change with any new Rust release or any seemingly unrelated change anywhere else in the program.
With "particularly dangerous" I mean OOM. I'm gonna be more clear the next time but this it is not relevant to the issue.
Closing in accordance with #57563 (comment).