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!