Skip to content

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

New issue

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

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

Already on GitHub? # 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. ;)

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants