moveit/drop_flag.rs
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
56use core::cell::Cell;
57use core::mem;
58use core::mem::ManuallyDrop;
59use core::ops::Deref;
60use core::ops::DerefMut;
61
62#[cfg(doc)]
63use {
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)]
80pub struct DropFlag<'frame> {
81 counter: &'frame Cell<usize>,
82}
83
84impl 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]
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]
98 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]
108 pub fn is_dead(self) -> bool {
109 self.counter.get() == 0
110 }
111
112 /// Lengthens the lifetime of `self`.
113 #[inline]
114 #[allow(unused)]
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>`].
138pub struct DroppingFlag<T> {
139 value: ManuallyDrop<T>,
140 counter: Cell<usize>,
141}
142
143impl<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.
147 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.
158 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.
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.
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
195impl<T> Deref for DroppingFlag<T> {
196 type Target = T;
197 #[inline]
198 fn deref(&self) -> &T {
199 &self.value
200 }
201}
202
203impl<T> DerefMut for DroppingFlag<T> {
204 #[inline]
205 fn deref_mut(&mut self) -> &mut T {
206 &mut self.value
207 }
208}
209
210impl<T> Drop for DroppingFlag<T> {
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.
227pub 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
236impl TrappedFlag {
237 /// Creates a new trap with a dead flag.
238 #[cfg(debug_assertions)]
239 #[track_caller]
240 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))]
249 pub fn new() -> Self {
250 Self {
251 counter: Cell::new(0),
252 }
253 }
254
255 /// Returns a reference to the [`DropFlag`].
256 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.
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
293impl Default for TrappedFlag {
294 fn default() -> Self {
295 Self::new()
296 }
297}
298
299impl Drop for TrappedFlag {
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.
310pub struct QuietFlag {
311 counter: Cell<usize>,
312}
313
314impl QuietFlag {
315 /// Creates a new dead flag.
316 pub fn new() -> Self {
317 Self {
318 counter: Cell::new(0),
319 }
320 }
321
322 /// Returns a reference to the [`DropFlag`].
323 pub fn flag(&self) -> DropFlag {
324 DropFlag {
325 counter: &self.counter,
326 }
327 }
328}
329
330impl Default for QuietFlag {
331 fn default() -> Self {
332 Self::new()
333 }
334}