Skip to main content

creusot_std/ghost/
perm.rs

1//! Generic permissions for accessing memory pointed to by pointers or within an interior mutable
2//! type.
3
4use crate::prelude::*;
5#[cfg(creusot)]
6use crate::resolve::structural_resolve;
7
8pub trait PermTarget {
9    type Value<'a>
10    where
11        Self: 'a;
12    type PermPayload: ?Sized;
13
14    #[logic(open, inline)]
15    fn is_disjoint(
16        &self,
17        _self_val: Self::Value<'_>,
18        other: &Self,
19        _other_val: Self::Value<'_>,
20    ) -> bool {
21        self != other
22    }
23}
24
25/// Token that represents the ownership of the contents of a container object. The container is
26/// either an interior mutable type (e.g., `Perm` or atomic types) or a raw pointer.
27///
28/// A `Perm` only exists in the ghost world, and it must be used in conjunction with its container
29/// in order to read or write the value.
30///
31/// Permissions are made unsized to guarantee that they cannot be replaced in a mutable reference.
32/// This would allow the permission to outlive the reference it has been placed in. This makes it
33/// easier to specify splitting a mutable reference of a permission to a slice, and makes it
34/// possible to specify functions such as [`Perm::from_mut`].
35///
36/// # Pointer permissions
37///
38/// A particular case of permissions is the case of permissions for raw pointers (i.e., `C` is
39/// `*const T`). In this case, the permission represents the ownership of the memory cell.
40///
41/// A warning regarding memory leaks: dropping a `Perm<*const T>` cannot deallocate the memory
42/// corresponding to the pointer because it is a ghost value. One must thus remember to explicitly
43/// call [`drop`] in order to free the memory tracked by a `Perm<*const T>` token.
44///
45/// ## Safety
46///
47/// When using Creusot to verify the code, all methods should be safe to call. Indeed,
48/// Creusot ensures that every operation on the inner value uses the right [`Perm`] object
49/// created by [`Perm::new`], ensuring safety in a manner similar to [ghost_cell](https://docs.rs/ghost-cell/latest/ghost_cell/).
50///
51/// ## `#[check(terminates)]`
52///
53/// `Perm<*const T>` methods, particularly constructors (`new`, `from_box`, `from_ref`, `from_mut`),
54/// are marked `check(terminates)` rather than `check(ghost)` to prevent two things from happening
55/// in ghost code:
56/// 1. running out of pointer addresses;
57/// 2. allocating too large objects.
58///
59/// Note that we already can't guard against these issues in program code.
60/// But preventing them in ghost code is even more imperative to ensure soundness.
61///
62/// Specifically, creating too many pointers contradicts the [`Perm::disjoint_lemma`],
63/// and allocating too large objects contradicts the [`Perm::invariant`] that
64/// allocations have size at most `isize::MAX`.
65///
66/// ## Layout facts
67///
68/// Certain facts about the layout and alignment of pointers can be made available
69/// through the type invariant of [`crate::std::ptr::PtrLive`] by calling [`Perm::live`].
70#[opaque]
71pub struct Perm<C: ?Sized + PermTarget>(#[allow(unused)] C::PermPayload);
72
73impl<C: ?Sized + PermTarget> Perm<C> {
74    /// Returns the underlying container that is managed by this permission.
75    #[logic(opaque)]
76    pub fn ward<'a>(self) -> &'a C {
77        dead
78    }
79
80    /// Get the logical value contained by the container.
81    #[logic(opaque)]
82    pub fn val<'a>(self) -> C::Value<'a> {
83        dead
84    }
85
86    /// If one owns two permissions in ghost code, then they correspond to different containers.
87    #[trusted]
88    #[check(ghost)]
89    #[ensures(self.ward().is_disjoint(self.val(), other.ward(), other.val()))]
90    #[ensures(*self == ^self)]
91    #[allow(unused_variables)]
92    pub fn disjoint_lemma(&mut self, other: &Self) {}
93}
94
95impl<C: ?Sized + PermTarget> Resolve for Perm<C> {
96    #[logic(open, prophetic, inline)]
97    #[creusot::trusted_trivial_if_param_trivial]
98    fn resolve(self) -> bool {
99        resolve(self.val())
100    }
101
102    #[trusted]
103    #[logic(prophetic)]
104    #[requires(inv(self))]
105    #[requires(structural_resolve(self))]
106    #[ensures(self.resolve())]
107    fn resolve_coherence(self) {}
108}