]> git.proxmox.com Git - rustc.git/blob - src/doc/nomicon/src/dropck.md
New upstream version 1.49.0~beta.4+dfsg1
[rustc.git] / src / doc / nomicon / src / dropck.md
1 # Drop Check
2
3 We have seen how lifetimes provide us some fairly simple rules for ensuring
4 that we never read dangling references. However up to this point we have only ever
5 interacted with the _outlives_ relationship in an inclusive manner. That is,
6 when we talked about `'a: 'b`, it was ok for `'a` to live _exactly_ as long as
7 `'b`. At first glance, this seems to be a meaningless distinction. Nothing ever
8 gets dropped at the same time as another, right? This is why we used the
9 following desugaring of `let` statements:
10
11 ```rust,ignore
12 let x;
13 let y;
14 ```
15
16 ```rust,ignore
17 {
18 let x;
19 {
20 let y;
21 }
22 }
23 ```
24
25 There are some more complex situations which are not possible to desugar using
26 scopes, but the order is still defined ‒ variables are dropped in the reverse
27 order of their definition, fields of structs and tuples in order of their
28 definition. There are some more details about order of drop in [RFC 1857][rfc1857].
29
30 Let's do this:
31
32 ```rust,ignore
33 let tuple = (vec![], vec![]);
34 ```
35
36 The left vector is dropped first. But does it mean the right one strictly
37 outlives it in the eyes of the borrow checker? The answer to this question is
38 _no_. The borrow checker could track fields of tuples separately, but it would
39 still be unable to decide what outlives what in case of vector elements, which
40 are dropped manually via pure-library code the borrow checker doesn't
41 understand.
42
43 So why do we care? We care because if the type system isn't careful, it could
44 accidentally make dangling pointers. Consider the following simple program:
45
46 ```rust
47 struct Inspector<'a>(&'a u8);
48
49 struct World<'a> {
50 inspector: Option<Inspector<'a>>,
51 days: Box<u8>,
52 }
53
54 fn main() {
55 let mut world = World {
56 inspector: None,
57 days: Box::new(1),
58 };
59 world.inspector = Some(Inspector(&world.days));
60 }
61 ```
62
63 This program is totally sound and compiles today. The fact that `days` does not
64 strictly outlive `inspector` doesn't matter. As long as the `inspector` is
65 alive, so is `days`.
66
67 However if we add a destructor, the program will no longer compile!
68
69 ```rust,compile_fail
70 struct Inspector<'a>(&'a u8);
71
72 impl<'a> Drop for Inspector<'a> {
73 fn drop(&mut self) {
74 println!("I was only {} days from retirement!", self.0);
75 }
76 }
77
78 struct World<'a> {
79 inspector: Option<Inspector<'a>>,
80 days: Box<u8>,
81 }
82
83 fn main() {
84 let mut world = World {
85 inspector: None,
86 days: Box::new(1),
87 };
88 world.inspector = Some(Inspector(&world.days));
89 // Let's say `days` happens to get dropped first.
90 // Then when Inspector is dropped, it will try to read free'd memory!
91 }
92 ```
93
94 ```text
95 error[E0597]: `world.days` does not live long enough
96 --> src/main.rs:19:38
97 |
98 19 | world.inspector = Some(Inspector(&world.days));
99 | ^^^^^^^^^^^ borrowed value does not live long enough
100 ...
101 22 | }
102 | -
103 | |
104 | `world.days` dropped here while still borrowed
105 | borrow might be used here, when `world` is dropped and runs the destructor for type `World<'_>`
106 ```
107
108 You can try changing the order of fields or use a tuple instead of the struct,
109 it'll still not compile.
110
111 Implementing `Drop` lets the `Inspector` execute some arbitrary code during its
112 death. This means it can potentially observe that types that are supposed to
113 live as long as it does actually were destroyed first.
114
115 Interestingly, only generic types need to worry about this. If they aren't
116 generic, then the only lifetimes they can harbor are `'static`, which will truly
117 live _forever_. This is why this problem is referred to as _sound generic drop_.
118 Sound generic drop is enforced by the _drop checker_. As of this writing, some
119 of the finer details of how the drop checker validates types is totally up in
120 the air. However The Big Rule is the subtlety that we have focused on this whole
121 section:
122
123 **For a generic type to soundly implement drop, its generics arguments must
124 strictly outlive it.**
125
126 Obeying this rule is (usually) necessary to satisfy the borrow
127 checker; obeying it is sufficient but not necessary to be
128 sound. That is, if your type obeys this rule then it's definitely
129 sound to drop.
130
131 The reason that it is not always necessary to satisfy the above rule
132 is that some Drop implementations will not access borrowed data even
133 though their type gives them the capability for such access, or because we know
134 the specific drop order and the borrowed data is still fine even if the borrow
135 checker doesn't know that.
136
137 For example, this variant of the above `Inspector` example will never
138 access borrowed data:
139
140 ```rust,compile_fail
141 struct Inspector<'a>(&'a u8, &'static str);
142
143 impl<'a> Drop for Inspector<'a> {
144 fn drop(&mut self) {
145 println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
146 }
147 }
148
149 struct World<'a> {
150 inspector: Option<Inspector<'a>>,
151 days: Box<u8>,
152 }
153
154 fn main() {
155 let mut world = World {
156 inspector: None,
157 days: Box::new(1),
158 };
159 world.inspector = Some(Inspector(&world.days, "gadget"));
160 // Let's say `days` happens to get dropped first.
161 // Even when Inspector is dropped, its destructor will not access the
162 // borrowed `days`.
163 }
164 ```
165
166 Likewise, this variant will also never access borrowed data:
167
168 ```rust,compile_fail
169 struct Inspector<T>(T, &'static str);
170
171 impl<T> Drop for Inspector<T> {
172 fn drop(&mut self) {
173 println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
174 }
175 }
176
177 struct World<T> {
178 inspector: Option<Inspector<T>>,
179 days: Box<u8>,
180 }
181
182 fn main() {
183 let mut world = World {
184 inspector: None,
185 days: Box::new(1),
186 };
187 world.inspector = Some(Inspector(&world.days, "gadget"));
188 // Let's say `days` happens to get dropped first.
189 // Even when Inspector is dropped, its destructor will not access the
190 // borrowed `days`.
191 }
192 ```
193
194 However, _both_ of the above variants are rejected by the borrow
195 checker during the analysis of `fn main`, saying that `days` does not
196 live long enough.
197
198 The reason is that the borrow checking analysis of `main` does not
199 know about the internals of each `Inspector`'s `Drop` implementation. As
200 far as the borrow checker knows while it is analyzing `main`, the body
201 of an inspector's destructor might access that borrowed data.
202
203 Therefore, the drop checker forces all borrowed data in a value to
204 strictly outlive that value.
205
206 # An Escape Hatch
207
208 The precise rules that govern drop checking may be less restrictive in
209 the future.
210
211 The current analysis is deliberately conservative and trivial; it forces all
212 borrowed data in a value to outlive that value, which is certainly sound.
213
214 Future versions of the language may make the analysis more precise, to
215 reduce the number of cases where sound code is rejected as unsafe.
216 This would help address cases such as the two `Inspector`s above that
217 know not to inspect during destruction.
218
219 In the meantime, there is an unstable attribute that one can use to
220 assert (unsafely) that a generic type's destructor is _guaranteed_ to
221 not access any expired data, even if its type gives it the capability
222 to do so.
223
224 That attribute is called `may_dangle` and was introduced in [RFC 1327][rfc1327].
225 To deploy it on the `Inspector` from above, we would write:
226
227 ```rust
228 #![feature(dropck_eyepatch)]
229
230 struct Inspector<'a>(&'a u8, &'static str);
231
232 unsafe impl<#[may_dangle] 'a> Drop for Inspector<'a> {
233 fn drop(&mut self) {
234 println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
235 }
236 }
237
238 struct World<'a> {
239 days: Box<u8>,
240 inspector: Option<Inspector<'a>>,
241 }
242
243 fn main() {
244 let mut world = World {
245 inspector: None,
246 days: Box::new(1),
247 };
248 world.inspector = Some(Inspector(&world.days, "gatget"));
249 }
250 ```
251
252 Use of this attribute requires the `Drop` impl to be marked `unsafe` because the
253 compiler is not checking the implicit assertion that no potentially expired data
254 (e.g. `self.0` above) is accessed.
255
256 The attribute can be applied to any number of lifetime and type parameters. In
257 the following example, we assert that we access no data behind a reference of
258 lifetime `'b` and that the only uses of `T` will be moves or drops, but omit
259 the attribute from `'a` and `U`, because we do access data with that lifetime
260 and that type:
261
262 ```rust,ignore
263 use std::fmt::Display;
264
265 struct Inspector<'a, 'b, T, U: Display>(&'a u8, &'b u8, T, U);
266
267 unsafe impl<'a, #[may_dangle] 'b, #[may_dangle] T, U: Display> Drop for Inspector<'a, 'b, T, U> {
268 fn drop(&mut self) {
269 println!("Inspector({}, _, _, {})", self.0, self.3);
270 }
271 }
272 ```
273
274 It is sometimes obvious that no such access can occur, like the case above.
275 However, when dealing with a generic type parameter, such access can
276 occur indirectly. Examples of such indirect access are:
277
278 - invoking a callback,
279 - via a trait method call.
280
281 (Future changes to the language, such as impl specialization, may add
282 other avenues for such indirect access.)
283
284 Here is an example of invoking a callback:
285
286 ```rust,ignore
287 struct Inspector<T>(T, &'static str, Box<for <'r> fn(&'r T) -> String>);
288
289 impl<T> Drop for Inspector<T> {
290 fn drop(&mut self) {
291 // The `self.2` call could access a borrow e.g. if `T` is `&'a _`.
292 println!("Inspector({}, {}) unwittingly inspects expired data.",
293 (self.2)(&self.0), self.1);
294 }
295 }
296 ```
297
298 Here is an example of a trait method call:
299
300 ```rust,ignore
301 use std::fmt;
302
303 struct Inspector<T: fmt::Display>(T, &'static str);
304
305 impl<T: fmt::Display> Drop for Inspector<T> {
306 fn drop(&mut self) {
307 // There is a hidden call to `<T as Display>::fmt` below, which
308 // could access a borrow e.g. if `T` is `&'a _`
309 println!("Inspector({}, {}) unwittingly inspects expired data.",
310 self.0, self.1);
311 }
312 }
313 ```
314
315 And of course, all of these accesses could be further hidden within
316 some other method invoked by the destructor, rather than being written
317 directly within it.
318
319 In all of the above cases where the `&'a u8` is accessed in the
320 destructor, adding the `#[may_dangle]`
321 attribute makes the type vulnerable to misuse that the borrower
322 checker will not catch, inviting havoc. It is better to avoid adding
323 the attribute.
324
325 # A related side note about drop order
326
327 While the drop order of fields inside a struct is defined, relying on it is
328 fragile and subtle. When the order matters, it is better to use the
329 [`ManuallyDrop`] wrapper.
330
331 # Is that all about drop checker?
332
333 It turns out that when writing unsafe code, we generally don't need to
334 worry at all about doing the right thing for the drop checker. However there
335 is one special case that you need to worry about, which we will look at in
336 the next section.
337
338 [rfc1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md
339 [rfc1857]: https://github.com/rust-lang/rfcs/blob/master/text/1857-stabilize-drop-order.md
340 [`manuallydrop`]: ../std/mem/struct.ManuallyDrop.html