1#[cfg(creusot)]
2use crate::std::mem::{align_of_logic, size_of_logic, size_of_val_logic};
3use crate::{
4 ghost::perm::{Container, Perm},
5 prelude::*,
6};
7#[cfg(creusot)]
8use core::ptr::Pointee;
9
10#[cfg(not(feature = "std"))]
11use alloc::boxed::Box;
12
13#[logic(opaque)]
17pub fn metadata_logic<T: ?Sized>(_: *const T) -> <T as Pointee>::Metadata {
18 dead
19}
20
21#[logic(open, inline)]
41#[intrinsic("metadata_matches")]
42pub fn metadata_matches<T: ?Sized>(_value: T, _metadata: <T as Pointee>::Metadata) -> bool {
43 dead
44}
45
46#[allow(unused)]
48#[logic]
49#[intrinsic("metadata_matches_slice")]
50fn metadata_matches_slice<T>(value: [T], len: usize) -> bool {
51 pearlite! { value@.len() == len@ }
52}
53
54#[allow(unused)]
56#[logic]
57#[intrinsic("metadata_matches_str")]
58fn metadata_matches_str(value: str, len: usize) -> bool {
59 pearlite! { value@.to_bytes().len() == len@ }
60}
61
62#[allow(unused_variables)]
74#[logic(open, inline)]
75#[intrinsic("is_aligned_logic")]
76pub fn is_aligned_logic<T: ?Sized>(ptr: *const T) -> bool {
77 dead
78}
79
80#[allow(unused)]
82#[logic]
83#[intrinsic("is_aligned_logic_sized")]
84fn is_aligned_logic_sized<T>(ptr: *const T) -> bool {
85 ptr.is_aligned_to_logic(align_of_logic::<T>())
86}
87
88#[allow(unused)]
90#[logic]
91#[intrinsic("is_aligned_logic_slice")]
92fn is_aligned_logic_slice<T>(ptr: *const [T]) -> bool {
93 ptr.is_aligned_to_logic(align_of_logic::<T>())
94}
95
96#[allow(dead_code)]
107pub struct PtrDeepModel {
108 pub addr: usize,
109 runtime_metadata: usize,
110}
111
112impl<T: ?Sized> DeepModel for *mut T {
113 type DeepModelTy = PtrDeepModel;
114 #[trusted]
115 #[logic(opaque)]
116 #[ensures(result.addr == self.addr_logic())]
117 fn deep_model(self) -> Self::DeepModelTy {
118 dead
119 }
120}
121
122impl<T: ?Sized> DeepModel for *const T {
123 type DeepModelTy = PtrDeepModel;
124 #[trusted]
125 #[logic(opaque)]
126 #[ensures(result.addr == self.addr_logic())]
127 fn deep_model(self) -> Self::DeepModelTy {
128 dead
129 }
130}
131
132pub trait PointerExt<T: ?Sized>: Sized {
134 #[logic]
136 fn addr_logic(self) -> usize;
137
138 #[logic(open, sealed)]
140 fn is_null_logic(self) -> bool {
141 self.addr_logic() == 0usize
142 }
143
144 #[logic(open, sealed)]
148 fn is_aligned_to_logic(self, align: usize) -> bool {
149 pearlite! { self.addr_logic() & (align - 1usize) == 0usize }
150 }
151
152 #[logic]
158 fn is_aligned_logic(self) -> bool;
159}
160
161impl<T: ?Sized> PointerExt<T> for *const T {
162 #[logic]
163 #[cfg_attr(target_pointer_width = "16", builtin("creusot.prelude.Ptr$BW$.addr_logic_u16"))]
164 #[cfg_attr(target_pointer_width = "32", builtin("creusot.prelude.Ptr$BW$.addr_logic_u32"))]
165 #[cfg_attr(target_pointer_width = "64", builtin("creusot.prelude.Ptr$BW$.addr_logic_u64"))]
166 fn addr_logic(self) -> usize {
167 dead
168 }
169
170 #[logic(open, inline)]
171 fn is_aligned_logic(self) -> bool {
172 is_aligned_logic(self)
173 }
174}
175
176impl<T: ?Sized> PointerExt<T> for *mut T {
177 #[logic]
178 #[cfg_attr(target_pointer_width = "16", builtin("creusot.prelude.Ptr$BW$.addr_logic_u16"))]
179 #[cfg_attr(target_pointer_width = "32", builtin("creusot.prelude.Ptr$BW$.addr_logic_u32"))]
180 #[cfg_attr(target_pointer_width = "64", builtin("creusot.prelude.Ptr$BW$.addr_logic_u64"))]
181 fn addr_logic(self) -> usize {
182 dead
183 }
184
185 #[logic(open, inline)]
186 fn is_aligned_logic(self) -> bool {
187 is_aligned_logic(self)
188 }
189}
190
191pub trait SizedPointerExt<T>: PointerExt<T> {
193 #[logic]
197 #[requires(self.addr_logic()@ + offset * size_of_logic::<T>() < usize::MAX@)]
198 #[ensures(result.addr_logic()@ == self.addr_logic()@ + offset * size_of_logic::<T>())]
199 fn offset_logic(self, offset: Int) -> Self;
200
201 #[logic(law)]
203 #[ensures(self.offset_logic(0) == self)]
204 fn offset_logic_zero(self);
205
206 #[logic(law)]
208 #[ensures(self.offset_logic(offset1).offset_logic(offset2) == self.offset_logic(offset1 + offset2))]
209 fn offset_logic_assoc(self, offset1: Int, offset2: Int);
210
211 #[logic]
215 fn sub_logic(self, rhs: Self) -> Int;
216
217 #[logic(law)]
218 #[ensures(self.sub_logic(self) == 0)]
219 fn sub_logic_refl(self);
220
221 #[logic(law)]
222 #[ensures(self.offset_logic(offset).sub_logic(self) == offset)]
223 fn sub_offset_logic(self, offset: Int);
224}
225
226impl<T> SizedPointerExt<T> for *const T {
227 #[trusted]
228 #[logic(opaque)]
229 #[requires(self.addr_logic()@ + offset * size_of_logic::<T>() < usize::MAX@)]
230 #[ensures(result.addr_logic()@ == self.addr_logic()@ + offset * size_of_logic::<T>())]
231 fn offset_logic(self, offset: Int) -> Self {
232 dead
233 }
234
235 #[trusted]
236 #[logic(law)]
237 #[ensures(self.offset_logic(0) == self)]
238 fn offset_logic_zero(self) {}
239
240 #[trusted]
241 #[logic(law)]
242 #[ensures(self.offset_logic(offset1).offset_logic(offset2) == self.offset_logic(offset1 + offset2))]
243 fn offset_logic_assoc(self, offset1: Int, offset2: Int) {}
244
245 #[allow(unused)]
246 #[trusted]
247 #[logic(opaque)]
248 fn sub_logic(self, rhs: Self) -> Int {
249 dead
250 }
251
252 #[trusted]
253 #[logic(law)]
254 #[ensures(self.sub_logic(self) == 0)]
255 fn sub_logic_refl(self) {}
256
257 #[trusted]
258 #[logic(law)]
259 #[ensures(self.offset_logic(offset).sub_logic(self) == offset)]
260 fn sub_offset_logic(self, offset: Int) {}
261}
262
263pub trait SlicePointerExt<T>: PointerExt<[T]> {
268 #[logic]
270 fn thin(self) -> *const T;
271
272 #[logic]
274 fn len_logic(self) -> usize;
275
276 #[logic(law)]
278 #[ensures(self.thin() == other.thin() && self.len_logic() == other.len_logic() ==> self == other)]
279 fn slice_ptr_ext(self, other: Self);
280}
281
282impl<T> SlicePointerExt<T> for *const [T] {
283 #[logic(open, inline)]
285 fn thin(self) -> *const T {
286 self as *const T
287 }
288
289 #[logic(open, inline)]
291 fn len_logic(self) -> usize {
292 pearlite! { metadata_logic(self) }
293 }
294
295 #[trusted]
297 #[logic(law)]
298 #[ensures(self.thin() == other.thin() && self.len_logic() == other.len_logic() ==> self == other)]
299 fn slice_ptr_ext(self, other: Self) {}
300}
301
302extern_spec! {
303 impl<T: ?Sized> *const T {
304 #[check(ghost)]
305 #[ensures(result == self.addr_logic())]
306 fn addr(self) -> usize;
307
308 #[check(ghost)]
309 #[ensures(result == self.is_null_logic())]
310 fn is_null(self) -> bool;
311
312 #[check(ghost)]
313 #[erasure]
314 #[ensures(result == self as _)]
315 fn cast<U>(self) -> *const U {
316 self as _
317 }
318
319 #[check(terminates)]
320 #[erasure]
321 #[ensures(result == self.is_aligned_logic())]
322 fn is_aligned(self) -> bool
323 where T: Sized,
324 {
325 self.is_aligned_to(core::mem::align_of::<T>())
326 }
327
328 #[check(ghost)]
329 #[erasure]
330 #[bitwise_proof]
331 #[requires(align != 0usize && align & (align - 1usize) == 0usize)]
332 #[ensures(result == self.is_aligned_to_logic(align))]
333 fn is_aligned_to(self, align: usize) -> bool
334 {
335 if !align.is_power_of_two() {
336 ::core::panic::panic_2021!("is_aligned_to: align is not a power-of-two");
337 }
338 self.addr() & (align - 1) == 0
339 }
340 }
341
342 impl<T: ?Sized> *mut T {
343 #[check(ghost)]
344 #[ensures(result == self.addr_logic())]
345 fn addr(self) -> usize;
346
347 #[check(ghost)]
348 #[ensures(result == self.is_null_logic())]
349 fn is_null(self) -> bool;
350
351 #[check(ghost)]
352 #[erasure]
353 #[ensures(result == self as _)]
354 fn cast<U>(self) -> *mut U {
355 self as _
356 }
357
358 #[check(terminates)]
359 #[erasure]
360 #[ensures(result == self.is_aligned_logic())]
361 fn is_aligned(self) -> bool
362 where T: Sized,
363 {
364 self.is_aligned_to(core::mem::align_of::<T>())
365 }
366
367 #[check(ghost)]
368 #[erasure]
369 #[bitwise_proof]
370 #[requires(align != 0usize && align & (align - 1usize) == 0usize)]
371 #[ensures(result == self.is_aligned_to_logic(align))]
372 fn is_aligned_to(self, align: usize) -> bool
373 {
374 if !align.is_power_of_two() {
375 ::core::panic::panic_2021!("is_aligned_to: align is not a power-of-two");
376 }
377 self.addr() & (align - 1) == 0
378 }
379 }
380
381 impl<T> *const [T] {
382 #[ensures(result == metadata_logic(self))]
383 fn len(self) -> usize;
384 }
385
386 impl<T> *mut [T] {
387 #[ensures(result == metadata_logic(self))]
388 fn len(self) -> usize;
389 }
390
391 mod core {
392 mod ptr {
393 #[check(ghost)]
394 #[ensures(result.is_null_logic())]
395 fn null<T>() -> *const T
396 where
397 T: core::ptr::Thin + ?Sized;
398
399 #[check(ghost)]
400 #[ensures(result.is_null_logic())]
401 fn null_mut<T>() -> *mut T
402 where
403 T: core::ptr::Thin + ?Sized;
404
405 #[check(ghost)]
406 #[ensures(result == (p.addr_logic() == q.addr_logic()))]
407 fn addr_eq<T, U>(p: *const T, q: *const U) -> bool
408 where
409 T: ?Sized, U: ?Sized;
410
411 #[check(ghost)]
412 #[ensures(result == metadata_logic(ptr))]
413 fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata;
414
415 #[check(ghost)]
418 #[ensures(false)]
419 unsafe fn read_volatile<T>(src: *const T) -> T;
420
421 #[ensures(result as *const T == data && result.len_logic() == len)]
422 fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T];
423
424 #[ensures(result as *mut T == data && result.len_logic() == len)]
425 fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T];
426 }
427 }
428
429 impl<T> Clone for *mut T {
430 #[check(ghost)]
431 #[ensures(result == *self)]
432 fn clone(&self) -> *mut T {
433 *self
434 }
435 }
436
437 impl<T> Clone for *const T {
438 #[check(ghost)]
439 #[ensures(result == *self)]
440 fn clone(&self) -> *const T {
441 *self
442 }
443 }
444}
445
446impl<T: ?Sized> Container for *const T {
447 type Value = T;
448
449 #[logic(open, inline)]
450 fn is_disjoint(&self, self_val: &T, other: &Self, other_val: &T) -> bool {
451 pearlite! {
452 size_of_val_logic(*self_val) != 0 && size_of_val_logic(*other_val) != 0 ==>
453 self.addr_logic() != other.addr_logic()
454 }
455 }
456}
457
458impl<T: ?Sized> Invariant for Perm<*const T> {
459 #[logic(open, prophetic)]
460 fn invariant(self) -> bool {
461 pearlite! {
462 !self.ward().is_null_logic()
463 && self.ptr_is_aligned_opaque()
464 && metadata_matches(*self.val(), metadata_logic(*self.ward()))
465 && size_of_val_logic(*self.val()) <= isize::MAX@
467 && self.ward().addr_logic()@ + size_of_val_logic(*self.val()) <= usize::MAX@
470 && inv(self.val())
471 }
472 }
473}
474
475impl<T: ?Sized> Perm<*const T> {
476 #[check(terminates)] #[ensures(*result.1.ward() == result.0 && *result.1.val() == v)]
480 pub fn new(v: T) -> (*mut T, Ghost<Box<Perm<*const T>>>)
481 where
482 T: Sized,
483 {
484 Self::from_box(Box::new(v))
485 }
486
487 #[trusted]
489 #[check(terminates)] #[ensures(*result.1.ward() == result.0 && *result.1.val() == *val)]
491 #[erasure(Box::into_raw)]
492 pub fn from_box(val: Box<T>) -> (*mut T, Ghost<Box<Perm<*const T>>>) {
493 (Box::into_raw(val), Ghost::conjure())
494 }
495
496 #[trusted]
508 #[check(terminates)] #[ensures(*result.1.ward() == result.0)]
510 #[ensures(*result.1.val() == *r)]
511 #[intrinsic("perm_from_ref")]
512 pub fn from_ref(r: &T) -> (*const T, Ghost<&Perm<*const T>>) {
513 (r, Ghost::conjure())
514 }
515
516 #[trusted]
528 #[check(terminates)] #[ensures(*result.1.ward() == result.0)]
530 #[ensures(*result.1.val() == *r)]
531 #[ensures(*(^result.1.inner_logic()).val() == ^r)]
532 #[intrinsic("perm_from_mut")]
533 pub fn from_mut(r: &mut T) -> (*mut T, Ghost<&mut Perm<*const T>>) {
534 (r, Ghost::conjure())
535 }
536
537 #[trusted]
556 #[check(terminates)]
557 #[requires(ptr == *own.ward())]
558 #[ensures(*result == *own.val())]
559 #[allow(unused_variables)]
560 #[intrinsic("perm_as_ref")]
561 pub unsafe fn as_ref(ptr: *const T, own: Ghost<&Perm<*const T>>) -> &T {
562 unsafe { &*ptr }
563 }
564
565 #[trusted]
584 #[check(terminates)]
585 #[allow(unused_variables)]
586 #[requires(ptr as *const T == *own.ward())]
587 #[ensures(*result == *own.val())]
588 #[ensures((^own).ward() == own.ward())]
589 #[ensures(*(^own).val() == ^result)]
590 #[intrinsic("perm_as_mut")]
591 pub unsafe fn as_mut(ptr: *mut T, own: Ghost<&mut Perm<*const T>>) -> &mut T {
592 unsafe { &mut *ptr }
593 }
594
595 #[trusted]
604 #[check(terminates)]
605 #[requires(ptr as *const T == *own.ward())]
606 #[ensures(*result == *own.val())]
607 #[allow(unused_variables)]
608 #[erasure(Box::from_raw)]
609 pub unsafe fn to_box(ptr: *mut T, own: Ghost<Box<Perm<*const T>>>) -> Box<T> {
610 unsafe { Box::from_raw(ptr) }
611 }
612
613 #[check(terminates)]
622 #[requires(ptr as *const T == *own.ward())]
623 pub unsafe fn drop(ptr: *mut T, own: Ghost<Box<Perm<*const T>>>) {
624 let _ = unsafe { Self::to_box(ptr, own) };
625 }
626
627 #[check(ghost)]
629 #[ensures(self.ward().is_aligned_logic())]
630 pub fn ptr_is_aligned_lemma(&self) {}
631
632 #[logic(open(self))]
636 pub fn ptr_is_aligned_opaque(self) -> bool {
637 self.ward().is_aligned_logic()
638 }
639}