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:
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].
33 let tuple = (vec![], vec![]);
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
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:
47 struct Inspector<'a>(&'a u8);
50 inspector: Option<Inspector<'a>>,
55 let mut world = World {
59 world.inspector = Some(Inspector(&world.days));
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
67 However if we add a destructor, the program will no longer compile!
70 struct Inspector<'a>(&'a u8);
72 impl<'a> Drop for Inspector<'a> {
74 println!("I was only {} days from retirement!", self.0);
79 inspector: Option<Inspector<'a>>,
84 let mut world = World {
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!
95 error[E0597]: `world.days` does not live long enough
98 19 | world.inspector = Some(Inspector(&world.days));
99 | ^^^^^^^^^^^ borrowed value does not live long enough
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<'_>`
108 You can try changing the order of fields or use a tuple instead of the struct,
109 it'll still not compile.
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.
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
123 **For a generic type to soundly implement drop, its generics arguments must
124 strictly outlive it.**
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
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.
137 For example, this variant of the above `Inspector` example will never
138 access borrowed data:
141 struct Inspector<'a>(&'a u8, &'static str);
143 impl<'a> Drop for Inspector<'a> {
145 println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
150 inspector: Option<Inspector<'a>>,
155 let mut world = World {
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
166 Likewise, this variant will also never access borrowed data:
169 struct Inspector<T>(T, &'static str);
171 impl<T> Drop for Inspector<T> {
173 println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
178 inspector: Option<Inspector<T>>,
183 let mut world = World {
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
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
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.
203 Therefore, the drop checker forces all borrowed data in a value to
204 strictly outlive that value.
208 The precise rules that govern drop checking may be less restrictive in
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.
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.
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
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:
228 #![feature(dropck_eyepatch)]
230 struct Inspector<'a>(&'a u8, &'static str);
232 unsafe impl<#[may_dangle] 'a> Drop for Inspector<'a> {
234 println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
240 inspector: Option<Inspector<'a>>,
244 let mut world = World {
248 world.inspector = Some(Inspector(&world.days, "gatget"));
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.
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
263 use std::fmt::Display;
265 struct Inspector<'a, 'b, T, U: Display>(&'a u8, &'b u8, T, U);
267 unsafe impl<'a, #[may_dangle] 'b, #[may_dangle] T, U: Display> Drop for Inspector<'a, 'b, T, U> {
269 println!("Inspector({}, _, _, {})", self.0, self.3);
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:
278 - invoking a callback,
279 - via a trait method call.
281 (Future changes to the language, such as impl specialization, may add
282 other avenues for such indirect access.)
284 Here is an example of invoking a callback:
287 struct Inspector<T>(T, &'static str, Box<for <'r> fn(&'r T) -> String>);
289 impl<T> Drop for Inspector<T> {
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);
298 Here is an example of a trait method call:
303 struct Inspector<T: fmt::Display>(T, &'static str);
305 impl<T: fmt::Display> Drop for Inspector<T> {
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.",
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
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
325 # A related side note about drop order
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.
331 # Is that all about drop checker?
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
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