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