Document subtleties of ManuallyDrop
· qinheping/verify-rust-std@6695a56 (original) (raw)
1
1
`use crate::ops::{Deref, DerefMut, DerefPure};
`
2
2
`use crate::ptr;
`
3
3
``
4
``
`` -
/// A wrapper to inhibit the compiler from automatically calling T
’s destructor.
``
5
``
`-
/// This wrapper is 0-cost.
`
``
4
`` +
/// A wrapper to inhibit the compiler from automatically calling T
’s
``
``
5
`+
/// destructor. This wrapper is 0-cost.
`
6
6
`///
`
7
7
`` /// ManuallyDrop<T>
is guaranteed to have the same layout and bit validity as
``
8
``
`` -
/// T
, and is subject to the same layout optimizations as T
. As a consequence,
``
9
``
`-
/// it has no effect on the assumptions that the compiler makes about its
`
10
``
`` -
/// contents. For example, initializing a ManuallyDrop<&mut T>
with [mem::zeroed
]
``
11
``
`-
/// is undefined behavior. If you need to handle uninitialized data, use
`
12
``
`` -
/// [MaybeUninit<T>
] instead.
``
``
8
`` +
/// T
, and is subject to the same layout optimizations as T
. As a
``
``
9
`+
/// consequence, it has no effect on the assumptions that the compiler makes
`
``
10
`` +
/// about its contents. For example, initializing a ManuallyDrop<&mut T>
with
``
``
11
`` +
/// [mem::zeroed
] is undefined behavior. If you need to handle uninitialized
``
``
12
`` +
/// data, use [MaybeUninit<T>
] instead.
``
13
13
`///
`
14
``
`` -
/// Note that accessing the value inside a ManuallyDrop<T>
is safe.
``
15
``
`` -
/// This means that a ManuallyDrop<T>
whose content has been dropped must not
``
16
``
`-
/// be exposed through a public safe API.
`
17
``
`` -
/// Correspondingly, ManuallyDrop::drop
is unsafe.
``
``
14
`` +
/// Note that accessing the value inside a ManuallyDrop<T>
is safe. This means
``
``
15
`` +
/// that a ManuallyDrop<T>
whose content has been dropped must not be exposed
``
``
16
`` +
/// through a public safe API. Correspondingly, ManuallyDrop::drop
is unsafe.
``
18
17
`///
`
19
18
`` /// # ManuallyDrop
and drop order.
``
20
19
`///
`
`@@ -40,9 +39,114 @@ use crate::ptr;
`
40
39
`/// }
`
41
40
```` /// ```
`42`
`41`
`///
`
``
`42`
`` +
/// # Interaction with `Box`.
``
``
`43`
`+
///
`
``
`44`
`` +
/// Currently, once the `Box<T>` inside a `ManuallyDrop<Box<T>>` is dropped,
``
``
`45`
`` +
/// moving the `ManuallyDrop<Box<T>>` is [considered to be undefined
``
``
`46`
`+
/// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245).
`
``
`47`
`+
/// That is, the following code causes undefined behavior:
`
``
`48`
`+
///
`
``
`49`
```` +
/// ```no_run
``
50
`+
/// use std::mem::ManuallyDrop;
`
``
51
`+
///
`
``
52
`+
/// let mut x = ManuallyDrop::new(Box::new(42));
`
``
53
`+
/// unsafe {
`
``
54
`+
/// ManuallyDrop::drop(&mut x);
`
``
55
`+
/// }
`
``
56
`+
/// let y = x; // Undefined behavior!
`
``
57
/// ```
``
58
`+
///
`
``
59
`+
/// This may change in the future. In the meantime, consider using
`
``
60
`` +
/// [MaybeUninit
] instead.
``
``
61
`+
///
`
``
62
`` +
/// # Safety hazards when storing ManuallyDrop
in a struct / enum.
``
``
63
`+
///
`
``
64
`+
/// Special care is needed when all of the conditions below are met:
`
``
65
`` +
/// * A field of a struct or enum is a ManuallyDrop
or contains a
``
``
66
`` +
/// ManuallyDrop
, without the ManuallyDrop
being inside a union
.
``
``
67
`+
/// * The struct or enum is part of public API, or is stored in a struct or enum
`
``
68
`+
/// that is part of public API.
`
``
69
`` +
/// * There is code outside of a Drop
implementation that calls
``
``
70
`` +
/// [ManuallyDrop::drop
] or [ManuallyDrop::take
] on the ManuallyDrop
``
``
71
`+
/// field.
`
``
72
`+
///
`
``
73
`+
/// In particular, the following hazards can occur:
`
``
74
`+
///
`
``
75
`+
/// #### Storing generic types
`
``
76
`+
///
`
``
77
`` +
/// If the ManuallyDrop
contains a client-supplied generic type, the client
``
``
78
`` +
/// might provide a Box
, causing undefined behavior when the struct / enum is
``
``
79
`+
/// later moved, as mentioned above. For example, the following code causes
`
``
80
`+
/// undefined behavior:
`
``
81
`+
///
`
``
82
/// ```no_run
``
83
`+
/// use std::mem::ManuallyDrop;
`
``
84
`+
///
`
``
85
`+
/// pub struct BadOption {
`
``
86
`` +
/// // Invariant: Has been dropped iff is_some
is false.
``
``
87
`+
/// value: ManuallyDrop,
`
``
88
`+
/// is_some: bool,
`
``
89
`+
/// }
`
``
90
`+
/// impl BadOption {
`
``
91
`+
/// pub fn new(value: T) -> Self {
`
``
92
`+
/// Self { value: ManuallyDrop::new(value), is_some: true }
`
``
93
`+
/// }
`
``
94
`+
/// pub fn change_to_none(&mut self) {
`
``
95
`+
/// if self.is_some {
`
``
96
`+
/// self.is_some = false;
`
``
97
`+
/// unsafe {
`
``
98
`` +
/// // SAFETY: value
hasn't been dropped yet, as per the invariant
``
``
99
`+
/// // (This is actually unsound!)
`
``
100
`+
/// ManuallyDrop::drop(&mut self.value);
`
``
101
`+
/// }
`
``
102
`+
/// }
`
``
103
`+
/// }
`
``
104
`+
/// }
`
``
105
`+
///
`
``
106
`+
/// // In another crate:
`
``
107
`+
///
`
``
108
`+
/// let mut option = BadOption::new(Box::new(42));
`
``
109
`+
/// option.change_to_none();
`
``
110
`+
/// let option2 = option; // Undefined behavior!
`
``
111
/// ```
``
112
`+
///
`
``
113
`+
/// #### Deriving traits
`
``
114
`+
///
`
``
115
`` +
/// Deriving Debug
, Clone
, PartialEq
, PartialOrd
, Ord
, or Hash
on
``
``
116
`+
/// the struct / enum could be unsound, since the derived implementations of
`
``
117
`` +
/// these traits would access the ManuallyDrop
field. For example, the
``
``
118
`+
/// following code causes undefined behavior:
`
``
119
`+
///
`
``
120
/// ```no_run
``
121
`+
/// use std::mem::ManuallyDrop;
`
``
122
`+
///
`
``
123
`+
/// #[derive(Debug)] // This is unsound!
`
``
124
`+
/// pub struct Foo {
`
``
125
`+
/// value: ManuallyDrop,
`
``
126
`+
/// }
`
``
127
`+
/// impl Foo {
`
``
128
`+
/// pub fn new() -> Self {
`
``
129
`+
/// let mut temp = Self {
`
``
130
`+
/// value: ManuallyDrop::new(String::from("Unsafe rust is hard"))
`
``
131
`+
/// };
`
``
132
`+
/// unsafe {
`
``
133
`` +
/// // SAFETY: value
hasn't been dropped yet.
``
``
134
`+
/// ManuallyDrop::drop(&mut temp.value);
`
``
135
`+
/// }
`
``
136
`+
/// temp
`
``
137
`+
/// }
`
``
138
`+
/// }
`
``
139
`+
///
`
``
140
`+
/// // In another crate:
`
``
141
`+
///
`
``
142
`+
/// let foo = Foo::new();
`
``
143
`+
/// println!("{:?}", foo); // Undefined behavior!
`
``
144
/// ```
``
145
`+
///
`
43
146
`/// [drop order]: https://doc.rust-lang.org/reference/destructors.html
`
44
147
`` /// [mem::zeroed
]: crate::mem::zeroed
``
45
148
`` /// [MaybeUninit<T>
]: crate::mem::MaybeUninit
``
``
149
`` +
/// [MaybeUninit
]: crate::mem::MaybeUninit
``
46
150
`#[stable(feature = "manually_drop", since = "1.20.0")]
`
47
151
`#[lang = "manually_drop"]
`
48
152
`#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
`