Skip to content
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

Does UnsafeCell::raw_get preserve pointer provenance? #474

Closed
Kolsky opened this issue Nov 8, 2023 · 3 comments
Closed

Does UnsafeCell::raw_get preserve pointer provenance? #474

Kolsky opened this issue Nov 8, 2023 · 3 comments

Comments

@Kolsky
Copy link

Kolsky commented Nov 8, 2023

This code passes Miri as of now (playground):

use core::cell::UnsafeCell;
use core::ptr;

fn as_raw_mut_slice<T>(slice_of_ucells: &[UnsafeCell<T>]) -> *mut [T] {
    let len = slice_of_ucells.len();
    let data = UnsafeCell::raw_get(slice_of_ucells.as_ptr());
    ptr::slice_from_raw_parts_mut(data, len)
}

fn main() {
    let array = [1, -1, 3, -1, 5].map(UnsafeCell::new);
    let slice = unsafe { &mut *as_raw_mut_slice(&array[..4]) };
    slice[1] = 2;
    dbg!(unsafe { &*array[4].get() });
    slice[3] = 4;
    dbg!(array.map(UnsafeCell::into_inner));
}

Does it mean that raw_get will get to preserve provenance of a pointer going into the future, when Rust will have its own memory model specification?
Afaik Box::leak had the provenance shrinking issue, although it doesn't seem to be the case that pointers ever shrank provenance on their own in any other parts of the language, as long as no intermediate references are created.

@RalfJung
Copy link
Member

RalfJung commented Nov 10, 2023

Dumping a bunch of unsafe and raw ptr manipulating code without any comments for what to look at isn't very helpful, I am afraid. Please don't make me reverse engineer your intent from the code.

Regarding the questions below the code:

raw_get works on raw pointers so the idea with Miri's memory models is that it will indeed exactly preserve provenance. However we reserve the right to have something more strict in the future where if you do not go through raw_get, you are not allowed to perform mutation of the cell's contents.

Afaik Box::leak had the provenance shrinking issue

Do you mean #256? Box<T> is already only having provenance for T under Stacked Borrows through, so leak isn't really shrinking anything here.

@Kolsky
Copy link
Author

Kolsky commented Nov 10, 2023

Dumping a bunch of unsafe and raw ptr manipulating code without any comments for what to look at isn't very helpful, I am afraid. Please don't make me reverse engineer your intent from the code.

Yes, sorry for that. I'll try to clarify what I'm trying to do the next time.
Indeed what I'm trying to do here is to carry SharedReadWrite/Reserved (for interior mutability) rights over the entire raw slice. The question was then whether raw_get guarantees that it goes through contents of entire slice with just a start pointer, albeit the one that's able to access the entire allocation of a given slice. I believe you've answered it here

raw_get works on raw pointers so the idea with Miri's memory models is that it will indeed exactly preserve provenance.

Thanks. I hope I didn't get the wrong idea.

Do you mean # 256?

Yes. It's interesting to learn that Box<T> itself has this problem, but, in hindsight, it should've been obvious. It was mentioned in case it could've been considered a precedent for unexpected provenance shrinking in the language.

Edit: the shortened example would look like this:

fn write_at<T>(slice: &[UnsafeCell<T>], index: usize, value: T) {
    assert!(index < slice.len(), "index out of bounds"); // ensure we're able to access slice at `index`
    let start = UnsafeCell::raw_get(slice.as_ptr()); // supposedly the normal start pointer that allows both reads and writes for start.add(index)
    unsafe { *start.add(index) = value }; // is this sound or ub
}

@RalfJung
Copy link
Member

The question was then whether raw_get guarantees that it goes through contents of entire slice with just a start pointer, albeit the one that's able to access the entire allocation of a given slice. I believe you've answered it here

UnsafeCell::raw_get does not do any "narrowing" of provenance to the type -- the entire memory range of the original provenance is preserved. That much I think we can guarantee, that's pretty much why the method exists.

Conceptually, what it does is equip the pointer with the permission to mutate -- you have to go through UnsafeCell::get/get_mut for that. That's not how it is actually implemented in Miri, but at least for now that's the model for the API that is exposed by UnsafeCell.

@Kolsky Kolsky closed this as completed Nov 10, 2023
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