Skip to main content

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::raw_ptr::*;
7use vstd_extra::prelude::*;
8
9mod either;
10
11use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr::NonNull};
12
13verus! {
14
15broadcast use {group_nonull_axioms, group_raw_ptr_axioms};
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    // VERUS LIMITATION: Verus does not support generic associated type with lifetime yet,
37    // so we put all methods related to the Ref associated type in the `NonNullPtrRef` trait.
38    /*/// A type that behaves just like a shared reference to the `NonNullPtr`.
39    type Ref<'a>
40    where
41        Self: 'a;*/
42    /// A verification-only permission type that represents the ownership of the memory managed by the pointer.
43    type Permission: Inv;
44
45    /// The power of two of the pointer alignment.
46    const ALIGN_BITS: u32;
47
48    /// Converts to a raw pointer.
49    ///
50    /// Each call to `into_raw` must be paired with a call to `from_raw`
51    /// in order to avoid memory leakage.
52    ///
53    /// The lower [`Self::ALIGN_BITS`] of the raw pointer is guaranteed to
54    /// be zero. In other words, the pointer is guaranteed to be aligned to
55    /// `1 << Self::ALIGN_BITS`.
56    /// VERUS LIMITATION: the #[verus_spec] attribute does not support `with` in trait yet.
57    fn into_raw(self) -> ((res_ptr, perm): (NonNull<Self::Target>, Tracked<Self::Permission>))
58        ensures
59            Self::ptr_perm_match(res_ptr.view_ptr_mut(), perm@),
60            self.rel_perm(perm@),
61            perm@.inv(),
62            res_ptr.view_ptr_mut().addr() % (1usize << Self::ALIGN_BITS) == 0,
63    ;
64
65    /// Converts back from a raw pointer.
66    ///
67    /// # Safety
68    ///
69    /// 1. The raw pointer must have been previously returned by a call to
70    ///    `into_raw`.
71    /// 2. The raw pointer must not be used after calling `from_raw`.
72    ///
73    /// Note that the second point is a hard requirement: Even if the
74    /// resulting value has not (yet) been dropped, the pointer cannot be
75    /// used because it may break Rust aliasing rules (e.g., `Box<T>`
76    /// requires the pointer to be unique and thus _never_ aliased).
77    /// VERIFICATION DESIGN: It's easy to verify the second point by consuming the permission produced by `into_raw`,
78    /// so we can do nothing with the raw pointer because of the absence of permission.
79    /// VERUS LIMITATION: the #[verus_spec] attribute does not support `with` in trait yet.
80    unsafe fn from_raw(ptr: NonNull<Self::Target>, perm: Tracked<Self::Permission>) -> (ret: Self)
81        requires
82            Self::ptr_perm_match(ptr.view_ptr_mut(), perm@),
83            perm@.inv(),
84        ensures
85            ret.rel_perm(perm@),
86    ;
87
88    /*/// Obtains a shared reference to the original pointer.
89    ///
90    /// # Safety
91    ///
92    /// The original pointer must outlive the lifetime parameter `'a`, and during `'a`
93    /// no mutable references to the pointer will exist.
94    //unsafe fn raw_as_ref<'a>(raw: NonNull<Self::Target>) -> Self::Ref<'a>;*/
95    /*/// Converts a shared reference to a raw pointer.
96    fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> NonNull<Self::Target>;*/
97    /// A specification function that constraints the nonnull pointer and the permission returned by `into_raw`.
98    /// This design is to support the tagged pointer trick used in `Either`.
99    spec fn ptr_perm_match(ptr: *mut Self::Target, perm: Self::Permission) -> bool;
100
101    /// A specification function that relates the original smart pointer and the permission.
102    spec fn rel_perm(self, perm: Self::Permission) -> bool;
103
104    /// The ALIGN_BITS must be less than usize::BITS.
105    proof fn lemma_align_bits_range()
106        ensures
107            Self::ALIGN_BITS < usize::BITS,
108    ;
109}
110
111/// The trait for the associated Ref type of `NonNullPtr`, which is separated from the `NonNullPtr` trait.
112/// FIXME: This is a workaround for the lack of GAT with lifetime in Verus. We can merge this trait back to `NonNullPtr`
113/// once it is supported.
114pub unsafe trait NonNullPtrRef<'a>: NonNullPtr {
115    type Ref: 'a;
116
117    /// A verification-only permission type that represents the reading permission of the memory managed by the pointer.
118    type RefPermission: Inv;
119
120    /// The RefPermission must be able to be viewed as the owned Permission.
121    spec fn ref_perm_view_permission(perm: Self::RefPermission) -> Self::Permission;
122
123    /// A specification function that relates the `Ref` type and the `RefPermission`.
124    spec fn ref_rel_perm(r: Self::Ref, perm: Self::RefPermission) -> bool;
125
126    /// The `RefPermission` must present the invariant of the `Permission`.
127    proof fn lemma_ref_perm_inv_impl_perm_inv(perm: Self::RefPermission)
128        requires
129            perm.inv(),
130        ensures
131            Self::ref_perm_view_permission(perm).inv(),
132    ;
133
134    /// Borrows a reusable reading permission from an existing reading permission.
135    proof fn borrow_ref_perm(tracked perm: &Self::RefPermission) -> (tracked ret:
136        Self::RefPermission)
137        requires
138            perm.inv(),
139        ensures
140            ret.inv(),
141            Self::ref_perm_view_permission(ret) == Self::ref_perm_view_permission(*perm),
142    ;
143
144    /// Borrows a reusable reading permission from the owned permission.
145    proof fn borrow_perm_as_ref_perm(tracked perm: &'a Self::Permission) -> (tracked ret:
146        Self::RefPermission)
147        requires
148            perm.inv(),
149        ensures
150            ret.inv(),
151            Self::ref_perm_view_permission(ret) == *perm,
152    ;
153
154    /// Obtains a shared reference to the original pointer.
155    ///
156    /// # Safety
157    ///
158    /// The original pointer must outlive the lifetime parameter `'a`, and during `'a`
159    /// no mutable references to the pointer will exist.
160    unsafe fn raw_as_ref(raw: NonNull<Self::Target>, perm: Tracked<Self::RefPermission>) -> (ret:
161        Self::Ref)
162        requires
163            Self::ptr_perm_match(raw.view_ptr_mut(), Self::ref_perm_view_permission(perm@)),
164            perm@.inv(),
165        ensures
166            Self::ref_rel_perm(ret, perm@),
167    ;
168
169    /// Converts a shared reference to a raw pointer.
170    fn ref_as_raw(ptr_ref: Self::Ref) -> ((res_ptr, perm): (
171        NonNull<Self::Target>,
172        Tracked<Self::RefPermission>,
173    ))
174        ensures
175            Self::ref_rel_perm(ptr_ref, perm@),
176            Self::ptr_perm_match(res_ptr.view_ptr_mut(), Self::ref_perm_view_permission(perm@)),
177            perm@.inv(),
178            res_ptr.view_ptr_mut().addr() % (1usize << Self::ALIGN_BITS) == 0,
179    ;
180}
181
182} // verus!
183/// A type that represents `&'a Box<T>`.
184#[verus_verify]
185#[derive(Debug)]
186pub struct BoxRef<'a, T> {
187    inner: *mut T,
188    _marker: PhantomData<&'a T>,
189    tracked_perm: Tracked<BoxPointsToRef<'a, T>>,
190}
191
192/*
193impl<T> Deref for BoxRef<'_, T> {
194    type Target = Box<T>;
195
196    fn deref(&self) -> &Self::Target {
197        // SAFETY: A `Box<T>` is guaranteed to be represented by a single pointer [1] and a shared
198        // reference to the `Box<T>` during the lifetime `'a` can be created according to the
199        // safety requirements of `NonNullPtr::raw_as_ref`.
200        //
201        // [1]: https://doc.rust-lang.org/std/boxed/#memory-layout
202        unsafe { core::mem::transmute(&self.inner) }
203    }
204}
205*/
206
207verus! {
208
209#[verus_verify]
210impl<'a, T> BoxRef<'a, T> {
211    /// Dereferences `self` to get a reference to `T` with the lifetime `'a`.
212    #[verus_spec(ret => ensures *ret == self.value())]
213    pub fn deref_target(&self) -> &'a T {
214        proof!{
215            use_type_invariant(self);
216        }
217        // [VERIFIED] SAFETY: The reference is created through `NonNullPtr::raw_as_ref`, hence
218        // the original owned pointer and target must outlive the lifetime parameter `'a`,
219        // and during `'a` no mutable references to the pointer will exist.
220
221        // The function body of ptr_ref is exactly the same as `unsafe { &*(self.inner) }`
222        //unsafe { &*(self.inner) }
223        // FIXME: Fix when verus supports attribute syntax for raw pointers.
224        vstd::raw_ptr::ptr_ref(
225            self.inner,
226            Tracked(self.tracked_perm.borrow().tracked_borrow_points_to()),
227        )
228    }
229}
230
231unsafe impl<T: 'static> NonNullPtr for Box<T> {
232    type Target = T;
233
234    type Permission = BoxPointsTo<T>;
235
236    /*type Ref<'a>
237        = BoxRef<'a, T>
238    where
239        Self: 'a;*/
240    #[verifier::external_body]
241    const ALIGN_BITS: u32 = core::mem::align_of::<T>().trailing_zeros();
242
243    #[verus_spec]
244    fn into_raw(self) -> (NonNull<Self::Target>, Tracked<Self::Permission>) {
245        proof_decl! {
246            let tracked perm: (PointsTo<T>, Option<Dealloc>);
247        }
248
249        //let ptr = Box::into_raw(self);
250        proof_with!(=> Tracked(perm));
251        let ptr = box_into_raw(self);
252
253        proof_decl!{
254            let tracked box_points_to = BoxPointsTo {
255                perm: PointsTowithDealloc::new(perm.0, perm.1),
256            };
257        }
258        assume(ptr.addr() % (1usize << Self::ALIGN_BITS) == 0);
259
260        // [VERIFIED] SAFETY: The pointer representing a `Box` can never be NULL.
261        (unsafe { NonNull::new_unchecked(ptr) }, Tracked(box_points_to))
262    }
263
264    #[verus_spec]
265    unsafe fn from_raw(
266        ptr: NonNull<Self::Target>,
267        Tracked(perm): Tracked<Self::Permission>,
268    ) -> Self {
269        proof_decl!{
270            let tracked perm = perm.tracked_get_points_to_with_dealloc();
271        }
272
273        let ptr = ptr.as_ptr();
274
275        // [VERIFIED] SAFETY: The safety is upheld by the caller.
276        // unsafe { Box::from_raw(ptr) }
277        unsafe {
278            proof_with!(Tracked(perm.points_to), Tracked(perm.dealloc));
279            box_from_raw(ptr)
280        }
281    }
282
283    open spec fn ptr_perm_match(ptr: *mut Self::Target, perm: Self::Permission) -> bool {
284        ptr == perm.ptr()
285    }
286
287    open spec fn rel_perm(self, perm: Self::Permission) -> bool {
288        perm.view_target() == *self
289    }
290
291    axiom fn lemma_align_bits_range();
292}
293
294unsafe impl<'a, T: 'static> NonNullPtrRef<'a> for Box<T> {
295    type Ref = BoxRef<'a, T>;
296
297    type RefPermission = BoxPointsToRef<'a, T>;
298
299    open spec fn ref_perm_view_permission(perm: Self::RefPermission) -> Self::Permission {
300        perm@
301    }
302
303    open spec fn ref_rel_perm(r: Self::Ref, perm: Self::RefPermission) -> bool {
304        &&& r.value() == perm@.value()
305        &&& r.ptr() == perm@.ptr()
306    }
307
308    proof fn lemma_ref_perm_inv_impl_perm_inv(perm: Self::RefPermission) {
309    }
310
311    proof fn borrow_ref_perm(tracked perm: &Self::RefPermission) -> (tracked ret:
312        Self::RefPermission) {
313        BoxPointsToRef(perm.0)
314    }
315
316    proof fn borrow_perm_as_ref_perm(tracked perm: &'a Self::Permission) -> (tracked ret:
317        Self::RefPermission) {
318        BoxPointsToRef(perm)
319    }
320
321    unsafe fn raw_as_ref(
322        raw: NonNull<Self::Target>,
323        perm: Tracked<Self::RefPermission>,
324    ) -> Self::Ref {
325        BoxRef { inner: raw.as_ptr(), _marker: PhantomData, tracked_perm: perm }
326    }
327
328    fn ref_as_raw(ptr_ref: Self::Ref) -> (NonNull<Self::Target>, Tracked<Self::RefPermission>) {
329        proof!{
330            use_type_invariant(&ptr_ref);
331            assume(ptr_ref.ptr().addr() % (1usize << Self::ALIGN_BITS) == 0);
332        }
333        // [VERIFIED] SAFETY: The pointer representing a `Box` can never be NULL.
334        (unsafe { NonNull::new_unchecked(ptr_ref.inner) }, ptr_ref.tracked_perm)
335    }
336}
337
338impl<'a, T> BoxRef<'a, T> {
339    #[verifier::type_invariant]
340    spec fn type_inv(self) -> bool {
341        &&& self.inner@.addr != 0
342        &&& self.inner@.addr as int % vstd::layout::align_of::<T>() as int == 0
343        &&& self.tracked_perm@@.ptr() == self.inner
344        &&& self.tracked_perm@.inv()
345    }
346
347    pub closed spec fn ptr(self) -> *mut T {
348        self.inner
349    }
350
351    pub closed spec fn value(self) -> T {
352        self.tracked_perm@@.value()
353    }
354}
355
356} // verus!
357/// A type that represents `&'a Arc<T>`.
358///
359/// Note there is no verification-only permission field, because `ArcRef` uses `Arc` instead of a raw pointer internally.
360#[verus_verify]
361#[derive(Debug)]
362pub struct ArcRef<'a, T: 'static> {
363    inner: ManuallyDrop<Arc<T>>,
364    _marker: PhantomData<&'a Arc<T>>,
365}
366
367#[verus_verify]
368impl<T> Deref for ArcRef<'_, T> {
369    type Target = Arc<T>;
370
371    #[verus_spec(ret =>
372        ensures *ret == self@
373    )]
374    fn deref(&self) -> &Self::Target {
375        &self.inner
376    }
377}
378
379#[verus_verify]
380impl<'a, T> ArcRef<'a, T> {
381    /// Dereferences `self` to get a reference to `T` with the lifetime `'a`.
382    /// VERUS LIMITATION: The code includes a cast from `&T` to `*const T`, which is not specified yet in Verus.
383    /// This is also a nontrivial use case that extends the lifetime of the reference.
384    #[verus_verify(external_body)]
385    #[verus_spec(ret => ensures *ret == *self@)]
386    pub fn deref_target(&self) -> &'a T {
387        // SAFETY: The reference is created through `NonNullPtr::raw_as_ref`, hence
388        // the original owned pointer and target must outlive the lifetime parameter `'a`,
389        // and during `'a` no mutable references to the pointer will exist.
390        unsafe { &*(self.deref().deref() as *const T) }
391    }
392}
393
394verus! {
395
396unsafe impl<T: 'static> NonNullPtr for Arc<T> {
397    type Target = T;
398
399    type Permission = ArcPointsTo<T>;
400
401    /*
402    type Ref<'a>
403        = ArcRef<'a, T>
404    where
405        Self: 'a;*/
406    #[verifier::external_body]
407    const ALIGN_BITS: u32 = core::mem::align_of::<T>().trailing_zeros();
408
409    #[verus_spec]
410    fn into_raw(self) -> (NonNull<Self::Target>, Tracked<Self::Permission>) {
411        proof_decl!{
412            let tracked perm: ArcPointsTo<T>;
413        }
414        // let ptr = Arc::into_raw(self).cast_mut();
415        let ptr = (#[verus_spec(with => Tracked(perm))]
416        arc_into_raw(self)).cast_mut();
417        assume(ptr.addr() % (1usize << Self::ALIGN_BITS) == 0);
418
419        // [VERIFIED] SAFETY: The pointer representing an `Arc` can never be NULL.
420        (unsafe { NonNull::new_unchecked(ptr) }, Tracked(perm))
421    }
422
423    unsafe fn from_raw(
424        ptr: NonNull<Self::Target>,
425        Tracked(perm): Tracked<Self::Permission>,
426    ) -> Self {
427        let ptr = ptr.as_ptr().cast_const();
428
429        // [VERIFIED] SAFETY: The safety is upheld by the caller.
430        // unsafe { Arc::from_raw(ptr) }
431        unsafe {
432            #[verus_spec(with Tracked(perm))]
433            arc_from_raw(ptr)
434        }
435    }
436
437    open spec fn ptr_perm_match(ptr: *mut Self::Target, perm: Self::Permission) -> bool {
438        ptr == perm.ptr()
439    }
440
441    open spec fn rel_perm(self, perm: Self::Permission) -> bool {
442        perm.view_target() == *self
443    }
444
445    axiom fn lemma_align_bits_range();
446}
447
448unsafe impl<'a, T: 'static> NonNullPtrRef<'a> for Arc<T> {
449    type Ref = ArcRef<'a, T>;
450
451    type RefPermission = ArcPointsTo<T>;
452
453    open spec fn ref_perm_view_permission(perm: Self::RefPermission) -> Self::Permission {
454        perm
455    }
456
457    open spec fn ref_rel_perm(r: Self::Ref, perm: Self::RefPermission) -> bool {
458        perm.view_target() == *r@
459    }
460
461    proof fn lemma_ref_perm_inv_impl_perm_inv(perm: Self::RefPermission) {
462    }
463
464    proof fn borrow_ref_perm(tracked perm: &Self::RefPermission) -> (tracked ret:
465        Self::RefPermission) {
466        ArcPointsTo { perm: perm.perm }
467    }
468
469    proof fn borrow_perm_as_ref_perm(tracked perm: &'a Self::Permission) -> (tracked ret:
470        Self::RefPermission) {
471        ArcPointsTo { perm: perm.perm }
472    }
473
474    unsafe fn raw_as_ref(
475        raw: NonNull<Self::Target>,
476        perm: Tracked<Self::RefPermission>,
477    ) -> Self::Ref {
478        unsafe {
479            ArcRef {
480                inner: ManuallyDrop::new(
481                    #[verus_spec(with perm)]
482                    arc_from_raw(raw.as_ptr()),
483                ),
484                _marker: PhantomData,
485            }
486        }
487    }
488
489    fn ref_as_raw(ptr_ref: Self::Ref) -> (NonNull<Self::Target>, Tracked<Self::RefPermission>) {
490        NonNullPtr::into_raw(ManuallyDrop::into_inner(ptr_ref.inner))
491    }
492}
493
494impl<T> View for ArcRef<'_, T> {
495    type V = Arc<T>;
496
497    closed spec fn view(&self) -> Arc<T> {
498        self.inner@
499    }
500}
501
502} // verus!