Skip to content

Odd behaviour on self-referential types that use UnsafeCell #1665

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
Kestrer opened this issue Jan 8, 2021 · 3 comments
Closed

Odd behaviour on self-referential types that use UnsafeCell #1665

Kestrer opened this issue Jan 8, 2021 · 3 comments

Comments

@Kestrer
Copy link

Kestrer commented Jan 8, 2021

When running this code under Miri (playground link):

use std::cell::UnsafeCell;
use std::marker::PhantomPinned;
use std::pin::Pin;

pub struct SelfReferential {
    number: UnsafeCell<i32>,
    number_mut_ref: Option<*const UnsafeCell<i32>>,
    _pinned: PhantomPinned,
}
impl SelfReferential {
    pub fn new() -> Self {
        Self {
            number: UnsafeCell::new(0),
            number_mut_ref: None,
            _pinned: PhantomPinned,
        }
    }
    pub fn initialize(self: Pin<&mut Self>, number: i32) {
        let this = unsafe { self.get_unchecked_mut() };
        this.number = UnsafeCell::new(number);
        this.number_mut_ref = Some(&this.number);
    }
    pub fn add_one(self: Pin<&mut Self>) {
        let this = unsafe { self.get_unchecked_mut() };
        // If this line that is seemingly a no-op is commented, this code fails.
        unsafe { &*this.number.get() };
        let number_ptr = this.number_mut_ref.unwrap();
        *unsafe { &mut *(&*number_ptr).get() } += 1;
    }
}

fn main() {
    let v = SelfReferential::new();
    pin_utils::pin_mut!(v);
    v.as_mut().initialize(5);
    v.as_mut().add_one();
}

No errors are produced. However, if that line is commented, there is a violation of stacked borrows.

What is the intended behaviour here? And is this a valid way to implement safe self-referential types?

@RalfJung
Copy link
Member

RalfJung commented Jan 8, 2021

However, if that line is commented, there is a violation of stacked borrows.

This is likely a "raw pointer creation side-effect". If my guess is correct, running Miri with -Zmiri-track-raw-pointers will cause an error even with that line.

And is this a valid way to implement safe self-referential types?

Unfortunately not, see rust-lang/unsafe-code-guidelines#148.

Thanks for the report! However, I will close this as not-a-Miri-bug -- the issue is not in the UB checker, but in the definition of UB itself, so this is better tracked in the UCG repository.

@Kestrer
Copy link
Author

Kestrer commented Jan 8, 2021

Thank you for the fast response! It's a shame it doesn't work, but I can work around it. Self referential types are hard :(.

@RalfJung
Copy link
Member

RalfJung commented Jan 8, 2021

Yeah, it is annoying indeed. :/

The extreme work-around would be -Zmiri-disable-stacked-borrows. You're still getting all the other UB checking that way (and as a bonus, Miri will be twice as fast or more. ;)

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