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 writing through a raw pointer with an assignment assert validity for Copy types? #317

Closed
nico-abram opened this issue Jan 30, 2022 · 6 comments

Comments

@nico-abram
Copy link

Basically, is this UB?

use core::mem::MaybeUninit;

fn main() {
    let mut x = MaybeUninit::<&'static u8>::uninit();
    let xp = x.as_mut_ptr();
    unsafe {
        *xp = &0;
    }
}

MIRI accepts it, but it also accepts this other one which I think is UB

use core::mem::MaybeUninit;

fn main() {
    let mut x = MaybeUninit::<&'static u8>::uninit();
    unsafe {
        let xp = &mut*x.as_mut_ptr();
        *xp = &0;
    }
}
@RalfJung
Copy link
Member

I am confused by the examples, could you explain their point?

Potentially related: #84

@digama0
Copy link

digama0 commented Jan 30, 2022

Why would either of them be UB? The only thing I can think is that writing to *xp causes the old value of *xp to be dropped, which is not okay since it's an uninitialized value. But it is okay because &'static u8 has no Drop and the core language knows this.

@nico-abram
Copy link
Author

nico-abram commented Jan 30, 2022

I am confused by the examples, could you explain their point?

Potentially related: #84

Before asking something in zulip (https://rust-lang.zulipchat.com/#narrow/stream/136281-t-lang.2Fwg-unsafe-code-guidelines/topic/Question.20about.20addr_of!.20and.20nested.20derefs) I asked in the community discord server's #dark-arts, where someone mentioned that a snippet like the following that tries to partially initialize a MaybeUninit struct

        struct Y { data: u8, _r: &'static u8 }
        let mut y: MaybeUninit<Y> = MaybeUninit::uninit();
        let y_ptr = &mut y as *mut _ as *mut Y;
        (*y_ptr).data = 1u8;

Was wrong because (*y_ptr).data = 1u8; asserts the validity of .data when writing, and it is uninit, so ptr::write should be used instead, even for Copy types.

The motivation is knowing if using raw pointer dereferences to uninitialized data on the left side of an assignment is incorrect, specifically for Copy types (With or without niches). So dereferencing a *mut T that points to an uninit MaybeUninit<T> on the left of an assignment.

The MaybeUninit::<&'static u8> example was just to try to make the question clear, since it involves a Copy type with niches

@nico-abram nico-abram changed the title Does writing through a raw pointer assert validity for Copy types? Does writing through a raw pointer with an assignment assert validity for Copy types? Jan 30, 2022
@nico-abram
Copy link
Author

Why would either of them be UB? The only thing I can think is that writing to *xp causes the old value of *xp to be dropped, which is not okay since it's an uninitialized value. But it is okay because &'static u8 has no Drop and the core language knows this.

Yes, this was my understanding. It's only UB if it is Drop. But someone told me it still asserted validity for Copy types which is why I'm asking.

Isn't the second example UB because it is making a &mut T to an uninit T? And in this case T has a niche, so it is not valid for all bit patterns. I believe this is discussed in #77 . Quoting this December 2021 comment rust-lang/miri#1240 (comment)

The Reference currently says they are UB, to keep our options open. Discussion happens at #71 and #77. My personal preference is that it should not be UB: integers must be initialized, but references do not recursively require anything about the memory they point to. This is also what Miri implements.

@RalfJung
Copy link
Member

RalfJung commented Jan 30, 2022

Oh you are asking if the old data that is being overwritten has to be valid? That wasn't clear at all from your question. :)

No it does not. Copy makes no difference.

@nico-abram
Copy link
Author

Yes, I meant the old data.

Thanks for the answer
Incidentally, I just saw a blog post published today that seems to have had a similar misunderstanding (Which has since been edited) clarified in this reddit comment by eddyb https://www.reddit.com/r/rust/comments/sg6pp5/uninitialized_memory_unsafe_rust_is_too_hard/huvpj28/?utm_source=reddit&utm_medium=web2x&context=3 that thought writing to a place via assignment implicitly made a &mut

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

3 participants