+49
-15
lifetime-guard/src/lib.rs
+49
-15
lifetime-guard/src/lib.rs
···
27
27
//!
28
28
//! # Safety
29
29
//!
30
-
//! You *may not* leak any instance of either `ValueGuard` or `RefGuard`.
30
+
//! You *may not* leak any instance of either `ValueGuard` or `RefGuard` to the
31
+
//! stack using `mem::forget()` or any other mechanism that causes thier
32
+
//! contents to be overwritten without `Drop::drop()` running.
33
+
//! Doing so creates unsoundness that likely will lead to dereferencing a null
34
+
//! pointer.
31
35
//!
32
36
//! Doing so creates unsoundness that likely will lead to dereferencing a null
33
37
//! pointer. See the
34
38
//! [Forget marker trait](https://github.com/rust-lang/rfcs/pull/3782) rfc for
35
39
//! progress on making interfaces that rely on not being leaked sound.
40
+
//!
41
+
//! Note that it is sound to leak `ValueGuard` and `RefGuard` to the heap using
42
+
//! methods including `Box::leak()` because heap allocated data will never be
43
+
//! overwritten if it is never freed.
36
44
37
45
use std::{cell::Cell, marker::PhantomPinned, pin::Pin, ptr::NonNull};
38
46
···
42
50
/// A `ValueGuard`:`RefGuard` relationship is exclusive, and behaves similarly
43
51
/// to a single `Rc` and `Weak` pair, but notably does not require heap
44
52
/// allocation. `ValueGuard::registration` creates a `GuardRegistration`, which
45
-
/// provides a movable wrapper for safetly creating the circular references
53
+
/// provides a movable wrapper for safety creating the circular references
46
54
/// between two pinned self referential structs.
47
55
///
48
56
/// # Safety
49
57
///
50
-
/// This struct *must* not be leaked, using `mem::forget`, `Rc`, `Arc`, etc.
51
-
///
58
+
/// This struct *must* not be leaked to the stack using `mem::forget` or any
59
+
/// other mechanism that causes the contents of `Self` to be overwritten
60
+
/// without `Drop::drop()` running.
52
61
/// Doing so creates unsoundness that likely will lead to dereferencing a null
53
-
/// pointer. See the
54
-
/// [Forget marker trait](https://github.com/rust-lang/rfcs/pull/3782) rfc for
55
-
/// progress on making interfaces that rely on not being leaked sound.
62
+
/// pointer.
63
+
///
64
+
/// Note that it is sound to leak `Self` to the heap using methods including
65
+
/// `Box::leak()` because heap allocated data will never be overwritten if it
66
+
/// is never freed.
56
67
pub struct ValueGuard<T> {
57
68
/// Contains the value being immutably accessed by `RefGuard` and
58
69
/// mutably accessed by `Self`
···
78
89
}
79
90
}
80
91
81
-
/// Returns a `GuardRegistration`, which can be used to safetly link `Self`
92
+
/// Returns a `GuardRegistration`, which can be used to safety link `Self`
82
93
/// to a `RefGuard`.
83
94
#[inline]
84
95
pub fn registration<'a>(self: Pin<&'a Self>) -> GuardRegistration<'a, T> {
···
119
130
///
120
131
/// # Safety
121
132
///
122
-
/// This struct *must* not be leaked, using `mem::forget`, `Rc`, `Arc`, etc.
123
-
///
133
+
/// This struct *must* not be leaked to the stack using `mem::forget` or any
134
+
/// other mechanism that causes the contents of `Self` to be overwritten
135
+
/// without `Drop::drop()` running.
124
136
/// Doing so creates unsoundness that likely will lead to dereferencing a null
125
-
/// pointer. See the
126
-
/// [Forget marker trait](https://github.com/rust-lang/rfcs/pull/3782) rfc for
127
-
/// progress on making interfaces that rely on not being leaked sound.
128
-
137
+
/// pointer.
138
+
///
139
+
/// Note that it is sound to leak `Self` to the heap using methods including
140
+
/// `Box::leak()` because heap allocated data will never be overwritten if it
141
+
/// is never freed.
129
142
pub struct RefGuard<T> {
130
143
value_guard: Cell<Option<NonNull<ValueGuard<T>>>>,
131
144
_marker: PhantomPinned,
···
165
178
if let Some(guard) = self.value_guard.get() {
166
179
invalidate_value_guard(guard);
167
180
}
181
+
}
182
+
}
183
+
184
+
impl<T> Default for RefGuard<T> {
185
+
#[inline]
186
+
fn default() -> Self {
187
+
Self::new()
168
188
}
169
189
}
170
190
···
210
230
211
231
#[cfg(test)]
212
232
mod test {
213
-
use std::pin;
233
+
use std::{mem, pin};
214
234
215
235
use super::*;
216
236
···
262
282
263
283
assert_eq!(weak1.get(), None);
264
284
assert_eq!(weak2.get(), None);
285
+
}
286
+
287
+
#[test]
288
+
#[cfg_attr(miri, ignore)]
289
+
fn safe_leak() {
290
+
let strong = Box::pin(ValueGuard::new(10));
291
+
let weak = pin::pin!(RefGuard::new());
292
+
strong.as_ref().registration().register(weak.as_ref());
293
+
294
+
// strong is now a ValueGuard on the heap that will never be freed
295
+
// this is sound because it will never be overwritten
296
+
mem::forget(strong);
297
+
298
+
assert_eq!(weak.get(), Some(10));
265
299
}
266
300
}