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    // VERUS LIMITATION: Cannot use associated type with lifetime yet.
37    /*/// A type that behaves just like a shared reference to the `NonNullPtr`.
38    type Ref<'a>
39    where
40        Self: 'a;*/
41    // Verus LIMITATION: Cannot use `const` associated type yet.
42    /// The power of two of the pointer alignment.
43    // const ALIGN_BITS: u32;
44    fn ALIGN_BITS() -> u32;
45
46    /// Converts to a raw pointer.
47    ///
48    /// Each call to `into_raw` must be paired with a call to `from_raw`
49    /// in order to avoid memory leakage.
50    ///
51    /// The lower [`Self::ALIGN_BITS`] of the raw pointer is guaranteed to
52    /// be zero. In other words, the pointer is guaranteed to be aligned to
53    /// `1 << Self::ALIGN_BITS`.
54    /// VERUS LIMITATION: the #[verus_spec] attribute does not support `with` in trait yet.
55    /// SOUNDNESS: Considering also returning the Dealloc permission to ensure no memory leak.
56    fn into_raw(self) -> (ret: (NonNull<Self::Target>, Tracked<SmartPtrPointsTo<Self::Target>>))
57        ensures
58            ptr_mut_from_nonnull(ret.0) == self.ptr_mut_spec(),
59            ptr_mut_from_nonnull(ret.0) == ret.1@.ptr(),
60            ret.1@.inv(),
61            Self::match_points_to_type(ret.1@),
62    ;
63
64    /// Converts back from a raw pointer.
65    ///
66    /// # Safety
67    ///
68    /// 1. The raw pointer must have been previously returned by a call to
69    ///    `into_raw`.
70    /// 2. The raw pointer must not be used after calling `from_raw`.
71    ///
72    /// Note that the second point is a hard requirement: Even if the
73    /// resulting value has not (yet) been dropped, the pointer cannot be
74    /// used because it may break Rust aliasing rules (e.g., `Box<T>`
75    /// requires the pointer to be unique and thus _never_ aliased).
76    /// VERIFICATION DESIGN: It's easy to verify the second point by consuming the permission produced by `into_raw`,
77    /// so we can do nothing with the raw pointer because of the absence of permission.
78    /// VERUS LIMITATION: the #[verus_spec] attribute does not support `with` in trait yet.
79    /// SOUNDNESS: Considering consuming the Dealloc permission to ensure no double free.
80    unsafe fn from_raw(
81        ptr: NonNull<Self::Target>,
82        perm: Tracked<SmartPtrPointsTo<Self::Target>>,
83    ) -> (ret: Self)
84        requires
85            Self::match_points_to_type(perm@),
86            ptr_mut_from_nonnull(ptr) == perm@.ptr(),
87            perm@.inv(),
88        ensures
89            ptr_mut_from_nonnull(ptr) == ret.ptr_mut_spec(),
90    ;
91
92    // VERUS LIMITATION: Cannot use associated type with lifetime yet, will implement it as a free function for each type.
93    /*/// Obtains a shared reference to the original pointer.
94    ///
95    /// # Safety
96    ///
97    /// The original pointer must outlive the lifetime parameter `'a`, and during `'a`
98    /// no mutable references to the pointer will exist.
99    //unsafe fn raw_as_ref<'a>(raw: NonNull<Self::Target>) -> Self::Ref<'a>;*/
100    // VERUS LIMITATION: Cannot use associated type with lifetime yet, will implement it as a free function for each type.
101    /*/// Converts a shared reference to a raw pointer.
102    fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> NonNull<Self::Target>;*/
103    spec fn match_points_to_type(perm: SmartPtrPointsTo<Self::Target>) -> bool;
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
172#[verus_verify]
173unsafe impl<T: 'static> NonNullPtr for Box<T> {
174    type Target = T;
175
176    /*type Ref<'a>
177        = BoxRef<'a, T>
178    where
179        Self: 'a;*/
180    //const ALIGN_BITS: u32 = core::mem::align_of::<T>().trailing_zeros();
181    #[verifier::external_body]
182    fn ALIGN_BITS() -> u32 {
183        core::mem::align_of::<T>().trailing_zeros()
184    }
185
186    fn into_raw(self) -> (NonNull<Self::Target>, Tracked<SmartPtrPointsTo<Self::Target>>) {
187        //let ptr = Box::into_raw(self);
188        let (ptr, Tracked(points_to), Tracked(dealloc)) = box_into_raw(self);
189        proof_decl!{
190            let tracked perm = SmartPtrPointsTo::new_box_points_to(points_to, dealloc);
191        }
192        // [VERIFIED] SAFETY: The pointer representing a `Box` can never be NULL.
193        (unsafe { NonNull::new_unchecked(ptr) }, Tracked(perm))
194    }
195
196    unsafe fn from_raw(
197        ptr: NonNull<Self::Target>,
198        Tracked(perm): Tracked<SmartPtrPointsTo<Self::Target>>,
199    ) -> Self {
200        proof_decl!{
201            let tracked perm = perm.get_box_points_to().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 match_points_to_type(perm: SmartPtrPointsTo<Self::Target>) -> bool {
221        perm is Box
222    }
223
224    open spec fn ptr_mut_spec(self) -> *mut Self::Target {
225        box_pointer_spec(self)
226    }
227}
228
229pub fn box_ref_as_raw<T: 'static>(ptr_ref: BoxRef<'_, T>) -> (ret: (
230    NonNull<T>,
231    Tracked<&BoxPointsTo<T>>,
232))
233    ensures
234        ret.0 == nonnull_from_ptr_mut(ptr_ref.ptr()),
235        ret.1@.ptr().addr() != 0,
236        ret.1@.ptr().addr() as int % vstd::layout::align_of::<T>() as int == 0,
237        ret.1@.ptr() == ptr_mut_from_nonnull(ret.0),
238        ret.1@.inv(),
239{
240    proof!{
241        use_type_invariant(&ptr_ref);
242    }
243    // [VERIFIED] SAFETY: The pointer representing a `Box` can never be NULL.
244    (unsafe { NonNull::new_unchecked(ptr_ref.inner) }, ptr_ref.v_perm)
245}
246
247pub unsafe fn box_raw_as_ref<'a, T: 'static>(
248    raw: NonNull<T>,
249    perm: Tracked<&'a BoxPointsTo<T>>,
250) -> BoxRef<'a, T>
251    requires
252        perm@.ptr() == ptr_mut_from_nonnull(raw),
253        perm@.inv(),
254{
255    BoxRef { inner: raw.as_ptr(), _marker: PhantomData, v_perm: perm }
256}
257
258/// A type that represents `&'a Arc<T>`.
259#[verus_verify]
260#[derive(Debug)]
261pub struct ArcRef<'a, T: 'static> {
262    inner: ManuallyDrop<Arc<T>>,
263    _marker: PhantomData<
264        &'a Arc<T>,
265    >,
266    // Note there is no permission field here, because `ArcRef` does not use a raw pointer directly.
267}
268
269impl<'a, T> ArcRef<'a, T> {
270    #[verifier::type_invariant]
271    spec fn type_inv(self) -> bool {
272        //&&& self.ptr() == self.v_perm@.ptr()
273        //&&& self.v_perm@.inv()
274        &&& self.ptr()@.addr != 0
275        &&& self.ptr()@.addr as int % vstd::layout::align_of::<T>() as int == 0
276    }
277
278    pub open spec fn ptr(self) -> *const T {
279        arc_pointer_spec(*self.deref_as_arc_spec())
280    }
281
282    pub closed spec fn deref_as_arc_spec(&self) -> &Arc<T> {
283        &self.inner@
284    }
285
286    /// A workaround that Verus does not support implementing spec for Deref trait yet.
287    pub broadcast axiom fn arcref_deref_spec_eq(self)
288        ensures
289            #[trigger] self.deref_as_arc_spec() == #[trigger] self.deref_spec(),
290    ;
291}
292
293#[verus_verify]
294impl<T> Deref for ArcRef<'_, T> {
295    type Target = Arc<T>;
296
297    #[verus_spec]
298    fn deref(&self) -> &Self::Target {
299        &self.inner
300    }
301}
302
303#[verus_verify]
304impl<'a, T> ArcRef<'a, T> {
305    /// Dereferences `self` to get a reference to `T` with the lifetime `'a`.
306    /// VERUS LIMITATION: The code includes a cast from `&T` to `*const T`, which is not specified yet in Verus.
307    /// This is also a nontrivial use case that extends the lifetime of the reference.
308    #[verus_verify(external_body)]
309    #[verus_spec(ret => ensures *ret == *(self.deref_as_arc_spec()))]
310    pub fn deref_target(&self) -> &'a T {
311        // SAFETY: The reference is created through `NonNullPtr::raw_as_ref`, hence
312        // the original owned pointer and target must outlive the lifetime parameter `'a`,
313        // and during `'a` no mutable references to the pointer will exist.
314        unsafe { &*(self.deref().deref() as *const T) }
315    }
316}
317
318unsafe impl<T: 'static> NonNullPtr for Arc<T> {
319    type Target = T;
320
321    /*
322    type Ref<'a>
323        = ArcRef<'a, T>
324    where
325        Self: 'a;*/
326    //const ALIGN_BITS: u32 = core::mem::align_of::<T>().trailing_zeros();
327    #[verifier::external_body]
328    fn ALIGN_BITS() -> u32 {
329        core::mem::align_of::<T>().trailing_zeros()
330    }
331
332    fn into_raw(self) -> (NonNull<Self::Target>, Tracked<SmartPtrPointsTo<Self::Target>>) {
333        // let ptr = Arc::into_raw(self).cast_mut();
334        let (ptr, Tracked(points_to)) = arc_into_raw(self);
335        let ptr = ptr as *mut T;
336        proof_decl!{
337            let tracked perm = SmartPtrPointsTo::Arc(points_to);
338        }
339        // [VERIFIED] SAFETY: The pointer representing an `Arc` can never be NULL.
340        (unsafe { NonNull::new_unchecked(ptr) }, Tracked(perm))
341    }
342
343    unsafe fn from_raw(
344        ptr: NonNull<Self::Target>,
345        Tracked(perm): Tracked<SmartPtrPointsTo<Self::Target>>,
346    ) -> Self {
347        proof_decl!{
348            let tracked perm = perm.get_arc_points_to();
349        }
350        //let ptr = ptr.as_ptr().cast_const();
351        let ptr = ptr.as_ptr() as *const T;
352
353        // [VERIFIED] SAFETY: The safety is upheld by the caller.
354        // unsafe { Arc::from_raw(ptr) }
355        unsafe { arc_from_raw(ptr, Tracked(perm)) }
356    }
357
358    /*
359    unsafe fn raw_as_ref<'a>(raw: NonNull<Self::Target>) -> Self::Ref<'a> {
360        // SAFETY: The safety is upheld by the caller.
361        unsafe {
362            ArcRef {
363                inner: ManuallyDrop::new(Arc::from_raw(raw.as_ptr())),
364                _marker: PhantomData,
365            }
366        }
367    }
368
369    fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> NonNull<Self::Target> {
370        NonNullPtr::into_raw(ManuallyDrop::into_inner(ptr_ref.inner))
371    }*/
372    open spec fn match_points_to_type(perm: SmartPtrPointsTo<Self::Target>) -> bool {
373        perm is Arc
374    }
375
376    open spec fn ptr_mut_spec(self) -> *mut Self::Target {
377        arc_pointer_spec(self) as *mut Self::Target
378    }
379}
380
381pub fn arc_ref_as_raw<T: 'static>(ptr_ref: ArcRef<'_, T>) -> (ret: (
382    NonNull<T>,
383    Tracked<ArcPointsTo<T>>,
384))
385    ensures
386        ret.0 == nonnull_from_ptr_mut(ptr_ref.ptr() as *mut T),
387        ret.1@.ptr().addr() != 0,
388        ret.1@.ptr().addr() as int % vstd::layout::align_of::<T>() as int == 0,
389        ret.1@.ptr() == ptr_mut_from_nonnull(ret.0),
390        ret.1@.inv(),
391{
392    // NonNullPtr::into_raw(ManuallyDrop::into_inner(ptr_ref.inner))
393    let (ptr, Tracked(perm)) = NonNullPtr::into_raw(ManuallyDrop::into_inner(ptr_ref.inner));
394    (ptr, Tracked(perm.get_arc_points_to()))
395}
396
397pub unsafe fn arc_raw_as_ref<'a, T: 'static>(
398    raw: NonNull<T>,
399    perm: Tracked<ArcPointsTo<T>>,
400) -> (ret: ArcRef<'a, T>)
401    requires
402        perm@.ptr() == ptr_mut_from_nonnull(raw),
403        perm@.inv(),
404    ensures
405        ret.ptr() == perm@.ptr(),
406{
407    unsafe {
408        ArcRef { inner: ManuallyDrop::new(arc_from_raw(raw.as_ptr(), perm)), _marker: PhantomData }
409    }
410}
411
412} // verus!
413verus! {
414
415broadcast use group_nonnull;
416
417} // verus!