1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Drop flags.
16 //!
17 //! The [`Pin<P>`] guarantees state that if we have a `T` allocated somewhere,
18 //! and we construct a pinned reference to it such as a `Pin<&'a mut T>`, then
19 //! before that "somewhere" in memory is reused by another Rust object, `T`'s
20 //! destructor must run.
21 //!
22 //! Normally, this isn't a problem for Rust code, since the storage of an object
23 //! is destroyed immediately after it is destroyed. [`DerefMove`], however,
24 //! breaks this expectation: it separates the destructors from its storage and
25 //! contents into two separately destroyed objects: a [`AsMove::Storage`] and a
26 //! [`MoveRef`]. If the [`MoveRef`] is [`mem::forget`]'ed, we lose: the storage
27 //! will potentially be re-used.
28 //!
29 //! Therefore, we must somehow detect that [`MoveRef`]s fail to be destroyed
30 //! when the destructor for the corresponding storage is run, and remediate it,
31 //! either by leaking heap storage or aborting if we would free stack storage
32 //! (a panic is insufficient, since that location can be reused if the panic is
33 //! caught).
34 //!
35 //! A [`DropFlag`] allows us to achieve this. It is a generalized, library-level
36 //! version of the Rust language's drop flags, which it uses to dynamically
37 //! determine whether to run destructors of stack-allocated values that might
38 //! have been moved from. Unlike Rust language drop flags, a [`DropFlag`] is
39 //! actually a counter, rather than a boolean. This allows storage that holds
40 //! many objects, like a vector, ensure that all contents have been properly
41 //! destroyed.
42 //!
43 //! This module also provides two helper types simplify safe creation and
44 //! management of drop flags.
45 //!
46 //! See the [Rustonomicon entry](https://doc.rust-lang.org/nomicon/drop-flags.html)
47 //! for the Rust language equivalent.
48 //!
49 //! # Safety
50 //!
51 //! No function in this module is `unsafe`: instead, functions that construct
52 //! [`MoveRef`]s out of [`DropFlag`]s are `unsafe`, and their callers are
53 //! responsible for ensuring that the passed-in [`DropFlag`] helps uphold the
54 //! relevant invariants.
55 
56 use core::cell::Cell;
57 use core::mem;
58 use core::mem::ManuallyDrop;
59 use core::ops::Deref;
60 use core::ops::DerefMut;
61 
62 #[cfg(doc)]
63 use {
64   crate::move_ref::{AsMove, DerefMove, MoveRef},
65   alloc::boxed::Box,
66   core::pin::Pin,
67 };
68 
69 /// A drop flag, for tracking successful destruction.
70 ///
71 /// A `DropFlag` is a reference to a counter somewhere on the stack that lives
72 /// adjacent to storage for some value. It is just a counter: `unsafe` code is
73 /// expected to associate semantic meaning to it.
74 ///
75 /// A flag with a value of zero is usually called "dead", and setting a flag to
76 /// the dead state is called clearing it.
77 ///
78 /// See the [module documentation][self] for more information.
79 #[derive(Clone, Copy)]
80 pub struct DropFlag<'frame> {
81   counter: &'frame Cell<usize>,
82 }
83 
84 impl DropFlag<'_> {
85   /// Increments the internal counter.
86   ///
87   /// This function does not provide any overflow protection; `unsafe` code is
88   /// responsible for making sure that cannot happen.
89   #[inline]
inc(self)90   pub fn inc(self) {
91     self.counter.set(self.counter.get() + 1)
92   }
93 
94   /// Decrements the internal counter and returns true if it became zero.
95   ///
96   /// This function will return `false` if the counter was already zero.
97   #[inline]
dec_and_check_if_died(self) -> bool98   pub fn dec_and_check_if_died(self) -> bool {
99     if self.counter.get() == 0 {
100       return false;
101     }
102     self.counter.set(self.counter.get() - 1);
103     self.is_dead()
104   }
105 
106   /// Returns whether the internal counter is zero.
107   #[inline]
is_dead(self) -> bool108   pub fn is_dead(self) -> bool {
109     self.counter.get() == 0
110   }
111 
112   /// Lengthens the lifetime of `self`.
113   #[inline]
114   #[allow(unused)]
longer_lifetime<'a>(self) -> DropFlag<'a>115   pub(crate) unsafe fn longer_lifetime<'a>(self) -> DropFlag<'a> {
116     DropFlag {
117       counter: mem::transmute(self.counter),
118     }
119   }
120 }
121 
122 /// A wrapper for managing when a value gets dropped via a [`DropFlag`].
123 ///
124 /// This type tracks the destruction state of some value relative to another
125 /// value via its [`DropFlag`]: for example, it might be the storage of a value
126 /// wrapped up in a [`MoveRef`]. When a `DroppingFlag` is destroyed, it will
127 /// run the destructor for the wrapped value if and only if the [`DropFlag`]
128 /// is dead.
129 ///
130 /// This type can be viewed as using a [`DropFlag`] to "complete" a
131 /// [`ManuallyDrop<T>`] by explicitly tracking whether it has been dropped. The
132 /// flag can be used to signal whether to destroy or leak the value, but the
133 /// destruction occurs lazily rather than immediately when the flag is flipped.
134 ///
135 /// This is useful as an [`AsMove::Storage`] type for types where the storage
136 /// should be leaked if the inner type was somehow not destroyed, such as in
137 /// the case of heap-allocated storage like [`Box<T>`].
138 pub struct DroppingFlag<T> {
139   value: ManuallyDrop<T>,
140   counter: Cell<usize>,
141 }
142 
143 impl<T> DroppingFlag<T> {
144   /// Wraps a new value to have its drop state managed by a `DropFlag`.
145   ///
146   /// The drop flag will start out dead and needs to be manually incremented.
new(value: T) -> Self147   pub fn new(value: T) -> Self {
148     Self {
149       value: ManuallyDrop::new(value),
150       counter: Cell::new(0),
151     }
152   }
153 
154   /// Gets a reference to the drop flag.
155   ///
156   /// This function is safe; the returned reference to the drop flag cannot be
157   /// used to make a previously dropped value live again.
flag(slot: &Self) -> DropFlag158   pub fn flag(slot: &Self) -> DropFlag {
159     DropFlag {
160       counter: &slot.counter,
161     }
162   }
163 
164   /// Splits this slot into a reference to the wrapped value plus a reference to
165   /// the drop flag.
166   ///
167   /// This function is safe; the returned reference to the drop flag cannot be
168   /// used to make a previously dropped value live again, since the value is
169   /// not destroyed before the wrapper is.
as_parts(slot: &Self) -> (&T, DropFlag)170   pub fn as_parts(slot: &Self) -> (&T, DropFlag) {
171     (
172       &slot.value,
173       DropFlag {
174         counter: &slot.counter,
175       },
176     )
177   }
178 
179   /// Splits this slot into a reference to the wrapped value plus a reference to
180   /// the drop flag.
181   ///
182   /// This function is safe; the returned reference to the drop flag cannot be
183   /// used to make a previously dropped value live again, since the value is
184   /// not destroyed before the wrapper is.
as_parts_mut(slot: &mut Self) -> (&mut T, DropFlag)185   pub fn as_parts_mut(slot: &mut Self) -> (&mut T, DropFlag) {
186     (
187       &mut slot.value,
188       DropFlag {
189         counter: &slot.counter,
190       },
191     )
192   }
193 }
194 
195 impl<T> Deref for DroppingFlag<T> {
196   type Target = T;
197   #[inline]
deref(&self) -> &T198   fn deref(&self) -> &T {
199     &self.value
200   }
201 }
202 
203 impl<T> DerefMut for DroppingFlag<T> {
204   #[inline]
deref_mut(&mut self) -> &mut T205   fn deref_mut(&mut self) -> &mut T {
206     &mut self.value
207   }
208 }
209 
210 impl<T> Drop for DroppingFlag<T> {
drop(&mut self)211   fn drop(&mut self) {
212     if Self::flag(self).is_dead() {
213       unsafe {
214         ManuallyDrop::drop(&mut self.value);
215       }
216     }
217   }
218 }
219 
220 /// An RAII trap that ensures a drop flag is correctly cleared.
221 ///
222 /// This type is *similar* to a [`DroppingFlag`], except that it does not wrap
223 /// a value and rather than leaking memory aborts the program if its flag is
224 /// not cleared.
225 ///
226 /// This type is useful for safely constructing [`MoveRef`]s.
227 pub struct TrappedFlag {
228   counter: Cell<usize>,
229 
230   // In debug mode, we capture the location the trap is created at, to help
231   // connect an eventual failure to the matching storage.
232   #[cfg(debug_assertions)]
233   location: &'static core::panic::Location<'static>,
234 }
235 
236 impl TrappedFlag {
237   /// Creates a new trap with a dead flag.
238   #[cfg(debug_assertions)]
239   #[track_caller]
new() -> Self240   pub fn new() -> Self {
241     Self {
242       counter: Cell::new(0),
243       location: core::panic::Location::caller(),
244     }
245   }
246 
247   /// Creates a new trap with a dead flag.
248   #[cfg(not(debug_assertions))]
new() -> Self249   pub fn new() -> Self {
250     Self {
251       counter: Cell::new(0),
252     }
253   }
254 
255   /// Returns a reference to the [`DropFlag`].
flag(&self) -> DropFlag256   pub fn flag(&self) -> DropFlag {
257     DropFlag {
258       counter: &self.counter,
259     }
260   }
261 
262   /// Preemptively checks that this flag has been cleared.
263   ///
264   /// Aborts (rather than panicking!) if the assertion fails.
assert_cleared(&self)265   pub fn assert_cleared(&self) {
266     if self.flag().is_dead() {
267       return;
268     }
269 
270     // We can force an abort by triggering a panic mid-unwind.
271     // This is the only way to force an LLVM abort from inside of `core`.
272     struct DoublePanic;
273     impl Drop for DoublePanic {
274       fn drop(&mut self) {
275         // In tests, we don't double-panic so that we can observe the
276         // failure correctly.
277         if cfg!(not(test)) {
278           panic!()
279         }
280       }
281     }
282 
283     let _dp = DoublePanic;
284 
285     #[cfg(debug_assertions)]
286     panic!("a critical drop flag at {} was not cleared!", self.location);
287 
288     #[cfg(not(debug_assertions))]
289     panic!("a critical drop flag was not cleared!");
290   }
291 }
292 
293 impl Default for TrappedFlag {
default() -> Self294   fn default() -> Self {
295     Self::new()
296   }
297 }
298 
299 impl Drop for TrappedFlag {
drop(&mut self)300   fn drop(&mut self) {
301     self.assert_cleared();
302   }
303 }
304 
305 /// A [`DropFlag`] source that doesn't do anything with it.
306 ///
307 /// This is similar to `TrappedFlag`, but where it does not abort the program
308 /// if used incorrectly. This type is generally only useful when some separate
309 /// mechanism is ensuring that invariants are not violated.
310 pub struct QuietFlag {
311   counter: Cell<usize>,
312 }
313 
314 impl QuietFlag {
315   /// Creates a new dead flag.
new() -> Self316   pub fn new() -> Self {
317     Self {
318       counter: Cell::new(0),
319     }
320   }
321 
322   /// Returns a reference to the [`DropFlag`].
flag(&self) -> DropFlag323   pub fn flag(&self) -> DropFlag {
324     DropFlag {
325       counter: &self.counter,
326     }
327   }
328 }
329 
330 impl Default for QuietFlag {
default() -> Self331   fn default() -> Self {
332     Self::new()
333   }
334 }
335