+49
-15
lifetime-guard/src/lib.rs
+49
-15
lifetime-guard/src/lib.rs
···
27
//!
28
//! # Safety
29
//!
30
-
//! You *may not* leak any instance of either `ValueGuard` or `RefGuard`.
31
//!
32
//! Doing so creates unsoundness that likely will lead to dereferencing a null
33
//! pointer. See the
34
//! [Forget marker trait](https://github.com/rust-lang/rfcs/pull/3782) rfc for
35
//! progress on making interfaces that rely on not being leaked sound.
36
37
use std::{cell::Cell, marker::PhantomPinned, pin::Pin, ptr::NonNull};
38
···
42
/// A `ValueGuard`:`RefGuard` relationship is exclusive, and behaves similarly
43
/// to a single `Rc` and `Weak` pair, but notably does not require heap
44
/// allocation. `ValueGuard::registration` creates a `GuardRegistration`, which
45
-
/// provides a movable wrapper for safetly creating the circular references
46
/// between two pinned self referential structs.
47
///
48
/// # Safety
49
///
50
-
/// This struct *must* not be leaked, using `mem::forget`, `Rc`, `Arc`, etc.
51
-
///
52
/// 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.
56
pub struct ValueGuard<T> {
57
/// Contains the value being immutably accessed by `RefGuard` and
58
/// mutably accessed by `Self`
···
78
}
79
}
80
81
-
/// Returns a `GuardRegistration`, which can be used to safetly link `Self`
82
/// to a `RefGuard`.
83
#[inline]
84
pub fn registration<'a>(self: Pin<&'a Self>) -> GuardRegistration<'a, T> {
···
119
///
120
/// # Safety
121
///
122
-
/// This struct *must* not be leaked, using `mem::forget`, `Rc`, `Arc`, etc.
123
-
///
124
/// 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
-
129
pub struct RefGuard<T> {
130
value_guard: Cell<Option<NonNull<ValueGuard<T>>>>,
131
_marker: PhantomPinned,
···
165
if let Some(guard) = self.value_guard.get() {
166
invalidate_value_guard(guard);
167
}
168
}
169
}
170
···
210
211
#[cfg(test)]
212
mod test {
213
-
use std::pin;
214
215
use super::*;
216
···
262
263
assert_eq!(weak1.get(), None);
264
assert_eq!(weak2.get(), None);
265
}
266
}
···
27
//!
28
//! # Safety
29
//!
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.
35
//!
36
//! Doing so creates unsoundness that likely will lead to dereferencing a null
37
//! pointer. See the
38
//! [Forget marker trait](https://github.com/rust-lang/rfcs/pull/3782) rfc for
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.
44
45
use std::{cell::Cell, marker::PhantomPinned, pin::Pin, ptr::NonNull};
46
···
50
/// A `ValueGuard`:`RefGuard` relationship is exclusive, and behaves similarly
51
/// to a single `Rc` and `Weak` pair, but notably does not require heap
52
/// allocation. `ValueGuard::registration` creates a `GuardRegistration`, which
53
+
/// provides a movable wrapper for safety creating the circular references
54
/// between two pinned self referential structs.
55
///
56
/// # Safety
57
///
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.
61
/// Doing so creates unsoundness that likely will lead to dereferencing a null
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.
67
pub struct ValueGuard<T> {
68
/// Contains the value being immutably accessed by `RefGuard` and
69
/// mutably accessed by `Self`
···
89
}
90
}
91
92
+
/// Returns a `GuardRegistration`, which can be used to safety link `Self`
93
/// to a `RefGuard`.
94
#[inline]
95
pub fn registration<'a>(self: Pin<&'a Self>) -> GuardRegistration<'a, T> {
···
130
///
131
/// # Safety
132
///
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.
136
/// Doing so creates unsoundness that likely will lead to dereferencing a null
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.
142
pub struct RefGuard<T> {
143
value_guard: Cell<Option<NonNull<ValueGuard<T>>>>,
144
_marker: PhantomPinned,
···
178
if let Some(guard) = self.value_guard.get() {
179
invalidate_value_guard(guard);
180
}
181
+
}
182
+
}
183
+
184
+
impl<T> Default for RefGuard<T> {
185
+
#[inline]
186
+
fn default() -> Self {
187
+
Self::new()
188
}
189
}
190
···
230
231
#[cfg(test)]
232
mod test {
233
+
use std::{mem, pin};
234
235
use super::*;
236
···
282
283
assert_eq!(weak1.get(), None);
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));
299
}
300
}