ostd/sync/rcu/non_null/mod.rs
1// SPDX-License-Identifier: MPL-2.0
2//! This module provides a trait and some auxiliary types to help abstract and
3//! work with non-null pointers.
4use alloc::{boxed::Box, sync::Arc};
5use vstd::prelude::*;
6use vstd_extra::prelude::*;
7
8//mod either;
9
10//use core::simd::ptr;
11use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr::NonNull};
12
13use crate::prelude::*;
14
15verus! {
16
17/// A trait that abstracts non-null pointers.
18///
19/// All common smart pointer types such as `Box<T>`, `Arc<T>`, and `Weak<T>`
20/// implement this trait as they can be converted to and from the raw pointer
21/// type of `*const T`.
22///
23/// # Safety
24///
25/// This trait must be implemented correctly (according to the doc comments for
26/// each method). Types like [`Rcu`] rely on this assumption to safely use the
27/// raw pointers.
28///
29/// [`Rcu`]: super::Rcu
30#[verus_verify]
31pub unsafe trait NonNullPtr: Sized + 'static {
32 /// The target type that this pointer refers to.
33 // TODO: Support `Target: ?Sized`.
34 type Target;
35
36 /// The verification-only permission type that represents the ownership of the smart pointer.
37 type Permission: RawPtrPerm<Ptr = Self, Target = Self::Target> + Inv;
38
39 // VERUS LIMITATION: Cannot use associated type with lifetime yet.
40 /*/// A type that behaves just like a shared reference to the `NonNullPtr`.
41 type Ref<'a>
42 where
43 Self: 'a;*/
44 // Verus LIMITATION: Cannot use `const` associated type yet.
45 /// The power of two of the pointer alignment.
46 // const ALIGN_BITS: u32;
47 const ALIGN_BITS: u32;
48
49 /// Converts to a raw pointer.
50 ///
51 /// Each call to `into_raw` must be paired with a call to `from_raw`
52 /// in order to avoid memory leakage.
53 ///
54 /// The lower [`Self::ALIGN_BITS`] of the raw pointer is guaranteed to
55 /// be zero. In other words, the pointer is guaranteed to be aligned to
56 /// `1 << Self::ALIGN_BITS`.
57 /// VERUS LIMITATION: the #[verus_spec] attribute does not support `with` in trait yet.
58 /// SOUNDNESS: Considering also returning the Dealloc permission to ensure no memory leak.
59 fn into_raw(self) -> ((ret,perm): (NonNull<Self::Target>, Tracked<Self::Permission>))
60 ensures
61 ptr_mut_from_nonnull(ret) == self.ptr_mut_spec(),
62 ptr_mut_from_nonnull(ret) == perm@.ptr(),
63 perm@.inv(),
64 ;
65
66 /// Converts back from a raw pointer.
67 ///
68 /// # Safety
69 ///
70 /// 1. The raw pointer must have been previously returned by a call to
71 /// `into_raw`.
72 /// 2. The raw pointer must not be used after calling `from_raw`.
73 ///
74 /// Note that the second point is a hard requirement: Even if the
75 /// resulting value has not (yet) been dropped, the pointer cannot be
76 /// used because it may break Rust aliasing rules (e.g., `Box<T>`
77 /// requires the pointer to be unique and thus _never_ aliased).
78 /// VERIFICATION DESIGN: It's easy to verify the second point by consuming the permission produced by `into_raw`,
79 /// so we can do nothing with the raw pointer because of the absence of permission.
80 /// VERUS LIMITATION: the #[verus_spec] attribute does not support `with` in trait yet.
81 /// SOUNDNESS: Considering consuming the Dealloc permission to ensure no double free.
82 unsafe fn from_raw(
83 ptr: NonNull<Self::Target>,
84 perm: Tracked<Self::Permission>,
85 ) -> (ret: Self)
86 requires
87 ptr_mut_from_nonnull(ptr) == perm@.ptr(),
88 perm@.inv(),
89 ensures
90 ptr_mut_from_nonnull(ptr) == ret.ptr_mut_spec(),
91 ;
92
93 // VERUS LIMITATION: Cannot use associated type with lifetime yet, will implement it as a free function for each type.
94 /*/// Obtains a shared reference to the original pointer.
95 ///
96 /// # Safety
97 ///
98 /// The original pointer must outlive the lifetime parameter `'a`, and during `'a`
99 /// no mutable references to the pointer will exist.
100 //unsafe fn raw_as_ref<'a>(raw: NonNull<Self::Target>) -> Self::Ref<'a>;*/
101 // VERUS LIMITATION: Cannot use associated type with lifetime yet, will implement it as a free function for each type.
102 /*/// Converts a shared reference to a raw pointer.
103 fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> NonNull<Self::Target>;*/
104
105 // A uninterpreted spec function that returns the inner raw pointer.
106 spec fn ptr_mut_spec(self) -> *mut Self::Target;
107}
108
109/// A type that represents `&'a Box<T>`.
110#[verus_verify]
111#[derive(Debug)]
112pub struct BoxRef<'a, T> {
113 inner: *mut T,
114 _marker: PhantomData<&'a T>,
115 v_perm: Tracked<&'a BoxPointsTo<T>>,
116}
117
118impl<'a, T> BoxRef<'a, T> {
119 #[verifier::type_invariant]
120 spec fn type_inv(self) -> bool {
121 &&& self.inner@.addr != 0
122 &&& self.inner@.addr as int % vstd::layout::align_of::<T>() as int == 0
123 &&& self.v_perm@.ptr() == self.inner
124 &&& self.v_perm@.inv()
125 }
126
127 pub closed spec fn ptr(self) -> *mut T {
128 self.inner
129 }
130
131 pub closed spec fn value(self) -> T {
132 self.v_perm@.value()
133 }
134}
135
136/*
137impl<T> Deref for BoxRef<'_, T> {
138 type Target = Box<T>;
139
140 fn deref(&self) -> &Self::Target {
141 // SAFETY: A `Box<T>` is guaranteed to be represented by a single pointer [1] and a shared
142 // reference to the `Box<T>` during the lifetime `'a` can be created according to the
143 // safety requirements of `NonNullPtr::raw_as_ref`.
144 //
145 // [1]: https://doc.rust-lang.org/std/boxed/#memory-layout
146 unsafe { core::mem::transmute(&self.inner) }
147 }
148}
149*/
150
151#[verus_verify]
152impl<'a, T> BoxRef<'a, T> {
153 /// Dereferences `self` to get a reference to `T` with the lifetime `'a`.
154 #[verus_spec(ret => ensures *ret == self.value())]
155 pub fn deref_target(&self) -> &'a T {
156 // [VERIFIED] SAFETY: The reference is created through `NonNullPtr::raw_as_ref`, hence
157 // the original owned pointer and target must outlive the lifetime parameter `'a`,
158 // and during `'a` no mutable references to the pointer will exist.
159 let Tracked(perm) = self.v_perm;
160 proof!{
161 use_type_invariant(self);
162 }
163 //unsafe { &*(self.inner) }
164 vstd::raw_ptr::ptr_ref(
165 self.inner,
166 Tracked(perm.tracked_borrow_points_to()),
167 ) // The function body of ptr_ref is exactly the same as `unsafe { &*(self.inner) }`
168
169 }
170}
171
172unsafe impl<T: 'static> NonNullPtr for Box<T> {
173 type Target = T;
174
175 type Permission = BoxPointsTo<T>;
176
177 /*type Ref<'a>
178 = BoxRef<'a, T>
179 where
180 Self: 'a;*/
181 #[verifier::external_body]
182 const ALIGN_BITS: u32 = core::mem::align_of::<T>().trailing_zeros();
183
184 fn into_raw(self) -> (NonNull<Self::Target>, Tracked<Self::Permission>) {
185 //let ptr = Box::into_raw(self);
186 let (ptr, Tracked(points_to), Tracked(dealloc)) = box_into_raw(self);
187 proof_decl!{
188 let tracked box_points_to = BoxPointsTo {
189 perm: PointsTowithDealloc::new(points_to, dealloc),
190 };
191 }
192 // [VERIFIED] SAFETY: The pointer representing a `Box` can never be NULL.
193 (unsafe { NonNull::new_unchecked(ptr) }, Tracked(box_points_to))
194 }
195
196 unsafe fn from_raw(
197 ptr: NonNull<Self::Target>,
198 Tracked(perm): Tracked<Self::Permission>,
199 ) -> Self {
200 proof_decl!{
201 let tracked perm = perm.tracked_get_points_to_with_dealloc();
202 }
203 let ptr = ptr.as_ptr();
204
205 // [VERIFIED] SAFETY: The safety is upheld by the caller.
206 // unsafe { Box::from_raw(ptr) }
207 unsafe { box_from_raw(ptr, Tracked(perm.points_to), Tracked(perm.dealloc)) }
208 }
209
210 /*unsafe fn raw_as_ref<'a>(raw: NonNull<Self::Target>) -> Self::Ref<'a> {
211 BoxRef {
212 inner: raw.as_ptr(),
213 _marker: PhantomData,
214 }
215 }*/
216 /*fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> NonNull<Self::Target> {
217 // SAFETY: The pointer representing a `Box` can never be NULL.
218 unsafe { NonNull::new_unchecked(ptr_ref.inner) }
219 }*/
220 open spec fn ptr_mut_spec(self) -> *mut Self::Target {
221 box_pointer_spec(self)
222 }
223}
224
225pub fn box_ref_as_raw<T: 'static>(ptr_ref: BoxRef<'_, T>) -> ((ret,perm): (
226 NonNull<T>,
227 Tracked<&BoxPointsTo<T>>,
228))
229 ensures
230 ret == nonnull_from_ptr_mut(ptr_ref.ptr()),
231 perm@.ptr().addr() != 0,
232 perm@.ptr().addr() as int % vstd::layout::align_of::<T>() as int == 0,
233 perm@.ptr() == ptr_mut_from_nonnull(ret),
234 perm@.inv(),
235{
236 proof!{
237 use_type_invariant(&ptr_ref);
238 }
239 // [VERIFIED] SAFETY: The pointer representing a `Box` can never be NULL.
240 (unsafe { NonNull::new_unchecked(ptr_ref.inner) }, ptr_ref.v_perm)
241}
242
243pub unsafe fn box_raw_as_ref<'a, T: 'static>(
244 raw: NonNull<T>,
245 perm: Tracked<&'a BoxPointsTo<T>>,
246) -> BoxRef<'a, T>
247 requires
248 perm@.ptr() == ptr_mut_from_nonnull(raw),
249 perm@.inv(),
250{
251 BoxRef { inner: raw.as_ptr(), _marker: PhantomData, v_perm: perm }
252}
253
254/// A type that represents `&'a Arc<T>`.
255#[verus_verify]
256#[derive(Debug)]
257pub struct ArcRef<'a, T: 'static> {
258 inner: ManuallyDrop<Arc<T>>,
259 _marker: PhantomData<
260 &'a Arc<T>,
261 >,
262 // Note there is no permission field here, because `ArcRef` does not use a raw pointer directly.
263}
264
265impl<'a, T> ArcRef<'a, T> {
266 #[verifier::type_invariant]
267 spec fn type_inv(self) -> bool {
268 //&&& self.ptr() == self.v_perm@.ptr()
269 //&&& self.v_perm@.inv()
270 &&& self.ptr()@.addr != 0
271 &&& self.ptr()@.addr as int % vstd::layout::align_of::<T>() as int == 0
272 }
273
274 pub open spec fn ptr(self) -> *const T {
275 arc_pointer_spec(*self.deref_as_arc_spec())
276 }
277
278 pub closed spec fn deref_as_arc_spec(&self) -> &Arc<T> {
279 &self.inner@
280 }
281}
282
283#[verus_verify]
284impl<T> Deref for ArcRef<'_, T> {
285 type Target = Arc<T>;
286
287 #[verus_spec]
288 fn deref(&self) -> &Self::Target {
289 &self.inner
290 }
291}
292
293#[verus_verify]
294impl<'a, T> ArcRef<'a, T> {
295 /// Dereferences `self` to get a reference to `T` with the lifetime `'a`.
296 /// VERUS LIMITATION: The code includes a cast from `&T` to `*const T`, which is not specified yet in Verus.
297 /// This is also a nontrivial use case that extends the lifetime of the reference.
298 #[verus_verify(external_body)]
299 #[verus_spec(ret => ensures *ret == *(self.deref_as_arc_spec()))]
300 pub fn deref_target(&self) -> &'a T {
301 // SAFETY: The reference is created through `NonNullPtr::raw_as_ref`, hence
302 // the original owned pointer and target must outlive the lifetime parameter `'a`,
303 // and during `'a` no mutable references to the pointer will exist.
304 unsafe { &*(self.deref().deref() as *const T) }
305 }
306}
307
308unsafe impl<T: 'static> NonNullPtr for Arc<T> {
309 type Target = T;
310
311 type Permission = ArcPointsTo<T>;
312
313 /*
314 type Ref<'a>
315 = ArcRef<'a, T>
316 where
317 Self: 'a;*/
318
319 #[verifier::external_body]
320 const ALIGN_BITS: u32 = core::mem::align_of::<T>().trailing_zeros();
321
322 fn into_raw(self) -> (NonNull<Self::Target>, Tracked<Self::Permission>) {
323 // let ptr = Arc::into_raw(self).cast_mut();
324 let (ptr, Tracked(perm)) = arc_into_raw(self);
325 let ptr = ptr as *mut T;
326 // [VERIFIED] SAFETY: The pointer representing an `Arc` can never be NULL.
327 (unsafe { NonNull::new_unchecked(ptr) }, Tracked(perm))
328 }
329
330 unsafe fn from_raw(
331 ptr: NonNull<Self::Target>,
332 Tracked(perm): Tracked<Self::Permission>,
333 ) -> Self {
334 //let ptr = ptr.as_ptr().cast_const();
335 let ptr = ptr.as_ptr() as *const T;
336
337 // [VERIFIED] SAFETY: The safety is upheld by the caller.
338 // unsafe { Arc::from_raw(ptr) }
339 unsafe { arc_from_raw(ptr, Tracked(perm)) }
340 }
341
342 /*
343 unsafe fn raw_as_ref<'a>(raw: NonNull<Self::Target>) -> Self::Ref<'a> {
344 // SAFETY: The safety is upheld by the caller.
345 unsafe {
346 ArcRef {
347 inner: ManuallyDrop::new(Arc::from_raw(raw.as_ptr())),
348 _marker: PhantomData,
349 }
350 }
351 }
352
353 fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> NonNull<Self::Target> {
354 NonNullPtr::into_raw(ManuallyDrop::into_inner(ptr_ref.inner))
355 }*/
356
357 open spec fn ptr_mut_spec(self) -> *mut Self::Target {
358 arc_pointer_spec(self) as *mut Self::Target
359 }
360}
361
362pub fn arc_ref_as_raw<T: 'static>(ptr_ref: ArcRef<'_, T>) -> ((ret,perm): (
363 NonNull<T>,
364 Tracked<ArcPointsTo<T>>,
365))
366 ensures
367 ret == nonnull_from_ptr_mut(ptr_ref.ptr() as *mut T),
368 perm@.ptr().addr() != 0,
369 perm@.ptr().addr() as int % vstd::layout::align_of::<T>() as int == 0,
370 perm@.ptr() == ptr_mut_from_nonnull(ret),
371 perm@.inv(),
372{
373 // NonNullPtr::into_raw(ManuallyDrop::into_inner(ptr_ref.inner))
374 let (ptr, Tracked(perm)) = NonNullPtr::into_raw(ManuallyDrop::into_inner(ptr_ref.inner));
375 (ptr, Tracked(perm))
376}
377
378pub unsafe fn arc_raw_as_ref<'a, T: 'static>(
379 raw: NonNull<T>,
380 perm: Tracked<ArcPointsTo<T>>,
381) -> (ret: ArcRef<'a, T>)
382 requires
383 perm@.ptr() == ptr_mut_from_nonnull(raw),
384 perm@.inv(),
385 ensures
386 ret.ptr() == perm@.ptr(),
387{
388 unsafe {
389 ArcRef { inner: ManuallyDrop::new(arc_from_raw(raw.as_ptr(), perm)), _marker: PhantomData }
390 }
391}
392
393broadcast use group_nonnull;
394
395} // verus!