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