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_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!