#[may_dangle] types can only be dropped, not moved#496
#[may_dangle] types can only be dropped, not moved#496theemathas wants to merge 1 commit intorust-lang:masterfrom
#[may_dangle] types can only be dropped, not moved#496Conversation
Moving a `#[may_dangle]` type in `Drop::drop` asserts the validity of references stored in that type, which is unsound. For example, the following code is UB according to Miri:
```rust
#![feature(dropck_eyepatch)]
#![allow(unused)]
struct Thing<T>(Option<T>);
unsafe impl<#[may_dangle] T> Drop for Thing<T> {
fn drop(&mut self) {
let _ = self.0.take();
}
}
fn main() {
let thing;
{
let a = 1;
thing = Thing(Some(&a));
}
// thing is dropped here
}
```
| The attribute can be applied to any number of lifetime and type parameters. In | ||
| the following example, we assert that we access no data behind a reference of | ||
| lifetime `'b` and that the only uses of `T` will be moves or drops, but omit | ||
| lifetime `'b` and that the only uses of `T` will be drops, but omit |
There was a problem hiding this comment.
I don't think the change here is correct as described in RFC: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md#the-eyepatch-attribute
When used on a type, e.g. #[may_dangle] T, the programmer is asserting the only uses of values of that type will be to move or drop them. Thus, no fields will be accessed nor methods called on values of such a type (apart from any access performed by the destructor for the type when the values are dropped). This ensures that no dangling references (such as when T is instantiated with &'a u32) are ever accessed in the scenario where 'a has the same lifetime as the value being currently destroyed (and thus the precise order of destruction between the two is unknown to the compiler).
In your example, the moved value will be dropped by Options::take, not us, while we have to take responsibility of drop here instead. When we use something like ManualDrop, it would be sound.
There was a problem hiding this comment.
I'm not sure what you mean. Miri still detects UB in this code:
#![feature(dropck_eyepatch)]
#![allow(unused)]
struct Thing<T>(Option<T>);
unsafe impl<#[may_dangle] T> Drop for Thing<T> {
fn drop(&mut self) {
std::mem::forget(self.0.take());
}
}
fn main() {
let thing;
{
let a = 1;
thing = Thing(Some(&a));
}
// thing is dropped here
}There was a problem hiding this comment.
It's unsound because drop is occured while we have to ensure moved value will not be used (i.e. dropped by destructor). Just move something is still sound.
There was a problem hiding this comment.
I don't understand which Drop you're talking about. Could you write code that demonstrates this?
Moving a
#[may_dangle]type inDrop::dropasserts the validity of references stored in that type, which is unsound. For example, the following code is UB according to Miri: