Unsound arena implementation

I also think this is the problem. My understanding though, was that the borrow ended at the drop location, but I guess that's not really the case.

The solution is to store memory: *mut [u8] in Allocation instead. That way, you’re not imposing the constraints on use that come with a reference.

I'll give this a try.

From a lifetime perspective, the borrow does not end until 'a ends, and 'a does not end until the function returns. (All generic parameters of a function always outlive the function call.) From a perspective of LLVM-backed code generation, the same is true because noalias is a property of the function's parameter that applies to the whole function call. From a Stacked Borrows perspective, I’m not well informed, but I believe a “protector” plays the same role.

What these all have in common is that they are claims upon (the kinds of access to) that memory which start when a reference is passed to a function, and end when that function call ends.

1 Like

FYI the stdlib's std::cell::Ref used to have the same issue Ref parameter incorrectly decorated with `noalias` attribute · Issue #63787 · rust-lang/rust · GitHub

1 Like

I think that worked: Rust Playground

I feel a bit weird about the impls for Deref/AsRef, but I don't see how else to make it work.

Unsafely converting a raw pointer to a reference is a normal thing to do for any sort of smart pointer managing an allocation.

I would suggest that you reduce the duplication by having AsRef use Deref, though.

2 Likes

I see Ref uses NonNull<T> and adds T: ?Sized. It looks like I could maybe save the pointer as *const [T] instead of *const T, but I'm not sure how to do that. If I change ptr.cast::<T>() to ptr.cast::<[T]>() I get

error[E0277]: the size for values of type `[T]` cannot be known at compilation time
   --> src/lib.rs:165:24
    |
165 |             ptr.cast::<[T]>()
    |                 ----   ^^^ doesn't have a size known at compile-time
    |                 |
    |                 required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `[T]`
note: required by an implicit `Sized` bound in `std::ptr::mut_ptr::<impl *mut T>::cast`
   --> /home/andy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mut_ptr.rs:47:23
    |
47  |     pub const fn cast<U>(self) -> *mut U {
    |                       ^ required by the implicit `Sized` requirement on this type parameter in `std::ptr::mut_ptr::<impl *mut T>::cast`

To make a *const [T] you want std::ptr::slice_from_raw_parts().

Why are you using *const and & instead of *mut and &mut, though? An allocation is only useful if there’s an opportunity to write to it.

1 Like

Thanks! I'll take a look :slight_smile:

I have a separate AllocationMut wrapper which has &mut. I didn't include it to make the repro smaller.