Skip to content

Commit 1ddea06

Browse files
authored
Add permissions in BoxRef (#256)
1 parent 94c89ef commit 1ddea06

File tree

2 files changed

+176
-32
lines changed

2 files changed

+176
-32
lines changed

ostd/src/sync/rcu/non_null/mod.rs

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,16 @@ pub unsafe trait NonNullPtr: Sized +'static {
107107
pub struct BoxRef<'a, T> {
108108
inner: *mut T,
109109
_marker: PhantomData<&'a T>,
110+
v_perm: Tracked<&'a BoxPointsTo<T>>,
110111
}
111112

112113
impl<'a, T> BoxRef<'a, T> {
113114
#[verifier::type_invariant]
114115
spec fn type_inv(self) -> bool {
115116
&&& self.inner@.addr != 0
116117
&&& self.inner@.addr as int % vstd::layout::align_of::<T>() as int == 0
118+
&&& self.v_perm@.ptr() == self.inner
119+
&&& self.v_perm@.inv()
117120
}
118121

119122
pub closed spec fn ptr(self) -> *mut T {
@@ -165,15 +168,15 @@ unsafe impl<T: 'static> NonNullPtr for Box<T> {
165168
//let ptr = Box::into_raw(self);
166169
let (ptr, Tracked(points_to), Tracked(dealloc)) = box_into_raw(self);
167170
proof_decl!{
168-
let tracked perm = SmartPtrPointsTo::Box(PointsTowithDealloc::new(points_to, dealloc));
171+
let tracked perm = SmartPtrPointsTo::new_box_points_to(points_to, dealloc);
169172
}
170173
// [VERIFIED] SAFETY: The pointer representing a `Box` can never be NULL.
171174
(unsafe { NonNull::new_unchecked(ptr) }, Tracked(perm))
172175
}
173176

174177
unsafe fn from_raw(ptr: NonNull<Self::Target>, Tracked(perm): Tracked<SmartPtrPointsTo<Self::Target>>) -> Self {
175178
proof_decl!{
176-
let tracked perm = perm.get_box_points_to();
179+
let tracked perm = perm.get_box_points_to().tracked_get_perm();
177180
}
178181
let ptr = ptr.as_ptr();
179182

@@ -182,16 +185,14 @@ unsafe impl<T: 'static> NonNullPtr for Box<T> {
182185
unsafe { box_from_raw(ptr, Tracked(perm.points_to), Tracked(perm.dealloc)) }
183186
}
184187

185-
/*#[verifier::external_body]
186-
unsafe fn raw_as_ref<'a>(raw: NonNull<Self::Target>) -> Self::Ref<'a> {
188+
/*unsafe fn raw_as_ref<'a>(raw: NonNull<Self::Target>) -> Self::Ref<'a> {
187189
BoxRef {
188190
inner: raw.as_ptr(),
189191
_marker: PhantomData,
190192
}
191193
}*/
192194

193-
/*#[verifier::external_body]
194-
fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> NonNull<Self::Target> {
195+
/*fn ref_as_raw(ptr_ref: Self::Ref<'_>) -> NonNull<Self::Target> {
195196
// SAFETY: The pointer representing a `Box` can never be NULL.
196197
unsafe { NonNull::new_unchecked(ptr_ref.inner) }
197198
}*/
@@ -201,18 +202,34 @@ unsafe impl<T: 'static> NonNullPtr for Box<T> {
201202
}
202203
}
203204

204-
#[verifier::external_body]
205-
pub fn box_ref_as_raw<T: 'static>(ptr_ref: BoxRef<'_ ,T>) -> NonNull<T>
206-
returns
207-
nonnull_from_ptr_mut(ptr_ref.ptr()),
205+
pub fn box_ref_as_raw<T: 'static>(ptr_ref: BoxRef<'_ ,T>) -> (ret:(NonNull<T>, Tracked<&BoxPointsTo<T>>))
206+
ensures
207+
ret.0 == nonnull_from_ptr_mut(ptr_ref.ptr()),
208+
ret.1@.ptr().addr() != 0,
209+
ret.1@.ptr().addr() as int % vstd::layout::align_of::<T>() as int == 0,
210+
ret.1@.ptr() == ptr_mut_from_nonull(ret.0),
211+
ret.1@.inv(),
212+
208213
{
209214
proof!{
210215
use_type_invariant(&ptr_ref);
211216
}
212217
// [VERIFIED] SAFETY: The pointer representing a `Box` can never be NULL.
213-
unsafe { NonNull::new_unchecked(ptr_ref.inner) }
218+
(unsafe { NonNull::new_unchecked(ptr_ref.inner) }, ptr_ref.v_perm)
214219
}
215220

221+
pub unsafe fn box_raw_as_ref<'a, T: 'static>(raw: NonNull<T>, perm: Tracked<&'a BoxPointsTo<T>>) -> BoxRef<'a, T>
222+
requires
223+
perm@.ptr() == ptr_mut_from_nonull(raw),
224+
perm@.inv(),
225+
{
226+
BoxRef {
227+
inner: raw.as_ptr(),
228+
_marker: PhantomData,
229+
v_perm: perm,
230+
}
231+
}
232+
216233
/// A type that represents `&'a Arc<T>`.
217234
#[verus_verify]
218235
#[derive(Debug)]

vstd_extra/src/external/smart_ptr.rs

Lines changed: 148 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,117 @@ use vstd::layout::valid_layout;
55
use vstd::prelude::*;
66
use vstd::raw_ptr::*;
77

8+
// A unified interface for the raw ptr permission returned by `into_raw` methods of smart pointers like `Box` and `Arc`.
89
verus! {
910

1011
// The permssion to access memory given by the `into_raw` methods of smart pointers like `Box` and `Arc`.
1112
/// For Box<T>, the `into_raw` method gives you the ownership of the memory
12-
pub type BoxPointsTo<T> = PointsTowithDealloc<T>;
13+
pub tracked struct BoxPointsTo<T> {
14+
pub perm: PointsTowithDealloc<T>,
15+
}
1316

1417
/// For Arc<T>, the `into_raw` method gives shared access to the memory, and the reference count is not decreased,
1518
/// so the value will not be deallocated until we convert back to Arc<T> and drop it.
1619
/// See https://doc.rust-lang.org/src/alloc/sync.rs.html#1480.
17-
pub type ArcPointsTo<T> = &'static PointsTo<T>;
20+
pub tracked struct ArcPointsTo<T: 'static> {
21+
pub perm: &'static PointsTo<T>,
22+
}
1823

1924
pub tracked enum SmartPtrPointsTo<T: 'static> {
2025
Box(BoxPointsTo<T>),
2126
Arc(ArcPointsTo<T>),
2227
}
2328

29+
impl<T> BoxPointsTo<T> {
30+
pub open spec fn perm(self) -> PointsTowithDealloc<T> {
31+
self.perm
32+
}
33+
34+
pub open spec fn ptr(self) -> *mut T {
35+
self.perm.ptr()
36+
}
37+
38+
pub open spec fn addr(self) -> usize {
39+
self.ptr().addr()
40+
}
41+
42+
pub open spec fn is_uninit(self) -> bool {
43+
self.perm.is_uninit()
44+
}
45+
46+
pub open spec fn is_init(self) -> bool {
47+
self.perm.is_init()
48+
}
49+
50+
pub proof fn tracked_get_perm(tracked self) -> (tracked ret: PointsTowithDealloc<T>)
51+
returns
52+
self.perm,
53+
{
54+
self.perm
55+
}
56+
57+
pub proof fn tracked_borrow_perm<'a>(tracked &'a self) -> (tracked ret: &'a PointsTowithDealloc<
58+
T,
59+
>)
60+
ensures
61+
ret == &self.perm,
62+
returns
63+
&self.perm,
64+
{
65+
&self.perm
66+
}
67+
}
68+
69+
impl<T> ArcPointsTo<T> {
70+
pub open spec fn perm(self) -> &'static PointsTo<T> {
71+
self.perm
72+
}
73+
74+
pub open spec fn ptr(self) -> *mut T {
75+
self.perm.ptr()
76+
}
77+
78+
pub open spec fn addr(self) -> usize {
79+
self.ptr().addr()
80+
}
81+
82+
pub open spec fn is_uninit(self) -> bool {
83+
self.perm.is_uninit()
84+
}
85+
86+
pub open spec fn is_init(self) -> bool {
87+
self.perm.is_init()
88+
}
89+
90+
pub proof fn tracked_get_perm(tracked self) -> (tracked ret: &'static PointsTo<T>)
91+
returns
92+
self.perm,
93+
{
94+
self.perm
95+
}
96+
}
97+
98+
impl<T> Inv for BoxPointsTo<T> {
99+
open spec fn inv(self) -> bool {
100+
&&& self.perm.inv()
101+
&&& self.perm.dealloc_aligned()
102+
&&& self.is_init()
103+
}
104+
}
105+
106+
impl<T> Inv for ArcPointsTo<T> {
107+
open spec fn inv(self) -> bool {
108+
&&& self.addr() != 0
109+
&&& self.addr() as int % vstd::layout::align_of::<T>() as int == 0
110+
&&& self.is_init()
111+
}
112+
}
113+
24114
impl<T> Inv for SmartPtrPointsTo<T> {
25115
open spec fn inv(self) -> bool {
26116
match self {
27-
SmartPtrPointsTo::Box(b) => {
28-
&&& b.inv()
29-
&&& b.dealloc_aligned()
30-
&&& b.is_init()
31-
},
32-
SmartPtrPointsTo::Arc(a) => {
33-
&&& a.ptr().addr() != 0
34-
&&& a.ptr().addr() as int % vstd::layout::align_of::<T>() as int == 0
35-
&&& a.is_init()
36-
},
117+
SmartPtrPointsTo::Box(b) => { b.inv() },
118+
SmartPtrPointsTo::Arc(a) => { a.inv() },
37119
}
38120
}
39121
}
@@ -70,11 +152,10 @@ impl<T> SmartPtrPointsTo<T> {
70152
returns
71153
self->Box_0,
72154
{
73-
let tracked option_perm = match self {
74-
SmartPtrPointsTo::Box(p) => Some(p),
75-
_ => None,
76-
};
77-
option_perm.tracked_unwrap()
155+
match self {
156+
SmartPtrPointsTo::Box(p) => p,
157+
_ => proof_from_false(),
158+
}
78159
}
79160

80161
pub proof fn get_arc_points_to(tracked self) -> (tracked ret: ArcPointsTo<T>)
@@ -83,11 +164,57 @@ impl<T> SmartPtrPointsTo<T> {
83164
returns
84165
self->Arc_0,
85166
{
86-
let tracked option_perm = match self {
87-
SmartPtrPointsTo::Arc(p) => Some(p),
88-
_ => None,
167+
match self {
168+
SmartPtrPointsTo::Arc(p) => p,
169+
_ => proof_from_false(),
170+
}
171+
}
172+
173+
pub proof fn new_box_points_to(
174+
tracked points_to: PointsTo<T>,
175+
tracked dealloc: Option<Dealloc>,
176+
) -> (tracked ret: SmartPtrPointsTo<T>)
177+
requires
178+
points_to.is_init(),
179+
match dealloc {
180+
Some(dealloc) => {
181+
&&& vstd::layout::size_of::<T>() > 0
182+
&&& valid_layout(size_of::<T>(), dealloc.align() as usize)
183+
&&& points_to.ptr().addr() == dealloc.addr()
184+
&&& points_to.ptr()@.provenance == dealloc.provenance()
185+
&&& dealloc.size() == vstd::layout::size_of::<T>()
186+
&&& dealloc.align() == vstd::layout::align_of::<T>()
187+
},
188+
None => { vstd::layout::size_of::<T>() == 0 },
189+
},
190+
ensures
191+
ret.inv(),
192+
ret is Box,
193+
returns
194+
(SmartPtrPointsTo::Box(
195+
BoxPointsTo { perm: PointsTowithDealloc { points_to, dealloc } },
196+
)),
197+
{
198+
let tracked box_points_to = BoxPointsTo {
199+
perm: PointsTowithDealloc::new(points_to, dealloc),
89200
};
90-
option_perm.tracked_unwrap()
201+
SmartPtrPointsTo::Box(box_points_to)
202+
}
203+
204+
pub proof fn new_arc_points_to(tracked points_to: &'static PointsTo<T>) -> (tracked ret:
205+
SmartPtrPointsTo<T>)
206+
requires
207+
points_to.is_init(),
208+
points_to.ptr().addr() != 0,
209+
points_to.ptr().addr() as int % vstd::layout::align_of::<T>() as int == 0,
210+
ensures
211+
ret.inv(),
212+
ret is Arc,
213+
returns
214+
(SmartPtrPointsTo::Arc(ArcPointsTo { perm: points_to })),
215+
{
216+
let tracked arc_points_to = ArcPointsTo { perm: points_to };
217+
SmartPtrPointsTo::Arc(arc_points_to)
91218
}
92219
}
93220

0 commit comments

Comments
 (0)