Skip to content

Stable, Miri-friendly way to get length of a boxed slice that is partially mutably borrowed #4317

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
golddranks opened this issue May 9, 2025 · 7 comments

Comments

@golddranks
Copy link

golddranks commented May 9, 2025

A follow-up from rust-lang/rust#129090 (comment)

I'm writing a custom memory allocator/object pool. I have a bunch of Box<[Thing]> chunks, where some of the Things are mutably borrowed as &mut Thing for a limited lifetime. During that lifetime, I need to access the slice len, but I don't need to touch its contents. I figured this would be okay to do, since the len is stored in the fat pointer, not in the slice itself. However naively doing chunk.len() or (&*chunk).len() triggers Miri UB warning. The problem seems to be that the dereference invalidates an earlier Unique tag within the slice. The offset 0x0..0x60 below corresponds to the whole memory span of the slice.

 <318767> was later invalidated at offsets [0x0..0x60] by a SharedReadOnly retag

I managed to get it to work with Box::as_ptr(&chunk).len() (there fortunately is a method <*const [T]>::len()), but this is not ideal as Box::as_ptr is still unstable. (&raw const *chunk).len() doesn't seem to work, as it retags the whole slice like chunk.len().

Are there any stable, Miri-friendly workarounds for getting the length, or more generally getting a pointer to a slice behind a box without retagging the contents of the slice?

@RalfJung
Copy link
Member

RalfJung commented May 9, 2025

Shouldn't https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.len work for this? It has been stable for a few releases.

@RalfJung
Copy link
Member

RalfJung commented May 9, 2025

(&raw const *chunk).len() doesn't seem to work, as it retags the whole slice like chunk.len().

Could you create a small self-contained example demonstrating this one not working?

@golddranks
Copy link
Author

Shouldn't https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.len work for this? It has been stable for a few releases.

Yes, this was the exact one I was referring to with "(there fortunately is a method <*const [T]>::len())". The problem is to get the pointer to begin with.

Thanks, I'll try creating a self-contained example.

@golddranks
Copy link
Author

@RalfJung
Copy link
Member

RalfJung commented May 9, 2025

Yeah that's the "SB raw pointer casts do retags which is bad" issue again. :/

For funny reasons, what would work in your particular case is (&raw mut *chunk).len() instead of &raw const...

@golddranks
Copy link
Author

Oh, apparently! So, because this thread was about finding a workaround, turns out that adding a helper that does conversion through a *mut pointer works for me:

struct Chunk(Box<[Thing]>);

impl Chunk {
    fn as_ptr(&self) -> *const [Thing] {
        // A workaround around current (as of Rust 1.86) Miri limitations:
        // converting the box to a pointer retags the contents of the slice
        // and causes an UB warning. Incidentally `&raw mut *boxed_slice` works
        // here even if `&raw const *boxed_slice` would be semantically more correct,
        // so we use a detour route & -> *const -> *mut -> deref -> *mut -> *const
        // as a workaround.
        //
        // See https://github.com/rust-lang/miri/issues/4317
        let chunk_ptr = &raw const *self as *mut Self;
        unsafe { &raw mut *(*chunk_ptr).0 }
    }
}

Thank you!

@RalfJung
Copy link
Member

RalfJung commented May 9, 2025

Okay, great. :) Let's close the issue then -- the underlying problem about cast-to-raw behaving weirdly in SB is already tracked elsewhere.

@RalfJung RalfJung closed this as completed May 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants