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

Is "validity on typed copy" enough? #189

Closed
RalfJung opened this issue Aug 2, 2019 · 3 comments
Closed

Is "validity on typed copy" enough? #189

RalfJung opened this issue Aug 2, 2019 · 3 comments

Comments

@RalfJung
Copy link
Member

RalfJung commented Aug 2, 2019

With #175, I am basically proposing to make the "validity invariant" arise from the bytelist -> value -> bytelist conversion that (in my view) happens any time a "typed cooy" is performed (in particular every time the assignment operator is executed). This also exactly matches when Miri currently checks validity.

It is conceivable, however, to be even more aggressive about this. Consider:

use std::num::NonZeroU32;

fn main() {
    let mut x = Some(NonZeroU32::new(1).unwrap());
    let xref = match x {
        Some(ref mut c) => c as *mut NonZeroU32 as *mut u32,
        None => panic!(),
    };
    unsafe { *xref = 0 }; // writing 0 into a `*mut u32`
    println!("{:?}", x);
}

Is this code UB? On the one hand, the last line stores a 0 into what could be thought of as a pointer to a NonZeroU32. On the other hand, if we look at this locally / operationally, all we are doing is writing a 0 to a *mut u32. We never "look" at that 0 at type NonZeroU32. Miri sees no UB here.
(NonZeroU32 is just an example; this can happen with basically any type that has a niche.)

This code certainly makes some layout assumptions, like Option<NonZeroU32> being basically the same as u32, but that is something we already or almost guarantee. And certainly the following code is fine; FFI code does something like this all the time when using Option<&T> on the interface:

fn main() {
    let mut x = Some(NonZeroU32::new(1).unwrap());
    let xref = &mut x as *mut _ as *mut u32;
    unsafe { *xref = 0 };
    println!("{:?}", x);
}

So, is there anything wrong with the first code? Do we want that (or some variant thereof) to be UB? Is there an optimization that could gain us?

(I thought we already had an issue about this somewhere, and I recall discussing this with @rkruppe, but I cannot find an issue so maybe it was just in chat.)

@hanna-kruppe
Copy link

@hanna-kruppe
Copy link

This code certainly makes some layout assumptions, like Option being basically the same as u32, but that is something we already or almost guarantee. And certainly the following code is fine; FFI code does something like this all the time when using Option<&T> on the interface:

In any case this is a new angle to me and a very convincing one.

@RalfJung
Copy link
Member Author

RalfJung commented Aug 2, 2019

Yes, that's the one! Thanks.

I will add this new angle there.

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