|
132 | 132 | /// are `Copy` get implicitly duplicated by the compiler, making it very
|
133 | 133 | /// hard to predict when, and how often destructors will be executed. As such,
|
134 | 134 | /// these types cannot have destructors.
|
| 135 | +/// |
| 136 | +/// ## Drop check |
| 137 | +/// |
| 138 | +/// Dropping interacts with the borrow checker in subtle ways: when a type `T` is being implicitly |
| 139 | +/// dropped as some variable of this type goes out of scope, the borrow checker needs to ensure that |
| 140 | +/// calling `T`'s destructor at this moment is safe. In particular, it also needs to be safe to |
| 141 | +/// recursively drop all the fields of `T`. For example, it is crucial that code like the following |
| 142 | +/// is being rejected: |
| 143 | +/// |
| 144 | +/// ```compile_fail,E0597 |
| 145 | +/// use std::cell::Cell; |
| 146 | +/// |
| 147 | +/// struct S<'a>(Cell<Option<&'a S<'a>>>, Box<i32>); |
| 148 | +/// impl Drop for S<'_> { |
| 149 | +/// fn drop(&mut self) { |
| 150 | +/// if let Some(r) = self.0.get() { |
| 151 | +/// // Print the contents of the `Box` in `r`. |
| 152 | +/// println!("{}", r.1); |
| 153 | +/// } |
| 154 | +/// } |
| 155 | +/// } |
| 156 | +/// |
| 157 | +/// fn main() { |
| 158 | +/// // Set up two `S` that point to each other. |
| 159 | +/// let s1 = S(Cell::new(None), Box::new(42)); |
| 160 | +/// let s2 = S(Cell::new(Some(&s1)), Box::new(42)); |
| 161 | +/// s1.0.set(Some(&s2)); |
| 162 | +/// // Now they both get dropped. But whichever is the 2nd one |
| 163 | +/// // to be dropped will access the `Box` in the first one, |
| 164 | +/// // which is a use-after-free! |
| 165 | +/// } |
| 166 | +/// ``` |
| 167 | +/// |
| 168 | +/// The Nomicon discusses the need for [drop check in more detail][drop check]. |
| 169 | +/// |
| 170 | +/// To reject such code, the "drop check" analysis determines which types and lifetimes need to |
| 171 | +/// still be live when `T` gets dropped. The exact details of this analysis are not yet |
| 172 | +/// stably guaranteed and **subject to change**. Currently, the analysis works as follows: |
| 173 | +/// - If `T` has no drop glue, then trivially nothing is required to be live. This is the case if |
| 174 | +/// neither `T` nor any of its (recursive) fields have a destructor (`impl Drop`). [`PhantomData`] |
| 175 | +/// and [`ManuallyDrop`] are considered to never have a destructor, no matter their field type. |
| 176 | +/// - If `T` has drop glue, then, for all types `U` that are *owned* by any field of `T`, |
| 177 | +/// recursively add the types and lifetimes that need to be live when `U` gets dropped. The set of |
| 178 | +/// owned types is determined by recursively traversing `T`: |
| 179 | +/// - Recursively descend through `PhantomData`, `Box`, tuples, and arrays (including arrays of |
| 180 | +/// length 0). |
| 181 | +/// - Stop at reference and raw pointer types as well as function pointers and function items; |
| 182 | +/// they do not own anything. |
| 183 | +/// - Stop at non-composite types (type parameters that remain generic in the current context and |
| 184 | +/// base types such as integers and `bool`); these types are owned. |
| 185 | +/// - When hitting an ADT with `impl Drop`, stop there; this type is owned. |
| 186 | +/// - When hitting an ADT without `impl Drop`, recursively descend to its fields. (For an `enum`, |
| 187 | +/// consider all fields of all variants.) |
| 188 | +/// - Furthermore, if `T` implements `Drop`, then all generic (lifetime and type) parameters of `T` |
| 189 | +/// must be live. |
| 190 | +/// |
| 191 | +/// In the above example, the last clause implies that `'a` must be live when `S<'a>` is dropped, |
| 192 | +/// and hence the example is rejected. If we remove the `impl Drop`, the liveness requirement |
| 193 | +/// disappears and the example is accepted. |
| 194 | +/// |
| 195 | +/// There exists an unstable way for a type to opt-out of the last clause; this is called "drop |
| 196 | +/// check eyepatch" or `may_dangle`. For more details on this nightly-only feature, see the |
| 197 | +/// [discussion in the Nomicon][nomicon]. |
| 198 | +/// |
| 199 | +/// [`ManuallyDrop`]: crate::mem::ManuallyDrop |
| 200 | +/// [`PhantomData`]: crate::marker::PhantomData |
| 201 | +/// [drop check]: ../../nomicon/dropck.html |
| 202 | +/// [nomicon]: ../../nomicon/phantom-data.html#an-exception-the-special-case-of-the-standard-library-and-its-unstable-may_dangle |
135 | 203 | #[lang = "drop"]
|
136 | 204 | #[stable(feature = "rust1", since = "1.0.0")]
|
137 | 205 | #[const_trait]
|
|
0 commit comments