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