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

What about: validity after/during drop #268

Closed
CAD97 opened this issue Dec 29, 2020 · 4 comments
Closed

What about: validity after/during drop #268

CAD97 opened this issue Dec 29, 2020 · 4 comments

Comments

@CAD97
Copy link

CAD97 commented Dec 29, 2020

e.g. Box<T> potentially has a validity requirement of being dereferencable. <Box<T> as Drop>::drop obviously breaks this requirement, and at the end of the function, the Box<T> still exists, but the pointer is now dangling.

That one is probably directly handled by #[may_dangle], so what about this minimal example:

struct Weird(NonZeroU8);

impl Drop for Weird {
    fn drop(&mut self) {
        unsafe { ptr::write(self as *mut Weird as *mut u8, 0u8) }; // <--- HERE
    }
}

fn main() {
    let w = Some(Weird(NonZeroU8::new(1).unwrap()));
    drop(w);
}

Does the indicated line invoke UB? When the allocated place is Weird? When the allocated place is Option<Weird> (#204 IIRC)?

@RustyYato
Copy link

e.g. Box potentially has a validity requirement of being dereferencable. <Box as Drop>::drop obviously breaks this requirement, and at the end of the function, the Box still exists, but the pointer is now dangling.

This looks like a dup of #245

That one is probably directly handled by #[may_dangle], so what about this minimal example:

I would say that does invoke UB, because you could have something like this:

struct Foo {
    weird: ManuallyDrop<Weird>,
    something_else: Box<u32>,
}

impl Drop for Foo {
    fn drop(&mut self) {
        unsafe { ManuallyDrop::drop(&mut self.weird); }
        println!("{}", self.something_else);
    }
}

fn main() {
    let foo = Some(Foo { ... });
    drop(foo);
}

Foo should always be safe, but by setting a NonZeroU8 to 0, it will convert the Option to None, this invalidating Foo.something_else! Since there is no way to know if Weird is going to be wrapped in an option-like enum, it is UB to write 0 to NonZeroU8. Now, this is different from Box, because even if Box dangles, it is still non-null, so none of these tricks can happen.

@RalfJung
Copy link
Member

and at the end of the function, the Box still exists, but the pointer is now dangling.

At least currently, the UB arises whenever any kind of "typed operation" is done on an invalid value. The compiler will prevent doing anything on the Box after it was dropped, so I think this is not a problem.

However, I also think that validity should be a bit-level property. So it's not validity that requires Box to be dereferencable. The dereferencability for Box and references arises from the aliasing model, which is mostly separate from validity.

@RalfJung
Copy link
Member

@CAD97 I think your second question is basically the same as #84, could you check?

@CAD97
Copy link
Author

CAD97 commented Feb 19, 2022

I think this was addressed enough to close. Though I've a different validity after drop issue I'm about to open, so that's the real motivation to closing this...

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