vstd/
raw_ptr.rs

1//! Tools and reasoning principles for [raw pointers](https://doc.rust-lang.org/std/primitive.pointer.html).
2//! The tools here are meant to address "real Rust pointers, including all their subtleties on the Rust Abstract Machine,
3//! to the largest extent that is reasonable."
4//!
5//! For a gentler introduction to some of the concepts here, see [`PPtr`](crate::simple_pptr), which uses a much-simplified pointer model.
6//!
7//! ### Pointer model
8//!
9//! A pointer consists of an address (`ptr.addr()` or `ptr as usize`), a provenance `ptr@.provenance`,
10//! and metadata `ptr@.metadata` (which is trivial except for pointers to non-sized types).
11//! Note that in spec code, pointer equality requires *all 3* to be equal, whereas runtime equality (eq)
12//! only compares addresses and metadata.
13//!
14//! `*mut T` vs. `*const T` do not have any semantic difference and Verus treats them as the same;
15//! they can be seamlessly cast to and fro.
16#![allow(unused_imports)]
17use super::layout::*;
18use super::prelude::*;
19
20verus! {
21
22//////////////////////////////////////
23// Define a model of Ptrs and PointsTo
24// Notes on mutability:
25//
26//  - Unique vs shared ownership in Verus is always determined
27//    via the PointsTo ghost tracked object.
28//
29//  - Thus, there is effectively no difference between *mut T and *const T,
30//    so we encode both of these in the same way.
31//    (In VIR, we distinguish these via a decoration.)
32//    Thus we can cast freely between them both in spec and exec code.
33//
34//  - This is consistent with Rust's operational semantics;
35//    casting between *mut T and *const T has no operational meaning.
36//
37//  - When creating a pointer from a reference, the mutability
38//    of the pointer *does* have an effect because it determines
39//    what kind of "tag" the pointer gets, i.e., whether that
40//    tag is readonly or not. In our model here, this tag is folded
41//    into the provenance.
42//
43/// Provenance
44///
45/// A full model of provenance is given by formalisms such as "Stacked Borrows"
46/// or "Tree Borrows."
47///
48/// None of these models are finalized, nor has Rust committed to them.
49/// Rust's recent [RFC on provenance](https://rust-lang.github.io/rfcs/3559-rust-has-provenance.html)
50/// simply details that there *is* some concept of provenance.
51///
52/// Our model here, likewise, simply declares `Provenance` as an
53/// abstract type.
54///
55/// MiniRust currently declares a pointer has an `Option<Provenance>`;
56/// the model here gives provenance a special "null" value instead
57/// of using an option.
58///
59/// More reading for reference:
60/// * [https://doc.rust-lang.org/std/ptr/](https://doc.rust-lang.org/std/ptr/)
61/// * [https://github.com/minirust/minirust/tree/master](https://github.com/minirust/minirust/tree/master)
62#[verifier::external_body]
63pub ghost struct Provenance {}
64
65impl Provenance {
66    /// The provenance of the null ptr (or really, "no provenance")
67    pub uninterp spec fn null() -> Self;
68}
69
70/// Metadata
71///
72/// For thin pointers (i.e., when T: Sized), the metadata is `()`.
73/// For slices (`[T]`) and `str`, the metadata is `usize`.
74/// For `dyn` types (not supported by Verus at the time of writing), this type is also nontrivial.
75///
76/// See: <https://doc.rust-lang.org/std/ptr/trait.Pointee.html>
77#[cfg(verus_keep_ghost)]
78pub type Metadata<T> = <T as core::ptr::Pointee>::Metadata;
79
80#[cfg(not(verus_keep_ghost))]
81pub struct FakeMetadata<T: ?Sized> {
82    t: *mut T,
83}
84
85#[cfg(not(verus_keep_ghost))]
86pub type Metadata<T> = FakeMetadata<T>;
87
88/// Model of a pointer `*mut T` or `*const T` in Rust's abstract machine.
89/// In addition to the address, each pointer has its corresponding provenance and metadata.
90#[cfg(verus_keep_ghost)]
91pub ghost struct PtrData<T: core::marker::PointeeSized> {
92    pub addr: usize,
93    pub provenance: Provenance,
94    pub metadata: Metadata<T>,
95}
96
97/**
98Permission to access possibly-initialized, _typed_ memory.
99
100The associated pointer ([`points_to.ptr()`](PointsTo::ptr)) is always a valid pointer for constructing
101a reference to the underlying data. That means it's always aligned to its type
102([`is_aligned`](PointsTo::is_nonnull)) and is non-null ([`is_nonnull`](PointsTo::is_nonnull)).
103
104### Notes
105
106The invariants on a `PointsTo` are a little more restrictive than is necessary for all
107Rust operations you might want to do. For example:
108
1091. With a null pointer to a ZST, Rust lets you read and write (though not take a reference).
110
111```
112#[derive(Copy, Clone)]
113#[repr(align(64))]
114struct X { }
115
116fn zst_test() {
117    let x_ptr: *mut X = std::ptr::null_mut();
118
119    let x = unsafe { *x_ptr };  // allowed
120
121    let x = X { };
122    unsafe { *x_ptr = x; }      // allowed
123
124    let j = unsafe { &*x_ptr }; // not allowed because ptr is null
125}
126```
127
1282. The [`std::ptr::read_unaligned`] and [`std::ptr::write_unaligned`] don't require the pointer
129   to be aligned.
130
131Currently, these use-cases aren't supported because `PointsTo` enforces both non-nullness
132and alignment.
133*/
134
135// ptr |--> Init(v) means:
136//   bytes in this memory are consistent with value v
137//   and we have all the ghost state associated with type V
138//
139// ptr |--> Uninit means:
140//   no knowledge about what's in memory
141//   (to be pedantic, the bytes might be initialized in rust's abstract machine,
142//   but we don't know so we have to pretend they're uninitialized)
143#[verifier::external_body]
144#[verifier::accept_recursive_types(T)]
145pub tracked struct PointsTo<T> {
146    phantom: core::marker::PhantomData<T>,
147    no_copy: NoCopy,
148}
149
150//#[verifier::external_body]
151//#[verifier::accept_recursive_types(T)]
152//pub tracked struct PointsToBytes<T> {
153//    phantom: core::marker::PhantomData<T>,
154//    no_copy: NoCopy,
155//}
156/// Represents (typed) contents of memory.
157// Don't use std Option here in order to avoid circular dependency issues
158// with verifying the standard library.
159// (Also, using our own enum here lets us have more meaningful
160// variant names like Uninit/Init.)
161#[verifier::accept_recursive_types(T)]
162pub ghost enum MemContents<T> {
163    /// Represents uninitialized memory.
164    Uninit,
165    /// Represents initialized memory with the given value of type `T`.
166    Init(T),
167}
168
169/// Data associated with a `PointsTo` permission.
170/// We keep track of both the pointer and the (potentially uninitialized) value
171/// it points to.
172///
173/// If `opt_value` is `Init(T)`, this signifies that `ptr` points to initialized memory,
174/// and the value of `opt_value` is consistent with the bytes `ptr` points to,
175/// We also have all the ghost state associated with type `T`.
176///
177/// If `opt_value` is `Uninit`, then we have no knowledge about what's in memory,
178/// and we assume `ptr` points to uninitialized memory.
179/// (To be pedantic, the bytes might be initialized in Rust's abstract machine,
180///  but we don't know, so we have to pretend they're uninitialized.)
181pub ghost struct PointsToData<T> {
182    pub ptr: *mut T,
183    pub opt_value: MemContents<T>,
184}
185
186#[cfg(verus_keep_ghost)]
187impl<T: core::marker::PointeeSized> View for *mut T {
188    type V = PtrData<T>;
189
190    uninterp spec fn view(&self) -> Self::V;
191}
192
193/// Compares the address and metadata of two pointers.
194///
195/// Note that this does NOT compare provenance, which does not exist in the runtime
196/// pointer representation (i.e., it only exists in the Rust abstract machine).
197#[cfg(verus_keep_ghost)]
198pub assume_specification<T: core::marker::PointeeSized>[ <*mut T as PartialEq<*mut T>>::eq ](
199    x: &*mut T,
200    y: &*mut T,
201) -> (res: bool)
202    ensures
203        res <==> (x@.addr == y@.addr) && (x@.metadata == y@.metadata),
204;
205
206#[cfg(verus_keep_ghost)]
207impl<T: core::marker::PointeeSized> View for *const T {
208    type V = PtrData<T>;
209
210    #[verifier::inline]
211    open spec fn view(&self) -> Self::V {
212        (*self as *mut T).view()
213    }
214}
215
216/// Compares the address and metadata of two pointers.
217///
218/// Note that this does NOT compare provenance, which does not exist in the runtime
219/// pointer representation (i.e., it only exists in the Rust abstract machine).
220#[cfg(verus_keep_ghost)]
221pub assume_specification<T: core::marker::PointeeSized>[ <*const T as PartialEq<*const T>>::eq ](
222    x: &*const T,
223    y: &*const T,
224) -> (res: bool)
225    ensures
226        res <==> (x@.addr == y@.addr) && (x@.metadata == y@.metadata),
227;
228
229impl<T> View for PointsTo<T> {
230    type V = PointsToData<T>;
231
232    uninterp spec fn view(&self) -> Self::V;
233}
234
235impl<T> PointsTo<T> {
236    /// The pointer that this permission is associated with.
237    #[verifier::inline]
238    pub open spec fn ptr(&self) -> *mut T {
239        self.view().ptr
240    }
241
242    /// The (possibly uninitialized) memory that this permission gives access to.
243    #[verifier::inline]
244    pub open spec fn opt_value(&self) -> MemContents<T> {
245        self.view().opt_value
246    }
247
248    /// Returns `true` if the permission's associated memory is initialized.
249    #[verifier::inline]
250    pub open spec fn is_init(&self) -> bool {
251        self.opt_value().is_init()
252    }
253
254    /// Returns `true` if the permission's associated memory is uninitialized.
255    #[verifier::inline]
256    pub open spec fn is_uninit(&self) -> bool {
257        self.opt_value().is_uninit()
258    }
259
260    /// If the permission's associated memory is initialized,
261    /// returns the value that the pointer points to.
262    /// Otherwise, the result is meaningless.
263    #[verifier::inline]
264    pub open spec fn value(&self) -> T
265        recommends
266            self.is_init(),
267    {
268        self.opt_value().value()
269    }
270
271    /// Guarantee that the `PointsTo` points to a non-null address.
272    pub axiom fn is_nonnull(tracked &self)
273        ensures
274            self@.ptr@.addr != 0,
275    ;
276
277    /// Guarantee that the `PointsTo` points to an aligned address.
278    pub axiom fn is_aligned(tracked &self)
279        ensures
280            self@.ptr@.addr as nat % align_of::<T>() == 0,
281    ;
282
283    /// "Forgets" about the value stored behind the pointer.
284    /// Updates the `PointsTo` value to [`MemContents::Uninit`](MemContents::Uninit).
285    /// Note that this is a `proof` function, i.e.,
286    /// it is operationally a no-op in executable code, even on the Rust Abstract Machine.
287    /// Only the proof-code representation changes.
288    pub axiom fn leak_contents(tracked &mut self)
289        ensures
290            self.ptr() == old(self).ptr(),
291            self.is_uninit(),
292    ;
293
294    /// Guarantees that the memory ranges associated with two distinct, non-ZST permissions will not overlap,
295    /// since you cannot have two permissions to the same memory.
296    /// (`self` is an &mut reference to enforce distinctness,
297    /// so you cannot pass the same PointsTo as both arguments.)
298    /// Since both S and T are non-zero-sized, this implies the pointers have distinct addresses.
299    ///
300    /// Note: If either S or T is zero-sized, we get disjointness "for free" without having to call this axiom,
301    /// since the empty memory range corresponding to a ZST cannot possibly intersect with any other memory.
302    /// However, note that if one type is a ZST and the other is a non-ZST,
303    /// the disjointness definition as stated here here does not hold,
304    /// since the ZST pointer could be in the middle of the non-ZST's range.
305    pub axiom fn is_disjoint<S>(tracked &mut self, tracked other: &PointsTo<S>)
306        requires
307            size_of::<T>() != 0,
308            size_of::<S>() != 0,
309        ensures
310            *old(self) == *self,
311            self.ptr() as int + size_of::<T>() <= other.ptr() as int || other.ptr() as int
312                + size_of::<S>() <= self.ptr() as int,
313    ;
314}
315
316impl<T> MemContents<T> {
317    /// Returns `true` if it is a [`MemContents::Init`] value.
318    #[verifier::inline]
319    pub open spec fn is_init(&self) -> bool {
320        self is Init
321    }
322
323    /// Returns `true` if it is a [`MemContents::Uninit`] value.
324    #[verifier::inline]
325    pub open spec fn is_uninit(&self) -> bool {
326        self is Uninit
327    }
328
329    /// If it is a [`MemContents::Init`] value, returns the value.
330    /// Otherwise, the return value is meaningless.
331    #[verifier::inline]
332    pub open spec fn value(&self) -> T
333        recommends
334            self is Init,
335    {
336        self->0
337    }
338}
339
340//////////////////////////////////////
341// Inverse functions:
342// Pointers are equivalent to their model
343/// Constructs a pointer from its underlying model.
344pub uninterp spec fn ptr_mut_from_data<T: core::marker::PointeeSized>(data: PtrData<T>) -> *mut T;
345
346/// Constructs a pointer from its underlying model.
347/// Since `*mut T` and `*const T` are [semantically the same](https://verus-lang.github.io/verus/verusdoc/vstd/raw_ptr/index.html#pointer-model),
348/// we can define this operation in terms of the operation on `*mut T`.
349#[verifier::inline]
350pub open spec fn ptr_from_data<T: core::marker::PointeeSized>(data: PtrData<T>) -> *const T {
351    ptr_mut_from_data(data) as *const T
352}
353
354/// The view of a pointer constructed from `data: PtrData` should be exactly that data.
355pub broadcast axiom fn axiom_ptr_mut_from_data<T: ?Sized>(data: PtrData<T>)
356    ensures
357        (#[trigger] ptr_mut_from_data::<T>(data))@ == data,
358;
359
360// Equiv to ptr_mut_from_data, but named differently to avoid trigger issues
361// Only use for ptrs_mut_eq
362#[doc(hidden)]
363pub uninterp spec fn view_reverse_for_eq<T: ?Sized>(data: PtrData<T>) -> *mut T;
364
365/// Implies that `a@ == b@ ==> a == b`.
366pub broadcast axiom fn ptrs_mut_eq<T: ?Sized>(a: *mut T)
367    ensures
368        view_reverse_for_eq::<T>(#[trigger] a@) == a,
369;
370
371// We do the same trick again, but specialized for Sized types. This improves automation.
372// Specifically, this makes it easier to prove `a == b` without having to explicitly write
373// `a@.metadata == b@.metadata`, since this condition is trivial; both values are always unit.
374// (See the test_extensionality_sized test case.)
375#[doc(hidden)]
376pub closed spec fn view_reverse_for_eq_sized<T>(addr: usize, provenance: Provenance) -> *mut T {
377    view_reverse_for_eq(PtrData { addr: addr, provenance: provenance, metadata: () })
378}
379
380pub broadcast proof fn ptrs_mut_eq_sized<T>(a: *mut T)
381    ensures
382        view_reverse_for_eq_sized::<T>((#[trigger] a@).addr, a@.provenance) == a,
383{
384    assert(a@.metadata == ());
385    ptrs_mut_eq(a);
386}
387
388//////////////////////////////////////
389/// Constructs a null pointer.
390/// NOTE: Trait aliases are not yet supported,
391/// so we use `Pointee<Metadata = ()>` instead of `core::ptr::Thin` here
392#[verifier::inline]
393pub open spec fn ptr_null<
394    T: ::core::marker::PointeeSized + core::ptr::Pointee<Metadata = ()>,
395>() -> *const T {
396    ptr_from_data(PtrData::<T> { addr: 0, provenance: Provenance::null(), metadata: () })
397}
398
399#[cfg(verus_keep_ghost)]
400#[verifier::when_used_as_spec(ptr_null)]
401pub assume_specification<
402    T: core::marker::PointeeSized + core::ptr::Pointee<Metadata = ()>,
403>[ core::ptr::null ]() -> (res: *const T)
404    ensures
405        res == ptr_null::<T>(),
406    opens_invariants none
407    no_unwind
408;
409
410/// Constructs a mutable null pointer.
411/// NOTE: Trait aliases are not yet supported,
412/// so we use `Pointee<Metadata = ()>` instead of `core::ptr::Thin` here
413#[verifier::inline]
414pub open spec fn ptr_null_mut<
415    T: core::marker::PointeeSized + core::ptr::Pointee<Metadata = ()>,
416>() -> *mut T {
417    ptr_mut_from_data(PtrData::<T> { addr: 0, provenance: Provenance::null(), metadata: () })
418}
419
420#[cfg(verus_keep_ghost)]
421#[verifier::when_used_as_spec(ptr_null_mut)]
422pub assume_specification<
423    T: core::marker::PointeeSized + core::ptr::Pointee<Metadata = ()>,
424>[ core::ptr::null_mut ]() -> (res: *mut T)
425    ensures
426        res == ptr_null_mut::<T>(),
427    opens_invariants none
428    no_unwind
429;
430
431//////////////////////////////////////
432// Casting
433// as-casts and implicit casts are translated internally to these functions
434// (including casts that involve *const ptrs)
435/// Cast a pointer to a thin pointer. Address and provenance are preserved; metadata is now thin.
436pub open spec fn spec_cast_ptr_to_thin_ptr<T: ?Sized, U: Sized>(ptr: *mut T) -> *mut U {
437    ptr_mut_from_data(PtrData::<U> { addr: ptr@.addr, provenance: ptr@.provenance, metadata: () })
438}
439
440/// Cast a pointer to a thin pointer. Address and provenance are preserved; metadata is now thin.
441///
442/// Don't call this directly; use an `as`-cast instead.
443#[verifier::external_body]
444#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::raw_ptr::cast_ptr_to_thin_ptr")]
445#[verifier::when_used_as_spec(spec_cast_ptr_to_thin_ptr)]
446pub fn cast_ptr_to_thin_ptr<T: ?Sized, U: Sized>(ptr: *mut T) -> (result: *mut U)
447    ensures
448        result == spec_cast_ptr_to_thin_ptr::<T, U>(ptr),
449    opens_invariants none
450    no_unwind
451{
452    ptr as *mut U
453}
454
455/// Cast a pointer to an array of length `N` to a slice pointer.
456/// Address and provenance are preserved; metadata has length `N`.
457pub open spec fn spec_cast_array_ptr_to_slice_ptr<T, const N: usize>(ptr: *mut [T; N]) -> *mut [T] {
458    ptr_mut_from_data(PtrData::<[T]> { addr: ptr@.addr, provenance: ptr@.provenance, metadata: N })
459}
460
461/// Cast a pointer to an array of length `N` to a slice pointer.
462/// Address and provenance are preserved; metadata has length `N`.
463///
464/// Don't call this directly; use an `as`-cast instead.
465#[verifier::external_body]
466#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::raw_ptr::cast_array_ptr_to_slice_ptr")]
467#[verifier::when_used_as_spec(spec_cast_array_ptr_to_slice_ptr)]
468pub fn cast_array_ptr_to_slice_ptr<T, const N: usize>(ptr: *mut [T; N]) -> (result: *mut [T])
469    ensures
470        result == spec_cast_array_ptr_to_slice_ptr(ptr),
471    opens_invariants none
472    no_unwind
473{
474    ptr as *mut [T]
475}
476
477/// Cast a slice pointer to another slice pointer.
478/// Length is preserved even if the size of the elements changes.
479pub open spec fn spec_cast_slice_ptr_to_slice_ptr<T, U>(ptr: *mut [T]) -> *mut [U] {
480    ptr_mut_from_data(
481        PtrData::<[U]> { addr: ptr@.addr, provenance: ptr@.provenance, metadata: ptr@.metadata },
482    )
483}
484
485/// Cast a slice pointer to another slice pointer.
486/// Length is preserved even if the size of the elements changes.
487///
488/// Don't call this directly; use an `as`-cast instead.
489#[verifier::external_body]
490#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::raw_ptr::cast_slice_ptr_to_slice_ptr")]
491#[verifier::when_used_as_spec(spec_cast_slice_ptr_to_slice_ptr)]
492pub fn cast_slice_ptr_to_slice_ptr<T, U>(ptr: *mut [T]) -> (result: *mut [U])
493    ensures
494        result == spec_cast_slice_ptr_to_slice_ptr::<T, U>(ptr),
495    opens_invariants none
496    no_unwind
497{
498    ptr as *mut [U]
499}
500
501/// Cast a slice pointer to a `str` pointer.
502/// Length is preserved even if the size of the elements changes.
503pub open spec fn spec_cast_slice_ptr_to_str_ptr<T>(ptr: *mut [T]) -> *mut str {
504    ptr_mut_from_data(
505        PtrData::<str> { addr: ptr@.addr, provenance: ptr@.provenance, metadata: ptr@.metadata },
506    )
507}
508
509/// Cast a slice pointer to a `str` pointer.
510/// Length is preserved even if the size of the elements changes.
511///
512/// Don't call this directly; use an `as`-cast instead.
513#[verifier::external_body]
514#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::raw_ptr::cast_slice_ptr_to_str_ptr")]
515#[verifier::when_used_as_spec(spec_cast_slice_ptr_to_str_ptr)]
516pub fn cast_slice_ptr_to_str_ptr<T>(ptr: *mut [T]) -> (result: *mut str)
517    ensures
518        result == spec_cast_slice_ptr_to_str_ptr::<T>(ptr),
519    opens_invariants none
520    no_unwind
521{
522    ptr as *mut str
523}
524
525/// Cast a `str` pointer to a slice pointer.
526/// Length is preserved even if the size of the elements changes.
527pub open spec fn spec_cast_str_ptr_to_slice_ptr<T>(ptr: *mut str) -> *mut [T] {
528    ptr_mut_from_data(
529        PtrData::<[T]> { addr: ptr@.addr, provenance: ptr@.provenance, metadata: ptr@.metadata },
530    )
531}
532
533/// Cast a `str` pointer to a slice pointer.
534/// Length is preserved even if the size of the elements changes.
535///
536/// Don't call this directly; use an `as`-cast instead.
537#[verifier::external_body]
538#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::raw_ptr::cast_str_ptr_to_slice_ptr")]
539#[verifier::when_used_as_spec(spec_cast_str_ptr_to_slice_ptr)]
540pub fn cast_str_ptr_to_slice_ptr<T>(ptr: *mut str) -> (result: *mut [T])
541    ensures
542        result == spec_cast_str_ptr_to_slice_ptr::<T>(ptr),
543    opens_invariants none
544    no_unwind
545{
546    ptr as *mut [T]
547}
548
549/// Cast a pointer to a `usize` by extracting just the address.
550pub open spec fn spec_cast_ptr_to_usize<T: Sized>(ptr: *mut T) -> usize {
551    ptr@.addr
552}
553
554/// Cast the address of a pointer to a `usize`.
555///
556/// Don't call this directly; use an `as`-cast instead.
557#[verifier::external_body]
558#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::raw_ptr::cast_ptr_to_usize")]
559#[verifier::when_used_as_spec(spec_cast_ptr_to_usize)]
560pub fn cast_ptr_to_usize<T: Sized>(ptr: *mut T) -> (result: usize)
561    ensures
562        result == spec_cast_ptr_to_usize(ptr),
563    opens_invariants none
564    no_unwind
565{
566    ptr as usize
567}
568
569//////////////////////////////////////
570// Reading and writing
571/// Calls [`core::ptr::write`] to write the value `v` to the memory location pointed to by `ptr`,
572/// using the permission `perm`.
573///
574/// This does _not_ drop the contents. If the memory is already initialized,
575/// this could leak allocations or resources, so care should be taken to not overwrite an object that should be dropped.
576/// This is appropriate for initializing uninitialized memory, or overwriting memory that has previously been [read](ptr_mut_read) from.
577#[inline(always)]
578#[verifier::external_body]
579pub fn ptr_mut_write<T>(ptr: *mut T, Tracked(perm): Tracked<&mut PointsTo<T>>, v: T)
580    requires
581        old(perm).ptr() == ptr,
582    ensures
583        perm.ptr() == ptr,
584        perm.opt_value() == MemContents::Init(v),
585    opens_invariants none
586    no_unwind
587{
588    unsafe {
589        core::ptr::write(ptr, v);
590    }
591}
592
593/// Calls [`core::ptr::read`] to read from the memory pointed to by `ptr`,
594/// using the permission `perm`.
595///
596/// This leaves the data as "unitialized", i.e., performs a move.
597///
598/// TODO: This needs to be made more general (i.e., should be able to read a Copy type
599/// without destroying it; should be able to leave the bytes intact without uninitializing them).
600#[inline(always)]
601#[verifier::external_body]
602pub fn ptr_mut_read<T>(ptr: *const T, Tracked(perm): Tracked<&mut PointsTo<T>>) -> (v: T)
603    requires
604        old(perm).ptr() == ptr,
605        old(perm).is_init(),
606    ensures
607        perm.ptr() == ptr,
608        perm.is_uninit(),
609        v == old(perm).value(),
610    opens_invariants none
611    no_unwind
612{
613    unsafe { core::ptr::read(ptr) }
614}
615
616/// Equivalent to `&*ptr`, passing in a permission `perm` to ensure safety.
617/// The memory pointed to by `ptr` must be initialized.
618#[inline(always)]
619#[verifier::external_body]
620pub fn ptr_ref<T>(ptr: *const T, Tracked(perm): Tracked<&PointsTo<T>>) -> (v: &T)
621    requires
622        perm.ptr() == ptr,
623        perm.is_init(),
624    ensures
625        v == perm.value(),
626    opens_invariants none
627    no_unwind
628{
629    unsafe { &*ptr }
630}
631
632/* coming soon
633/// Equivalent to &mut *X, passing in a permission `perm` to ensure safety.
634/// The memory pointed to by `ptr` must be initialized.
635#[inline(always)]
636#[verifier::external_body]
637pub fn ptr_mut_ref<T>(ptr: *mut T, Tracked(perm): Tracked<&mut PointsTo<T>>) -> (v: &mut T)
638    requires
639        old(perm).ptr() == ptr,
640        old(perm).is_init()
641    ensures
642        perm.ptr() == ptr,
643        perm.is_init(),
644
645        old(perm).value() == *old(v),
646        new(perm).value() == *new(v),
647    unsafe { &*ptr }
648}
649*/
650
651macro_rules! pointer_specs {
652    ($mod_ident:ident, $ptr_from_data:ident, $mu:tt) => {
653        #[cfg(verus_keep_ghost)]
654        mod $mod_ident {
655            use super::*;
656
657            verus!{
658
659            #[verifier::inline]
660            pub open spec fn spec_addr<T: ::core::marker::PointeeSized>(p: *$mu T) -> usize { p@.addr }
661
662            #[verifier::when_used_as_spec(spec_addr)]
663            #[cfg(verus_keep_ghost)]
664            pub assume_specification<T: ::core::marker::PointeeSized>[<*$mu T>::addr](p: *$mu T) -> (addr: usize)
665                ensures addr == spec_addr(p)
666                opens_invariants none
667                no_unwind;
668
669            pub open spec fn spec_with_addr<T: ::core::marker::PointeeSized>(p: *$mu T, addr: usize) -> *$mu T {
670                $ptr_from_data(PtrData::<T> { addr: addr, .. p@ })
671            }
672
673            #[verifier::when_used_as_spec(spec_with_addr)]
674            #[cfg(verus_keep_ghost)]
675            pub assume_specification<T: ::core::marker::PointeeSized>[<*$mu T>::with_addr](p: *$mu T, addr: usize) -> (q: *$mu T)
676                ensures q == spec_with_addr(p, addr)
677                opens_invariants none
678                no_unwind;
679
680            }
681        }
682    };
683}
684
685pointer_specs!(ptr_mut_specs, ptr_mut_from_data, mut);
686
687pointer_specs!(ptr_const_specs, ptr_from_data, const);
688
689pub broadcast group group_raw_ptr_axioms {
690    axiom_ptr_mut_from_data,
691    ptrs_mut_eq,
692    ptrs_mut_eq_sized,
693}
694
695/// Tracked object that indicates a given provenance has been exposed.
696#[verifier::external_body]
697pub tracked struct IsExposed {}
698
699impl Clone for IsExposed {
700    #[verifier::external_body]
701    fn clone(&self) -> (s: Self)
702        ensures
703            s == self,
704    {
705        IsExposed {  }
706    }
707}
708
709impl Copy for IsExposed {
710
711}
712
713impl IsExposed {
714    /// The view of `IsExposed` is simply its provenance.
715    pub open spec fn view(self) -> Provenance {
716        self.provenance()
717    }
718
719    /// Provenance we are exposing.
720    pub uninterp spec fn provenance(self) -> Provenance;
721
722    /// It is always possible to expose/construct the null provenance.
723    pub axiom fn null() -> (tracked exp: IsExposed)
724        ensures
725            exp.provenance() == Provenance::null(),
726    ;
727}
728
729/// Perform a provenance expose operation.
730#[verifier::external_body]
731pub fn expose_provenance<T: Sized>(m: *mut T) -> (provenance: Tracked<IsExposed>)
732    ensures
733        provenance@@ == m@.provenance,
734    opens_invariants none
735    no_unwind
736{
737    let _ = m as usize;
738    Tracked::assume_new()
739}
740
741/// Construct a pointer with the given provenance from a _usize_ address.
742/// The provenance must have previously been exposed.
743#[verifier::external_body]
744pub fn with_exposed_provenance<T: Sized>(
745    addr: usize,
746    Tracked(provenance): Tracked<IsExposed>,
747) -> (p: *mut T)
748    ensures
749        p == ptr_mut_from_data::<T>(
750            PtrData::<T> { addr: addr, provenance: provenance@, metadata: () },
751        ),
752    opens_invariants none
753    no_unwind
754{
755    addr as *mut T
756}
757
758/// Variable-sized uninitialized memory.
759///
760/// Permission is for an arbitrary set of addresses, not necessarily contiguous,
761/// and with a given provenance.
762// Note reading from uninitialized memory is UB, so we shouldn't give any
763// reading capabilities to PointsToRaw. Turning a PointsToRaw into a PointsTo
764// should always leave it as 'uninitialized'.
765#[verifier::external_body]
766pub tracked struct PointsToRaw {
767    // TODO implement this as Map<usize, PointsTo<u8>> or something
768    no_copy: NoCopy,
769}
770
771impl PointsToRaw {
772    /// Provenance of the `PointsToRaw` permission;
773    /// this corresponds to the original allocation and does not change.
774    pub uninterp spec fn provenance(self) -> Provenance;
775
776    /// Memory addresses (domain) that the `PointsToRaw` permission gives access to.
777    /// This set may be split apart and/or recombined, in order to create permissions to smaller pieces of the allocation.
778    pub uninterp spec fn dom(self) -> Set<int>;
779
780    /// Returns `true` if the domain of this permission is exactly the range `[start, start + len)`.
781    pub open spec fn is_range(self, start: int, len: int) -> bool {
782        super::set_lib::set_int_range(start, start + len) =~= self.dom()
783    }
784
785    /// Returns `true` if the domain of this permission contains the range `[start, start + len)`.
786    pub open spec fn contains_range(self, start: int, len: int) -> bool {
787        super::set_lib::set_int_range(start, start + len) <= self.dom()
788    }
789
790    /// Constructs a `PointsToRaw` permission over an empty domain with the given provenance.
791    pub axiom fn empty(provenance: Provenance) -> (tracked points_to_raw: Self)
792        ensures
793            points_to_raw.dom() == Set::<int>::empty(),
794            points_to_raw.provenance() == provenance,
795    ;
796
797    /// Splits the current `PointsToRaw` permission into a permission with domain `range`
798    /// and a permission containing the rest of the domain,
799    /// provided that `range` is contained in the domain of the current permission.
800    pub axiom fn split(tracked self, range: Set<int>) -> (tracked res: (Self, Self))
801        requires
802            range.subset_of(self.dom()),
803        ensures
804            res.0.provenance() == self.provenance(),
805            res.1.provenance() == self.provenance(),
806            res.0.dom() == range,
807            res.1.dom() == self.dom().difference(range),
808    ;
809
810    /// Joins two `PointsToRaw` permissions into one,
811    /// provided that they have the same provenance.
812    /// The memory addresses of the new permission is the union of the domains of `self` and `other`.
813    pub axiom fn join(tracked self, tracked other: Self) -> (tracked joined: Self)
814        requires
815            self.provenance() == other.provenance(),
816        ensures
817            joined.provenance() == self.provenance(),
818            joined.dom() == self.dom() + other.dom(),
819    ;
820
821    /// Creates a `PointsTo<V>` permission from a `PointsToRaw` permission
822    /// with address `start` and the same provanance as the `PointsToRaw` permission,
823    /// provided that `start` is aligned to `V` and
824    /// that the domain of the `PointsToRaw` permission matches the size of `V`.
825    ///
826    /// In combination with [`PointsToRaw::empty()`],
827    /// this lets us create a PointsTo for a ZST for _any_ non-null aligned pointer.
828    ///
829    /// To call this, it is necessary for the address to be non-null. This can be proved either
830    /// by showing `start != 0` or by showing the size of the type is non-zero (in which case
831    /// the non-null-ness follows from the existence of the `PointsToRaw`).
832    pub axiom fn into_typed<V>(tracked self, start: usize) -> (tracked points_to: PointsTo<V>)
833        requires
834            start != 0 || size_of::<V>() != 0,
835            start as int % align_of::<V>() as int == 0,
836            self.is_range(start as int, size_of::<V>() as int),
837        ensures
838            points_to.ptr() == ptr_mut_from_data::<V>(
839                PtrData { addr: start, provenance: self.provenance(), metadata: () },
840            ),
841            points_to.is_uninit(),
842    ;
843}
844
845impl<V> PointsTo<V> {
846    /// Creates a `PointsToRaw` from a `PointsTo<V>` with the same provenance
847    /// and a range corresponding to the address of the `PointsTo<V>` and size of `V`,
848    /// provided that the memory tracked by the `PointsTo<V>`is uninitialized.
849    pub axiom fn into_raw(tracked self) -> (tracked points_to_raw: PointsToRaw)
850        requires
851            self.is_uninit(),
852        ensures
853            points_to_raw.is_range(self.ptr().addr() as int, size_of::<V>() as int),
854            points_to_raw.provenance() == self.ptr()@.provenance,
855    ;
856}
857
858// Allocation and deallocation via the global allocator
859/// Permission to perform a deallocation with the global allocator.
860#[verifier::external_body]
861pub tracked struct Dealloc {
862    no_copy: NoCopy,
863}
864
865/// Data associated with a `Dealloc` permission.
866pub ghost struct DeallocData {
867    pub addr: usize,
868    pub size: nat,
869    pub align: nat,
870    /// This should probably be some kind of "allocation ID" (with "allocation ID" being
871    /// only one part of a full Provenance definition).
872    pub provenance: Provenance,
873}
874
875impl Dealloc {
876    pub uninterp spec fn view(self) -> DeallocData;
877
878    /// Start address of the allocation you are allowed to deallocate.
879    #[verifier::inline]
880    pub open spec fn addr(self) -> usize {
881        self.view().addr
882    }
883
884    /// Size of the allocation you are allowed to deallocate.
885    #[verifier::inline]
886    pub open spec fn size(self) -> nat {
887        self.view().size
888    }
889
890    /// Alignment of the allocation you are allowed to deallocate.
891    #[verifier::inline]
892    pub open spec fn align(self) -> nat {
893        self.view().align
894    }
895
896    /// Provenance of the allocation you are allowed to deallocate.
897    #[verifier::inline]
898    pub open spec fn provenance(self) -> Provenance {
899        self.view().provenance
900    }
901}
902
903/// Allocate with the global allocator.
904/// The precondition should be consistent with the [documented safety conditions on `alloc`](https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.alloc).
905/// Returns a pointer with a corresponding [`PointsToRaw`] and [`Dealloc`] permissions.
906#[cfg(feature = "std")]
907#[verifier::external_body]
908pub fn allocate(size: usize, align: usize) -> (pt: (
909    *mut u8,
910    Tracked<PointsToRaw>,
911    Tracked<Dealloc>,
912))
913    requires
914        valid_layout(size, align),
915        size != 0,
916    ensures
917        pt.1@.is_range(pt.0.addr() as int, size as int),
918        pt.0.addr() + size <= usize::MAX + 1,
919        pt.2@@ == (DeallocData {
920            addr: pt.0.addr(),
921            size: size as nat,
922            align: align as nat,
923            provenance: pt.1@.provenance(),
924        }),
925        pt.0.addr() as int % align as int == 0,
926        pt.0@.provenance == pt.1@.provenance(),
927    opens_invariants none
928{
929    // SAFETY: valid_layout is a precondition
930    let layout = unsafe { alloc::alloc::Layout::from_size_align_unchecked(size, align) };
931    // SAFETY: size != 0
932    let p = unsafe { ::alloc::alloc::alloc(layout) };
933    if p == core::ptr::null_mut() {
934        std::process::abort();
935    }
936    (p, Tracked::assume_new(), Tracked::assume_new())
937}
938
939/// Deallocate with the global allocator.
940///
941/// The [`Dealloc`] permission ensures that the
942/// [documented safety conditions on `dealloc`](https://doc.rust-lang.org/1.82.0/core/alloc/trait.GlobalAlloc.html#tymethod.dealloc)
943/// are satisfied; by also giving up permission of the [`PointsToRaw`] permission,
944/// we ensure there can be no use-after-free bug as a result of this deallocation.
945/// In order to do so, the parameters of the [`PointsToRaw`] and [`Dealloc`] permissions must match the parameters of the deallocation.
946#[cfg(feature = "alloc")]
947#[verifier::external_body]
948pub fn deallocate(
949    p: *mut u8,
950    size: usize,
951    align: usize,
952    Tracked(pt): Tracked<PointsToRaw>,
953    Tracked(dealloc): Tracked<Dealloc>,
954)
955    requires
956        dealloc.addr() == p.addr(),
957        dealloc.size() == size,
958        dealloc.align() == align,
959        dealloc.provenance() == pt.provenance(),
960        pt.is_range(dealloc.addr() as int, dealloc.size() as int),
961        p@.provenance == dealloc.provenance(),
962    opens_invariants none
963{
964    // SAFETY: ensured by dealloc token
965    let layout = unsafe { alloc::alloc::Layout::from_size_align_unchecked(size, align) };
966    unsafe {
967        ::alloc::alloc::dealloc(p, layout);
968    }
969}
970
971/// This is meant to be a replacement for `&'a T` that allows Verus to keep track of
972/// not just the `T` value but the pointer as well.
973/// It would be better to get rid of this and use normal reference types `&'a T`,
974/// but there are a lot of unsolved implementation questions.
975/// The existence of `SharedReference<'a, T>` is a stop-gap.
976#[verifier::external_body]
977#[verifier::accept_recursive_types(T)]
978pub struct SharedReference<'a, T>(&'a T);
979
980impl<'a, T> Clone for SharedReference<'a, T> {
981    #[verifier::external_body]
982    fn clone(&self) -> (ret: Self)
983        ensures
984            ret == *self,
985    {
986        SharedReference(self.0)
987    }
988}
989
990impl<'a, T> Copy for SharedReference<'a, T> {
991
992}
993
994impl<'a, T> SharedReference<'a, T> {
995    pub uninterp spec fn value(self) -> T;
996
997    pub uninterp spec fn ptr(self) -> *const T;
998
999    #[verifier::external_body]
1000    fn new(t: &'a T) -> (s: Self)
1001        ensures
1002            s.value() == t,
1003    {
1004        SharedReference(t)
1005    }
1006
1007    #[verifier::external_body]
1008    fn as_ref(self) -> (t: &'a T)
1009        ensures
1010            t == self.value(),
1011    {
1012        self.0
1013    }
1014
1015    #[verifier::external_body]
1016    fn as_ptr(self) -> (ptr: *const T)
1017        ensures
1018            ptr == self.ptr(),
1019    {
1020        &*self.0
1021    }
1022
1023    pub axiom fn points_to(tracked self) -> (tracked pt: &'a PointsTo<T>)
1024        ensures
1025            pt.ptr() == self.ptr(),
1026            pt.is_init(),
1027            pt.value() == self.value(),
1028    ;
1029}
1030
1031/// Like [`ptr_ref`] but returns a `SharedReference` so it keeps track of the relationship
1032/// between the pointers.
1033/// Note the resulting reference's pointers does NOT have the same provenance.
1034/// This is because in Rust models like Stacked Borrows / Tree Borrows, the pointer
1035/// gets a new tag.
1036#[inline(always)]
1037#[verifier::external_body]
1038pub fn ptr_ref2<'a, T>(ptr: *const T, Tracked(perm): Tracked<&PointsTo<T>>) -> (v: SharedReference<
1039    'a,
1040    T,
1041>)
1042    requires
1043        perm.ptr() == ptr,
1044        perm.is_init(),
1045    ensures
1046        v.value() == perm.value(),
1047        v.ptr().addr() == ptr.addr(),
1048        v.ptr()@.metadata == ptr@.metadata,
1049    opens_invariants none
1050    no_unwind
1051{
1052    SharedReference(unsafe { &*ptr })
1053}
1054
1055} // verus!