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/// Permission to access possibly-initialized, _typed_ memory.
98// ptr |--> Init(v) means:
99//   bytes in this memory are consistent with value v
100//   and we have all the ghost state associated with type V
101//
102// ptr |--> Uninit means:
103//   no knowledge about what's in memory
104//   (to be pedantic, the bytes might be initialized in rust's abstract machine,
105//   but we don't know so we have to pretend they're uninitialized)
106#[verifier::external_body]
107#[verifier::accept_recursive_types(T)]
108pub tracked struct PointsTo<T> {
109    phantom: core::marker::PhantomData<T>,
110    no_copy: NoCopy,
111}
112
113//#[verifier::external_body]
114//#[verifier::accept_recursive_types(T)]
115//pub tracked struct PointsToBytes<T> {
116//    phantom: core::marker::PhantomData<T>,
117//    no_copy: NoCopy,
118//}
119/// Represents (typed) contents of memory.
120// Don't use std Option here in order to avoid circular dependency issues
121// with verifying the standard library.
122// (Also, using our own enum here lets us have more meaningful
123// variant names like Uninit/Init.)
124#[verifier::accept_recursive_types(T)]
125pub ghost enum MemContents<T> {
126    /// Represents uninitialized memory.
127    Uninit,
128    /// Represents initialized memory with the given value of type `T`.
129    Init(T),
130}
131
132/// Data associated with a `PointsTo` permission.
133/// We keep track of both the pointer and the (potentially uninitialized) value
134/// it points to.
135///
136/// If `opt_value` is `Init(T)`, this signifies that `ptr` points to initialized memory,
137/// and the value of `opt_value` is consistent with the bytes `ptr` points to,
138/// We also have all the ghost state associated with type `T`.
139///
140/// If `opt_value` is `Uninit`, then we have no knowledge about what's in memory,
141/// and we assume `ptr` points to uninitialized memory.
142/// (To be pedantic, the bytes might be initialized in Rust's abstract machine,
143///  but we don't know, so we have to pretend they're uninitialized.)
144pub ghost struct PointsToData<T> {
145    pub ptr: *mut T,
146    pub opt_value: MemContents<T>,
147}
148
149#[cfg(verus_keep_ghost)]
150impl<T: core::marker::PointeeSized> View for *mut T {
151    type V = PtrData<T>;
152
153    uninterp spec fn view(&self) -> Self::V;
154}
155
156/// Compares the address and metadata of two pointers.
157///
158/// Note that this does NOT compare provenance, which does not exist in the runtime
159/// pointer representation (i.e., it only exists in the Rust abstract machine).
160#[cfg(verus_keep_ghost)]
161pub assume_specification<T: core::marker::PointeeSized>[ <*mut T as PartialEq<*mut T>>::eq ](
162    x: &*mut T,
163    y: &*mut T,
164) -> (res: bool)
165    ensures
166        res <==> (x@.addr == y@.addr) && (x@.metadata == y@.metadata),
167;
168
169#[cfg(verus_keep_ghost)]
170impl<T: core::marker::PointeeSized> View for *const T {
171    type V = PtrData<T>;
172
173    #[verifier::inline]
174    open spec fn view(&self) -> Self::V {
175        (*self as *mut T).view()
176    }
177}
178
179/// Compares the address and metadata of two pointers.
180///
181/// Note that this does NOT compare provenance, which does not exist in the runtime
182/// pointer representation (i.e., it only exists in the Rust abstract machine).
183#[cfg(verus_keep_ghost)]
184pub assume_specification<T: core::marker::PointeeSized>[ <*const T as PartialEq<*const T>>::eq ](
185    x: &*const T,
186    y: &*const T,
187) -> (res: bool)
188    ensures
189        res <==> (x@.addr == y@.addr) && (x@.metadata == y@.metadata),
190;
191
192impl<T> View for PointsTo<T> {
193    type V = PointsToData<T>;
194
195    uninterp spec fn view(&self) -> Self::V;
196}
197
198impl<T> PointsTo<T> {
199    /// The pointer that this permission is associated with.
200    #[verifier::inline]
201    pub open spec fn ptr(&self) -> *mut T {
202        self.view().ptr
203    }
204
205    /// The (possibly uninitialized) memory that this permission gives access to.
206    #[verifier::inline]
207    pub open spec fn opt_value(&self) -> MemContents<T> {
208        self.view().opt_value
209    }
210
211    /// Returns `true` if the permission's associated memory is initialized.
212    #[verifier::inline]
213    pub open spec fn is_init(&self) -> bool {
214        self.opt_value().is_init()
215    }
216
217    /// Returns `true` if the permission's associated memory is uninitialized.
218    #[verifier::inline]
219    pub open spec fn is_uninit(&self) -> bool {
220        self.opt_value().is_uninit()
221    }
222
223    /// If the permission's associated memory is initialized,
224    /// returns the value that the pointer points to.
225    /// Otherwise, the result is meaningless.
226    #[verifier::inline]
227    pub open spec fn value(&self) -> T
228        recommends
229            self.is_init(),
230    {
231        self.opt_value().value()
232    }
233
234    /// Guarantee that the `PointsTo` for any non-zero-sized type points to a non-null address.
235    ///
236    // ZST pointers *are* allowed to be null, so we need a precondition that size != 0.
237    // See https://doc.rust-lang.org/std/ptr/#safety
238    pub axiom fn is_nonnull(tracked &self)
239        requires
240            size_of::<T>() != 0,
241        ensures
242            self@.ptr@.addr != 0,
243    ;
244
245    /// Guarantee that the `PointsTo` points to an aligned address.
246    ///
247    // Note that even for ZSTs, pointers need to be aligned.
248    pub axiom fn is_aligned(tracked &self)
249        ensures
250            self@.ptr@.addr as nat % align_of::<T>() == 0,
251    ;
252
253    /// "Forgets" about the value stored behind the pointer.
254    /// Updates the `PointsTo` value to [`MemContents::Uninit`](MemContents::Uninit).
255    /// Note that this is a `proof` function, i.e.,
256    /// it is operationally a no-op in executable code, even on the Rust Abstract Machine.
257    /// Only the proof-code representation changes.
258    pub axiom fn leak_contents(tracked &mut self)
259        ensures
260            self.ptr() == old(self).ptr(),
261            self.is_uninit(),
262    ;
263
264    /// Guarantees that the memory ranges associated with two permissions will not overlap,
265    /// since you cannot have two permissions to the same memory.
266    ///
267    /// Note: If both S and T are non-zero-sized, then this implies the pointers
268    /// have distinct addresses.
269    pub axiom fn is_disjoint<S>(tracked &mut self, tracked other: &PointsTo<S>)
270        ensures
271            *old(self) == *self,
272            self.ptr() as int + size_of::<T>() <= other.ptr() as int || other.ptr() as int
273                + size_of::<S>() <= self.ptr() as int,
274    ;
275}
276
277impl<T> MemContents<T> {
278    /// Returns `true` if it is a [`MemContents::Init`] value.
279    #[verifier::inline]
280    pub open spec fn is_init(&self) -> bool {
281        self is Init
282    }
283
284    /// Returns `true` if it is a [`MemContents::Uninit`] value.
285    #[verifier::inline]
286    pub open spec fn is_uninit(&self) -> bool {
287        self is Uninit
288    }
289
290    /// If it is a [`MemContents::Init`] value, returns the value.
291    /// Otherwise, the return value is meaningless.
292    #[verifier::inline]
293    pub open spec fn value(&self) -> T
294        recommends
295            self is Init,
296    {
297        self->0
298    }
299}
300
301//////////////////////////////////////
302// Inverse functions:
303// Pointers are equivalent to their model
304/// Constructs a pointer from its underlying model.
305pub uninterp spec fn ptr_mut_from_data<T: core::marker::PointeeSized>(data: PtrData<T>) -> *mut T;
306
307/// Constructs a pointer from its underlying model.
308/// Since `*mut T` and `*const T` are [semantically the same](https://verus-lang.github.io/verus/verusdoc/vstd/raw_ptr/index.html#pointer-model),
309/// we can define this operation in terms of the operation on `*mut T`.
310#[verifier::inline]
311pub open spec fn ptr_from_data<T: core::marker::PointeeSized>(data: PtrData<T>) -> *const T {
312    ptr_mut_from_data(data) as *const T
313}
314
315/// The view of a pointer constructed from `data: PtrData` should be exactly that data.
316pub broadcast axiom fn axiom_ptr_mut_from_data<T: ?Sized>(data: PtrData<T>)
317    ensures
318        (#[trigger] ptr_mut_from_data::<T>(data))@ == data,
319;
320
321// Equiv to ptr_mut_from_data, but named differently to avoid trigger issues
322// Only use for ptrs_mut_eq
323#[doc(hidden)]
324pub uninterp spec fn view_reverse_for_eq<T: ?Sized>(data: PtrData<T>) -> *mut T;
325
326/// Implies that `a@ == b@ ==> a == b`.
327pub broadcast axiom fn ptrs_mut_eq<T: ?Sized>(a: *mut T)
328    ensures
329        view_reverse_for_eq::<T>(#[trigger] a@) == a,
330;
331
332// We do the same trick again, but specialized for Sized types. This improves automation.
333// Specifically, this makes it easier to prove `a == b` without having to explicitly write
334// `a@.metadata == b@.metadata`, since this condition is trivial; both values are always unit.
335// (See the test_extensionality_sized test case.)
336#[doc(hidden)]
337pub closed spec fn view_reverse_for_eq_sized<T>(addr: usize, provenance: Provenance) -> *mut T {
338    view_reverse_for_eq(PtrData { addr: addr, provenance: provenance, metadata: () })
339}
340
341pub broadcast proof fn ptrs_mut_eq_sized<T>(a: *mut T)
342    ensures
343        view_reverse_for_eq_sized::<T>((#[trigger] a@).addr, a@.provenance) == a,
344{
345    assert(a@.metadata == ());
346    ptrs_mut_eq(a);
347}
348
349//////////////////////////////////////
350/// Constructs a null pointer.
351/// NOTE: Trait aliases are not yet supported,
352/// so we use `Pointee<Metadata = ()>` instead of `core::ptr::Thin` here
353#[verifier::inline]
354pub open spec fn ptr_null<
355    T: ::core::marker::PointeeSized + core::ptr::Pointee<Metadata = ()>,
356>() -> *const T {
357    ptr_from_data(PtrData::<T> { addr: 0, provenance: Provenance::null(), metadata: () })
358}
359
360#[cfg(verus_keep_ghost)]
361#[verifier::when_used_as_spec(ptr_null)]
362pub assume_specification<
363    T: core::marker::PointeeSized + core::ptr::Pointee<Metadata = ()>,
364>[ core::ptr::null ]() -> (res: *const T)
365    ensures
366        res == ptr_null::<T>(),
367    opens_invariants none
368    no_unwind
369;
370
371/// Constructs a mutable null pointer.
372/// NOTE: Trait aliases are not yet supported,
373/// so we use `Pointee<Metadata = ()>` instead of `core::ptr::Thin` here
374#[verifier::inline]
375pub open spec fn ptr_null_mut<
376    T: core::marker::PointeeSized + core::ptr::Pointee<Metadata = ()>,
377>() -> *mut T {
378    ptr_mut_from_data(PtrData::<T> { addr: 0, provenance: Provenance::null(), metadata: () })
379}
380
381#[cfg(verus_keep_ghost)]
382#[verifier::when_used_as_spec(ptr_null_mut)]
383pub assume_specification<
384    T: core::marker::PointeeSized + core::ptr::Pointee<Metadata = ()>,
385>[ core::ptr::null_mut ]() -> (res: *mut T)
386    ensures
387        res == ptr_null_mut::<T>(),
388    opens_invariants none
389    no_unwind
390;
391
392//////////////////////////////////////
393// Casting
394// as-casts and implicit casts are translated internally to these functions
395// (including casts that involve *const ptrs)
396/// Cast a pointer to a thin pointer. Address and provenance are preserved; metadata is now thin.
397pub open spec fn spec_cast_ptr_to_thin_ptr<T: ?Sized, U: Sized>(ptr: *mut T) -> *mut U {
398    ptr_mut_from_data(PtrData::<U> { addr: ptr@.addr, provenance: ptr@.provenance, metadata: () })
399}
400
401/// Cast a pointer to a thin pointer. Address and provenance are preserved; metadata is now thin.
402///
403/// Don't call this directly; use an `as`-cast instead.
404#[verifier::external_body]
405#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::raw_ptr::cast_ptr_to_thin_ptr")]
406#[verifier::when_used_as_spec(spec_cast_ptr_to_thin_ptr)]
407pub fn cast_ptr_to_thin_ptr<T: ?Sized, U: Sized>(ptr: *mut T) -> (result: *mut U)
408    ensures
409        result == spec_cast_ptr_to_thin_ptr::<T, U>(ptr),
410    opens_invariants none
411    no_unwind
412{
413    ptr as *mut U
414}
415
416/// Cast a pointer to an array of length `N` to a slice pointer.
417/// Address and provenance are preserved; metadata has length `N`.
418pub open spec fn spec_cast_array_ptr_to_slice_ptr<T, const N: usize>(ptr: *mut [T; N]) -> *mut [T] {
419    ptr_mut_from_data(PtrData::<[T]> { addr: ptr@.addr, provenance: ptr@.provenance, metadata: N })
420}
421
422/// Cast a pointer to an array of length `N` to a slice pointer.
423/// Address and provenance are preserved; metadata has length `N`.
424///
425/// Don't call this directly; use an `as`-cast instead.
426#[verifier::external_body]
427#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::raw_ptr::cast_array_ptr_to_slice_ptr")]
428#[verifier::when_used_as_spec(spec_cast_array_ptr_to_slice_ptr)]
429pub fn cast_array_ptr_to_slice_ptr<T, const N: usize>(ptr: *mut [T; N]) -> (result: *mut [T])
430    ensures
431        result == spec_cast_array_ptr_to_slice_ptr(ptr),
432    opens_invariants none
433    no_unwind
434{
435    ptr as *mut [T]
436}
437
438/// Cast a pointer to a `usize` by extracting just the address.
439pub open spec fn spec_cast_ptr_to_usize<T: Sized>(ptr: *mut T) -> usize {
440    ptr@.addr
441}
442
443/// Cast the address of a pointer to a `usize`.
444///
445/// Don't call this directly; use an `as`-cast instead.
446#[verifier::external_body]
447#[cfg_attr(verus_keep_ghost, rustc_diagnostic_item = "verus::vstd::raw_ptr::cast_ptr_to_usize")]
448#[verifier::when_used_as_spec(spec_cast_ptr_to_usize)]
449pub fn cast_ptr_to_usize<T: Sized>(ptr: *mut T) -> (result: usize)
450    ensures
451        result == spec_cast_ptr_to_usize(ptr),
452    opens_invariants none
453    no_unwind
454{
455    ptr as usize
456}
457
458//////////////////////////////////////
459// Reading and writing
460/// Calls [`core::ptr::write`] to write the value `v` to the memory location pointed to by `ptr`,
461/// using the permission `perm`.
462///
463/// This does _not_ drop the contents. If the memory is already initialized,
464/// this could leak allocations or resources, so care should be taken to not overwrite an object that should be dropped.
465/// This is appropriate for initializing uninitialized memory, or overwriting memory that has previously been [read](ptr_mut_read) from.
466#[inline(always)]
467#[verifier::external_body]
468pub fn ptr_mut_write<T>(ptr: *mut T, Tracked(perm): Tracked<&mut PointsTo<T>>, v: T)
469    requires
470        old(perm).ptr() == ptr,
471    ensures
472        perm.ptr() == ptr,
473        perm.opt_value() == MemContents::Init(v),
474    opens_invariants none
475    no_unwind
476{
477    unsafe {
478        core::ptr::write(ptr, v);
479    }
480}
481
482/// Calls [`core::ptr::read`] to read from the memory pointed to by `ptr`,
483/// using the permission `perm`.
484///
485/// This leaves the data as "unitialized", i.e., performs a move.
486///
487/// TODO: This needs to be made more general (i.e., should be able to read a Copy type
488/// without destroying it; should be able to leave the bytes intact without uninitializing them).
489#[inline(always)]
490#[verifier::external_body]
491pub fn ptr_mut_read<T>(ptr: *const T, Tracked(perm): Tracked<&mut PointsTo<T>>) -> (v: T)
492    requires
493        old(perm).ptr() == ptr,
494        old(perm).is_init(),
495    ensures
496        perm.ptr() == ptr,
497        perm.is_uninit(),
498        v == old(perm).value(),
499    opens_invariants none
500    no_unwind
501{
502    unsafe { core::ptr::read(ptr) }
503}
504
505/// Equivalent to `&*ptr`, passing in a permission `perm` to ensure safety.
506/// The memory pointed to by `ptr` must be initialized.
507#[inline(always)]
508#[verifier::external_body]
509pub fn ptr_ref<T>(ptr: *const T, Tracked(perm): Tracked<&PointsTo<T>>) -> (v: &T)
510    requires
511        perm.ptr() == ptr,
512        perm.is_init(),
513    ensures
514        v == perm.value(),
515    opens_invariants none
516    no_unwind
517{
518    unsafe { &*ptr }
519}
520
521/* coming soon
522/// Equivalent to &mut *X, passing in a permission `perm` to ensure safety.
523/// The memory pointed to by `ptr` must be initialized.
524#[inline(always)]
525#[verifier::external_body]
526pub fn ptr_mut_ref<T>(ptr: *mut T, Tracked(perm): Tracked<&mut PointsTo<T>>) -> (v: &mut T)
527    requires
528        old(perm).ptr() == ptr,
529        old(perm).is_init()
530    ensures
531        perm.ptr() == ptr,
532        perm.is_init(),
533
534        old(perm).value() == *old(v),
535        new(perm).value() == *new(v),
536    unsafe { &*ptr }
537}
538*/
539
540macro_rules! pointer_specs {
541    ($mod_ident:ident, $ptr_from_data:ident, $mu:tt) => {
542        #[cfg(verus_keep_ghost)]
543        mod $mod_ident {
544            use super::*;
545
546            verus!{
547
548            #[verifier::inline]
549            pub open spec fn spec_addr<T: ::core::marker::PointeeSized>(p: *$mu T) -> usize { p@.addr }
550
551            #[verifier::when_used_as_spec(spec_addr)]
552            #[cfg(verus_keep_ghost)]
553            pub assume_specification<T: ::core::marker::PointeeSized>[<*$mu T>::addr](p: *$mu T) -> (addr: usize)
554                ensures addr == spec_addr(p)
555                opens_invariants none
556                no_unwind;
557
558            pub open spec fn spec_with_addr<T: ::core::marker::PointeeSized>(p: *$mu T, addr: usize) -> *$mu T {
559                $ptr_from_data(PtrData::<T> { addr: addr, .. p@ })
560            }
561
562            #[verifier::when_used_as_spec(spec_with_addr)]
563            #[cfg(verus_keep_ghost)]
564            pub assume_specification<T: ::core::marker::PointeeSized>[<*$mu T>::with_addr](p: *$mu T, addr: usize) -> (q: *$mu T)
565                ensures q == spec_with_addr(p, addr)
566                opens_invariants none
567                no_unwind;
568
569            }
570        }
571    };
572}
573
574pointer_specs!(ptr_mut_specs, ptr_mut_from_data, mut);
575
576pointer_specs!(ptr_const_specs, ptr_from_data, const);
577
578pub broadcast group group_raw_ptr_axioms {
579    axiom_ptr_mut_from_data,
580    ptrs_mut_eq,
581    ptrs_mut_eq_sized,
582}
583
584/// Tracked object that indicates a given provenance has been exposed.
585#[verifier::external_body]
586pub tracked struct IsExposed {}
587
588impl Clone for IsExposed {
589    #[verifier::external_body]
590    fn clone(&self) -> (s: Self)
591        ensures
592            s == self,
593    {
594        IsExposed {  }
595    }
596}
597
598impl Copy for IsExposed {
599
600}
601
602impl IsExposed {
603    /// The view of `IsExposed` is simply its provenance.
604    pub open spec fn view(self) -> Provenance {
605        self.provenance()
606    }
607
608    /// Provenance we are exposing.
609    pub uninterp spec fn provenance(self) -> Provenance;
610
611    /// It is always possible to expose/construct the null provenance.
612    pub axiom fn null() -> (tracked exp: IsExposed)
613        ensures
614            exp.provenance() == Provenance::null(),
615    ;
616}
617
618/// Perform a provenance expose operation.
619#[verifier::external_body]
620pub fn expose_provenance<T: Sized>(m: *mut T) -> (provenance: Tracked<IsExposed>)
621    ensures
622        provenance@@ == m@.provenance,
623    opens_invariants none
624    no_unwind
625{
626    let _ = m as usize;
627    Tracked::assume_new()
628}
629
630/// Construct a pointer with the given provenance from a _usize_ address.
631/// The provenance must have previously been exposed.
632#[verifier::external_body]
633pub fn with_exposed_provenance<T: Sized>(
634    addr: usize,
635    Tracked(provenance): Tracked<IsExposed>,
636) -> (p: *mut T)
637    ensures
638        p == ptr_mut_from_data::<T>(
639            PtrData::<T> { addr: addr, provenance: provenance@, metadata: () },
640        ),
641    opens_invariants none
642    no_unwind
643{
644    addr as *mut T
645}
646
647/// Variable-sized uninitialized memory.
648///
649/// Permission is for an arbitrary set of addresses, not necessarily contiguous,
650/// and with a given provenance.
651// Note reading from uninitialized memory is UB, so we shouldn't give any
652// reading capabilities to PointsToRaw. Turning a PointsToRaw into a PointsTo
653// should always leave it as 'uninitialized'.
654#[verifier::external_body]
655pub tracked struct PointsToRaw {
656    // TODO implement this as Map<usize, PointsTo<u8>> or something
657    no_copy: NoCopy,
658}
659
660impl PointsToRaw {
661    /// Provenance of the `PointsToRaw` permission;
662    /// this corresponds to the original allocation and does not change.
663    pub uninterp spec fn provenance(self) -> Provenance;
664
665    /// Memory addresses (domain) that the `PointsToRaw` permission gives access to.
666    /// This set may be split apart and/or recombined, in order to create permissions to smaller pieces of the allocation.
667    pub uninterp spec fn dom(self) -> Set<int>;
668
669    /// Returns `true` if the domain of this permission is exactly the range `[start, start + len)`.
670    pub open spec fn is_range(self, start: int, len: int) -> bool {
671        super::set_lib::set_int_range(start, start + len) =~= self.dom()
672    }
673
674    /// Returns `true` if the domain of this permission contains the range `[start, start + len)`.
675    pub open spec fn contains_range(self, start: int, len: int) -> bool {
676        super::set_lib::set_int_range(start, start + len) <= self.dom()
677    }
678
679    /// Constructs a `PointsToRaw` permission over an empty domain with the given provenance.
680    pub axiom fn empty(provenance: Provenance) -> (tracked points_to_raw: Self)
681        ensures
682            points_to_raw.dom() == Set::<int>::empty(),
683            points_to_raw.provenance() == provenance,
684    ;
685
686    /// Splits the current `PointsToRaw` permission into a permission with domain `range`
687    /// and a permission containing the rest of the domain,
688    /// provided that `range` is contained in the domain of the current permission.
689    pub axiom fn split(tracked self, range: Set<int>) -> (tracked res: (Self, Self))
690        requires
691            range.subset_of(self.dom()),
692        ensures
693            res.0.provenance() == self.provenance(),
694            res.1.provenance() == self.provenance(),
695            res.0.dom() == range,
696            res.1.dom() == self.dom().difference(range),
697    ;
698
699    /// Joins two `PointsToRaw` permissions into one,
700    /// provided that they have the same provenance.
701    /// The memory addresses of the new permission is the union of the domains of `self` and `other`.
702    pub axiom fn join(tracked self, tracked other: Self) -> (tracked joined: Self)
703        requires
704            self.provenance() == other.provenance(),
705        ensures
706            joined.provenance() == self.provenance(),
707            joined.dom() == self.dom() + other.dom(),
708    ;
709
710    /// Creates a `PointsTo<V>` permission from a `PointsToRaw` permission
711    /// with address `start` and the same provanance as the `PointsToRaw` permission,
712    /// provided that `start` is aligned to `V` and
713    /// that the domain of the `PointsToRaw` permission matches the size of `V`.
714    ///
715    /// In combination with PointsToRaw::empty(),
716    /// this lets us create a PointsTo for a ZST for _any_ aligned pointer (any address and provenance, even null).
717    pub axiom fn into_typed<V>(tracked self, start: usize) -> (tracked points_to: PointsTo<V>)
718        requires
719            start as int % align_of::<V>() as int == 0,
720            self.is_range(start as int, size_of::<V>() as int),
721        ensures
722            points_to.ptr() == ptr_mut_from_data::<V>(
723                PtrData { addr: start, provenance: self.provenance(), metadata: () },
724            ),
725            points_to.is_uninit(),
726    ;
727}
728
729impl<V> PointsTo<V> {
730    /// Creates a `PointsToRaw` from a `PointsTo<V>` with the same provenance
731    /// and a range corresponding to the address of the `PointsTo<V>` and size of `V`,
732    /// provided that the memory tracked by the `PointsTo<V>`is uninitialized.
733    pub axiom fn into_raw(tracked self) -> (tracked points_to_raw: PointsToRaw)
734        requires
735            self.is_uninit(),
736        ensures
737            points_to_raw.is_range(self.ptr().addr() as int, size_of::<V>() as int),
738            points_to_raw.provenance() == self.ptr()@.provenance,
739    ;
740}
741
742// Allocation and deallocation via the global allocator
743/// Permission to perform a deallocation with the global allocator.
744#[verifier::external_body]
745pub tracked struct Dealloc {
746    no_copy: NoCopy,
747}
748
749/// Data associated with a `Dealloc` permission.
750pub ghost struct DeallocData {
751    pub addr: usize,
752    pub size: nat,
753    pub align: nat,
754    /// This should probably be some kind of "allocation ID" (with "allocation ID" being
755    /// only one part of a full Provenance definition).
756    pub provenance: Provenance,
757}
758
759impl Dealloc {
760    pub uninterp spec fn view(self) -> DeallocData;
761
762    /// Start address of the allocation you are allowed to deallocate.
763    #[verifier::inline]
764    pub open spec fn addr(self) -> usize {
765        self.view().addr
766    }
767
768    /// Size of the allocation you are allowed to deallocate.
769    #[verifier::inline]
770    pub open spec fn size(self) -> nat {
771        self.view().size
772    }
773
774    /// Alignment of the allocation you are allowed to deallocate.
775    #[verifier::inline]
776    pub open spec fn align(self) -> nat {
777        self.view().align
778    }
779
780    /// Provenance of the allocation you are allowed to deallocate.
781    #[verifier::inline]
782    pub open spec fn provenance(self) -> Provenance {
783        self.view().provenance
784    }
785}
786
787/// Allocate with the global allocator.
788/// The precondition should be consistent with the [documented safety conditions on `alloc`](https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.alloc).
789/// Returns a pointer with a corresponding [`PointsToRaw`] and [`Dealloc`] permissions.
790#[cfg(feature = "std")]
791#[verifier::external_body]
792pub fn allocate(size: usize, align: usize) -> (pt: (
793    *mut u8,
794    Tracked<PointsToRaw>,
795    Tracked<Dealloc>,
796))
797    requires
798        valid_layout(size, align),
799        size != 0,
800    ensures
801        pt.1@.is_range(pt.0.addr() as int, size as int),
802        pt.0.addr() + size <= usize::MAX + 1,
803        pt.2@@ == (DeallocData {
804            addr: pt.0.addr(),
805            size: size as nat,
806            align: align as nat,
807            provenance: pt.1@.provenance(),
808        }),
809        pt.0.addr() as int % align as int == 0,
810        pt.0@.provenance == pt.1@.provenance(),
811    opens_invariants none
812{
813    // SAFETY: valid_layout is a precondition
814    let layout = unsafe { alloc::alloc::Layout::from_size_align_unchecked(size, align) };
815    // SAFETY: size != 0
816    let p = unsafe { ::alloc::alloc::alloc(layout) };
817    if p == core::ptr::null_mut() {
818        std::process::abort();
819    }
820    (p, Tracked::assume_new(), Tracked::assume_new())
821}
822
823/// Deallocate with the global allocator.
824///
825/// The [`Dealloc`] permission ensures that the
826/// [documented safety conditions on `dealloc`](https://doc.rust-lang.org/1.82.0/core/alloc/trait.GlobalAlloc.html#tymethod.dealloc)
827/// are satisfied; by also giving up permission of the [`PointsToRaw`] permission,
828/// we ensure there can be no use-after-free bug as a result of this deallocation.
829/// In order to do so, the parameters of the [`PointsToRaw`] and [`Dealloc`] permissions must match the parameters of the deallocation.
830#[cfg(feature = "alloc")]
831#[verifier::external_body]
832pub fn deallocate(
833    p: *mut u8,
834    size: usize,
835    align: usize,
836    Tracked(pt): Tracked<PointsToRaw>,
837    Tracked(dealloc): Tracked<Dealloc>,
838)
839    requires
840        dealloc.addr() == p.addr(),
841        dealloc.size() == size,
842        dealloc.align() == align,
843        dealloc.provenance() == pt.provenance(),
844        pt.is_range(dealloc.addr() as int, dealloc.size() as int),
845        p@.provenance == dealloc.provenance(),
846    opens_invariants none
847{
848    // SAFETY: ensured by dealloc token
849    let layout = unsafe { alloc::alloc::Layout::from_size_align_unchecked(size, align) };
850    unsafe {
851        ::alloc::alloc::dealloc(p, layout);
852    }
853}
854
855/// This is meant to be a replacement for `&'a T` that allows Verus to keep track of
856/// not just the `T` value but the pointer as well.
857/// It would be better to get rid of this and use normal reference types `&'a T`,
858/// but there are a lot of unsolved implementation questions.
859/// The existence of `SharedReference<'a, T>` is a stop-gap.
860#[verifier::external_body]
861#[verifier::accept_recursive_types(T)]
862pub struct SharedReference<'a, T>(&'a T);
863
864impl<'a, T> Clone for SharedReference<'a, T> {
865    #[verifier::external_body]
866    fn clone(&self) -> (ret: Self)
867        ensures
868            ret == *self,
869    {
870        SharedReference(self.0)
871    }
872}
873
874impl<'a, T> Copy for SharedReference<'a, T> {
875
876}
877
878impl<'a, T> SharedReference<'a, T> {
879    pub uninterp spec fn value(self) -> T;
880
881    pub uninterp spec fn ptr(self) -> *const T;
882
883    #[verifier::external_body]
884    fn new(t: &'a T) -> (s: Self)
885        ensures
886            s.value() == t,
887    {
888        SharedReference(t)
889    }
890
891    #[verifier::external_body]
892    fn as_ref(self) -> (t: &'a T)
893        ensures
894            t == self.value(),
895    {
896        self.0
897    }
898
899    #[verifier::external_body]
900    fn as_ptr(self) -> (ptr: *const T)
901        ensures
902            ptr == self.ptr(),
903    {
904        &*self.0
905    }
906
907    pub axiom fn points_to(tracked self) -> (tracked pt: &'a PointsTo<T>)
908        ensures
909            pt.ptr() == self.ptr(),
910            pt.is_init(),
911            pt.value() == self.value(),
912    ;
913}
914
915/// Like [`ptr_ref`] but returns a `SharedReference` so it keeps track of the relationship
916/// between the pointers.
917/// Note the resulting reference's pointers does NOT have the same provenance.
918/// This is because in Rust models like Stacked Borrows / Tree Borrows, the pointer
919/// gets a new tag.
920#[inline(always)]
921#[verifier::external_body]
922pub fn ptr_ref2<'a, T>(ptr: *const T, Tracked(perm): Tracked<&PointsTo<T>>) -> (v: SharedReference<
923    'a,
924    T,
925>)
926    requires
927        perm.ptr() == ptr,
928        perm.is_init(),
929    ensures
930        v.value() == perm.value(),
931        v.ptr().addr() == ptr.addr(),
932        v.ptr()@.metadata == ptr@.metadata,
933    opens_invariants none
934    no_unwind
935{
936    SharedReference(unsafe { &*ptr })
937}
938
939} // verus!