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 desugarring of `let` statements:
25 Each creates its own scope, clearly establishing that one drops before the
26 other. However, what if we do the following?
29 let (x, y) = (vec![], vec![]);
32 Does either value strictly outlive the other? The answer is in fact *no*,
33 neither value strictly outlives the other. Of course, one of x or y will be
34 dropped before the other, but the actual order is not specified. Tuples aren't
35 special in this regard; composite structures just don't guarantee their
36 destruction order as of Rust 1.0.
38 We *could* specify this for the fields of built-in composites like tuples and
39 structs. However, what about something like Vec? Vec has to manually drop its
40 elements via pure-library code. In general, anything that implements Drop has
41 a chance to fiddle with its innards during its final death knell. Therefore
42 the compiler can't sufficiently reason about the actual destruction order
43 of the contents of any type that implements Drop.
45 So why do we care? We care because if the type system isn't careful, it could
46 accidentally make dangling pointers. Consider the following simple program:
49 struct Inspector<'a>(&'a u8);
52 let (inspector, days);
54 inspector = Inspector(&days);
58 This program is totally sound and compiles today. The fact that `days` does
59 not *strictly* outlive `inspector` doesn't matter. As long as the `inspector`
62 However if we add a destructor, the program will no longer compile!
65 struct Inspector<'a>(&'a u8);
67 impl<'a> Drop for Inspector<'a> {
69 println!("I was only {} days from retirement!", self.0);
74 let (inspector, days);
76 inspector = Inspector(&days);
77 // Let's say `days` happens to get dropped first.
78 // Then when Inspector is dropped, it will try to read free'd memory!
83 <anon>:12:28: 12:32 error: `days` does not live long enough
84 <anon>:12 inspector = Inspector(&days);
86 <anon>:9:11: 15:2 note: reference must be valid for the block at 9:10...
88 <anon>:10 let (inspector, days);
89 <anon>:11 days = Box::new(1);
90 <anon>:12 inspector = Inspector(&days);
91 <anon>:13 // Let's say `days` happens to get dropped first.
92 <anon>:14 // Then when Inspector is dropped, it will try to read free'd memory!
94 <anon>:10:27: 15:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 10:26
95 <anon>:10 let (inspector, days);
96 <anon>:11 days = Box::new(1);
97 <anon>:12 inspector = Inspector(&days);
98 <anon>:13 // Let's say `days` happens to get dropped first.
99 <anon>:14 // Then when Inspector is dropped, it will try to read free'd memory!
103 Implementing Drop lets the Inspector execute some arbitrary code during its
104 death. This means it can potentially observe that types that are supposed to
105 live as long as it does actually were destroyed first.
107 Interestingly, only generic types need to worry about this. If they aren't
108 generic, then the only lifetimes they can harbor are `'static`, which will truly
109 live *forever*. This is why this problem is referred to as *sound generic drop*.
110 Sound generic drop is enforced by the *drop checker*. As of this writing, some
111 of the finer details of how the drop checker validates types is totally up in
112 the air. However The Big Rule is the subtlety that we have focused on this whole
115 **For a generic type to soundly implement drop, its generics arguments must
116 strictly outlive it.**
118 Obeying this rule is (usually) necessary to satisfy the borrow
119 checker; obeying it is sufficient but not necessary to be
120 sound. That is, if your type obeys this rule then it's definitely
123 The reason that it is not always necessary to satisfy the above rule
124 is that some Drop implementations will not access borrowed data even
125 though their type gives them the capability for such access.
127 For example, this variant of the above `Inspector` example will never
128 accessed borrowed data:
131 struct Inspector<'a>(&'a u8, &'static str);
133 impl<'a> Drop for Inspector<'a> {
135 println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
140 let (inspector, days);
142 inspector = Inspector(&days, "gadget");
143 // Let's say `days` happens to get dropped first.
144 // Even when Inspector is dropped, its destructor will not access the
149 Likewise, this variant will also never access borrowed data:
154 struct Inspector<T: fmt::Display>(T, &'static str);
156 impl<T: fmt::Display> Drop for Inspector<T> {
158 println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
163 let (inspector, days): (Inspector<&u8>, Box<u8>);
165 inspector = Inspector(&days, "gadget");
166 // Let's say `days` happens to get dropped first.
167 // Even when Inspector is dropped, its destructor will not access the
172 However, *both* of the above variants are rejected by the borrow
173 checker during the analysis of `fn main`, saying that `days` does not
176 The reason is that the borrow checking analysis of `main` does not
177 know about the internals of each Inspector's Drop implementation. As
178 far as the borrow checker knows while it is analyzing `main`, the body
179 of an inspector's destructor might access that borrowed data.
181 Therefore, the drop checker forces all borrowed data in a value to
182 strictly outlive that value.
186 The precise rules that govern drop checking may be less restrictive in
189 The current analysis is deliberately conservative and trivial; it forces all
190 borrowed data in a value to outlive that value, which is certainly sound.
192 Future versions of the language may make the analysis more precise, to
193 reduce the number of cases where sound code is rejected as unsafe.
194 This would help address cases such as the two Inspectors above that
195 know not to inspect during destruction.
197 In the meantime, there is an unstable attribute that one can use to
198 assert (unsafely) that a generic type's destructor is *guaranteed* to
199 not access any expired data, even if its type gives it the capability
202 That attribute is called `unsafe_destructor_blind_to_params`.
203 To deploy it on the Inspector example from above, we would write:
206 struct Inspector<'a>(&'a u8, &'static str);
208 impl<'a> Drop for Inspector<'a> {
209 #[unsafe_destructor_blind_to_params]
211 println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
216 This attribute has the word `unsafe` in it because the compiler is not
217 checking the implicit assertion that no potentially expired data
218 (e.g. `self.0` above) is accessed.
220 It is sometimes obvious that no such access can occur, like the case above.
221 However, when dealing with a generic type parameter, such access can
222 occur indirectly. Examples of such indirect access are:
223 * invoking a callback,
224 * via a trait method call.
226 (Future changes to the language, such as impl specialization, may add
227 other avenues for such indirect access.)
229 Here is an example of invoking a callback:
232 struct Inspector<T>(T, &'static str, Box<for <'r> fn(&'r T) -> String>);
234 impl<T> Drop for Inspector<T> {
236 // The `self.2` call could access a borrow e.g. if `T` is `&'a _`.
237 println!("Inspector({}, {}) unwittingly inspects expired data.",
238 (self.2)(&self.0), self.1);
243 Here is an example of a trait method call:
248 struct Inspector<T: fmt::Display>(T, &'static str);
250 impl<T: fmt::Display> Drop for Inspector<T> {
252 // There is a hidden call to `<T as Display>::fmt` below, which
253 // could access a borrow e.g. if `T` is `&'a _`
254 println!("Inspector({}, {}) unwittingly inspects expired data.",
260 And of course, all of these accesses could be further hidden within
261 some other method invoked by the destructor, rather than being written
264 In all of the above cases where the `&'a u8` is accessed in the
265 destructor, adding the `#[unsafe_destructor_blind_to_params]`
266 attribute makes the type vulnerable to misuse that the borrower
267 checker will not catch, inviting havoc. It is better to avoid adding
270 # Is that all about drop checker?
272 It turns out that when writing unsafe code, we generally don't need to
273 worry at all about doing the right thing for the drop checker. However there
274 is one special case that you need to worry about, which we will look at in