creusot_std/ghost/invariant.rs
1//! Resource invariants.
2//!
3//! Resource invariants allow the use of a shared piece of data to be used in
4//! the invariant (see [`Protocol`]), but in return they impose a much more
5//! restricted access to the underlying data, as well as the use of [`Tokens`].
6//!
7//! [Atomic invariants](AtomicInvariant) are used to specify concurrent
8//! operations.
9//!
10//! [Non-atomic invariants](NonAtomicInvariant) are used to specify thread-local
11//! operations.
12//!
13//! Not to be confused with [loop invariants][crate::macros::invariant] or
14//! [type invariants][crate::invariant::Invariant].
15//!
16//! # Example
17//!
18//! Building a simplified `Cell`, that only asserts its content's type invariant.
19//! ```
20//! # use creusot_std::{
21//! # cell::PCell,
22//! # ghost::{
23//! # invariant::{NonAtomicInvariant, Protocol, Tokens, declare_namespace},
24//! # perm::Perm,
25//! # },
26//! # logic::Id,
27//! # prelude::*,
28//! # };
29//! declare_namespace! { PERMCELL }
30//!
31//! /// A cell that simply asserts its content's type invariant.
32//! pub struct CellInv<T: Invariant> {
33//! data: PCell<T>,
34//! permission: Ghost<NonAtomicInvariant<PCellNAInv<T>>>,
35//! }
36//! impl<T: Invariant> Invariant for CellInv<T> {
37//! #[logic]
38//! fn invariant(self) -> bool {
39//! self.permission.namespace() == PERMCELL() && self.permission.public() == self.data.id()
40//! }
41//! }
42//!
43//! struct PCellNAInv<T>(Perm<PCell<T>>);
44//! impl<T: Invariant> Protocol for PCellNAInv<T> {
45//! type Public = Id;
46//!
47//! #[logic]
48//! fn public(self) -> Id { self.0.id() }
49//!
50//! #[logic]
51//! fn protocol(self) -> bool { true }
52//! }
53//!
54//! impl<T: Invariant> CellInv<T> {
55//! #[requires(tokens.contains(PERMCELL()))]
56//! pub fn write(&self, x: T, tokens: Ghost<Tokens>) {
57//! ghost_let!(perm = &mut self.permission.open(tokens.into_inner()).inner.0);
58//! unsafe { *self.data.borrow_mut(perm) = x }
59//! }
60//! }
61//! ```
62//!
63//! # Explicit tokens
64//!
65//! For now, [`Tokens`] must be explicitely passed to [`open`](NonAtomicInvariant::open).
66//! We plan to relax this limitation at some point.
67
68#![allow(unused_variables)]
69
70use crate::{
71 ghost::{FnGhost, Plain},
72 invariant::{GuardRef, Guarded},
73 logic::Set,
74 prelude::*,
75};
76use core::marker::PhantomData;
77
78#[cfg(creusot)]
79use crate::ghost::Objective;
80
81/// Declare a new namespace.
82///
83/// # Example
84///
85/// ```rust
86/// use creusot_std::{ghost::invariant::{declare_namespace, Namespace}, logic::Set, prelude::*};
87/// declare_namespace! { A }
88///
89/// #[requires(ns.contains(A()))]
90/// fn foo(ns: Ghost<&mut Set<Namespace>>) { /* ... */ }
91/// ```
92pub use base_macros::declare_namespace;
93
94/// The type of _namespaces_ of associated with non-atomic invariants.
95///
96/// Can be declared with the [`declare_namespace`] macro, and then attached to a non-atomic
97/// invariant when creating it with [`NonAtomicInvariant::new`].
98#[intrinsic("namespace")]
99pub struct Namespace(());
100
101impl Clone for Namespace {
102 #[check(ghost)]
103 #[ensures(result == *self)]
104 fn clone(&self) -> Self {
105 *self
106 }
107}
108impl Copy for Namespace {}
109
110impl Plain for Namespace {
111 #[trusted]
112 #[ensures(*result == *snap)]
113 #[check(ghost)]
114 #[allow(unused_variables)]
115 fn into_ghost(snap: Snapshot<Self>) -> Ghost<Self> {
116 Ghost::conjure()
117 }
118}
119
120/// Invariant tokens.
121///
122/// This is given at the start of the program, and must be passed along to
123/// [NonAtomicInvariant::open] to prevent opening invariant reentrantly.
124///
125/// # Tokens and `open`
126///
127/// Tokens are used to avoid reentrency in [`open`](NonAtomicInvariant::open).
128/// To ensure this, `Tokens` acts as a special kind of mutable borrow : only
129/// one may exist at a given point in the program, preventing multiple calls to
130/// `open` with the same namespace. This is the reason this type has a lifetime
131/// attached to it.
132///
133/// Note that after the execution of `open`, the token that was used is
134/// restored. Because of this, we never need to talk about the 'final' value
135/// of this borrow, because it never differs from the current value (in places
136/// where we can use it).
137///
138/// To help passing it into functions, it may be [reborrowed](Self::reborrow),
139/// similarly to a normal borrow.
140#[opaque]
141// `*mut ()` so that Tokens are neither Send nor Sync
142pub struct Tokens<'a>(PhantomData<&'a ()>, PhantomData<*mut ()>);
143
144impl<'a> Tokens<'a> {
145 /// Get the underlying set of namespaces of this token.
146 ///
147 /// Also accessible via the [`view`](View::view) (`@`) operator.
148 #[logic(opaque)]
149 pub fn namespaces(self) -> Set<Namespace> {
150 dead
151 }
152
153 /// Get the tokens for all the namespaces.
154 ///
155 /// This is only callable _once_, in `main`.
156 #[trusted]
157 #[ensures(forall<ns: Namespace> result.contains(ns))]
158 #[intrinsic("tokens_new")]
159 #[check(ghost)]
160 pub fn new() -> Ghost<Self> {
161 Ghost::conjure()
162 }
163
164 /// Reborrow the token, allowing it to be reused later.
165 ///
166 /// # Example
167 /// ```
168 /// # use creusot_std::{ghost::invariant::Tokens, prelude::*};
169 /// fn foo(tokens: Ghost<Tokens>) {}
170 /// fn bar(tokens: Ghost<Tokens>) {}
171 /// fn baz(mut tokens: Ghost<Tokens>) {
172 /// foo(ghost!(tokens.reborrow()));
173 /// bar(tokens);
174 /// }
175 /// ```
176 #[trusted]
177 #[ensures(result == *self && ^self == *self)]
178 #[check(ghost)]
179 pub fn reborrow<'b>(&'b mut self) -> Tokens<'b> {
180 Tokens(PhantomData, PhantomData)
181 }
182
183 /// Split the tokens in two, so that it can be used to access independent invariants.
184 ///
185 /// # Example
186 ///
187 /// ```
188 /// # use creusot_std::{ghost::invariant::{declare_namespace, Tokens}, prelude::*};
189 /// declare_namespace! { FOO }
190 /// declare_namespace! { BAR }
191 ///
192 /// // the lifetime 'locks' the namespace
193 /// #[requires(tokens.contains(FOO()))]
194 /// fn foo<'a>(tokens: Ghost<Tokens<'a>>) -> &'a i32 {
195 /// # todo!()
196 /// // access some invariant to get the reference
197 /// }
198 /// #[requires(tokens.contains(BAR()))]
199 /// fn bar(tokens: Ghost<Tokens>) {}
200 ///
201 /// #[requires(tokens.contains(FOO()) && tokens.contains(BAR()))]
202 /// fn baz(tokens: Ghost<Tokens>) -> i32 {
203 /// let (ns_foo, ns_bar) = ghost!(tokens.into_inner().split(snapshot!(FOO()))).split();
204 /// let x = foo(ns_foo);
205 /// bar(ns_bar);
206 /// *x
207 /// }
208 /// ```
209 #[trusted]
210 #[requires(self.contains(*ns))]
211 #[ensures(result.0.contains(*ns))]
212 #[ensures(result.1.namespaces() == self.namespaces().remove(*ns))]
213 #[check(ghost)]
214 pub fn split(self, ns: Snapshot<Namespace>) -> (Tokens<'a>, Tokens<'a>) {
215 (Tokens(PhantomData, PhantomData), Tokens(PhantomData, PhantomData))
216 }
217
218 #[logic(open)]
219 pub fn contains(self, namespace: Namespace) -> bool {
220 self.namespaces().contains(namespace)
221 }
222}
223
224impl View for Tokens<'_> {
225 type ViewTy = Set<Namespace>;
226 #[logic(open, inline)]
227 fn view(self) -> Set<Namespace> {
228 self.namespaces()
229 }
230}
231
232/// A variant of [`Invariant`] for use in `AtomicInvariantSC`s,
233/// [`AtomicInvariant`]s and [`NonAtomicInvariant`]s.
234///
235/// This allows specifying an invariant that depends on some public
236/// data (`AtomicInvariantSC::public`, [`AtomicInvariant::public`],
237/// [`NonAtomicInvariant::public`]).
238pub trait Protocol {
239 type Public;
240
241 /// The public data of the invariant, derived from the inner content.
242 ///
243 /// It is called public, because it is visible simply by holding the
244 /// invariant, without needing to open it.
245 ///
246 /// Because of this, calls to `open` must not modify this value.
247 #[logic]
248 fn public(self) -> Self::Public;
249
250 /// The protocol for the invariant.
251 ///
252 /// When opening the invariant ([`AtomicInvariantSC::open`],
253 /// [`AtomicInvariant::open`], [`NonAtomicInvariant::open`]), the data in
254 /// guaranteed to respect this protocol; then, you must ensure that it is
255 /// still verified when the invariant is closed.
256 #[logic(prophetic)]
257 fn protocol(self) -> bool;
258}
259
260/// A shareable invariant for sequentially consistent accesses between threads.
261///
262/// If you need non-sequentially consistent accesses, use [`AtomicInvariant`].
263///
264/// If you do not need to share the invariant across threads, see
265/// [`NonAtomicInvariant`].
266#[cfg(feature = "sc-drf")]
267#[opaque]
268pub struct AtomicInvariantSC<T>(PhantomData<*mut T>);
269
270#[cfg(feature = "sc-drf")]
271#[trusted]
272unsafe impl<T: Send> Sync for AtomicInvariantSC<T> {}
273
274#[cfg(feature = "sc-drf")]
275#[trusted]
276unsafe impl<T: Send> Send for AtomicInvariantSC<T> {}
277
278#[cfg(feature = "sc-drf")]
279impl<T: Protocol> AtomicInvariantSC<T> {
280 /// Construct a `AtomicInvariantSC`, aka a sequentially consistent atomic invariant.
281 ///
282 /// # Parameters
283 ///
284 /// - `value`: the actual data contained in the invariant. Use [`Self::open`] to
285 /// access it. Also called the 'private' part of the invariant.
286 /// - `namespace`: the namespace of the invariant.
287 /// This is required to avoid [open](Self::open)ing the same invariant twice.
288 #[trusted]
289 #[requires(value.protocol())]
290 #[ensures(result.public() == value.public())]
291 #[ensures(result.namespace() == *namespace)]
292 #[check(ghost)]
293 pub fn new(value: Ghost<T>, namespace: Snapshot<Namespace>) -> Ghost<Self> {
294 Ghost::conjure()
295 }
296
297 /// Get the namespace associated with this invariant.
298 #[logic(opaque)]
299 pub fn namespace(self) -> Namespace {
300 dead
301 }
302
303 /// Get the 'public' part of this invariant.
304 #[logic(opaque)]
305 pub fn public(self) -> T::Public {
306 dead
307 }
308
309 /// Gives the actual invariant held by the `AtomicInvariantSC`.
310 #[trusted]
311 #[ensures(result.public() == self.public() && result.protocol())]
312 #[check(ghost)]
313 pub fn into_inner(self) -> T {
314 panic!("Should not be called outside ghost code")
315 }
316
317 /// Open the invariant to get the data stored inside.
318 ///
319 /// This will call the closure `f` with the inner data. You must restore the
320 /// contained [`Protocol`] before returning from the closure.
321 ///
322 /// NOTE: This function can only be called from ghost code, because atomic
323 /// invariants are always wrapped in `Ghost`. This guarantees atomicity.
324 #[trusted]
325 #[requires(tokens.contains(self.namespace()))]
326 #[requires(forall<t: &mut T> t.public() == self.public() && t.protocol() && inv(t) ==>
327 f.precondition((t,)) &&
328 // f must restore the invariant
329 (forall<res: A> f.postcondition_once((t,), res) ==> (^t).public() == self.public() && (^t).protocol()))]
330 #[ensures(exists<t: &mut T> t.public() == self.public() && t.protocol() && inv(t) &&
331 f.postcondition_once((t,), result))]
332 #[check(ghost)]
333 pub fn open<A>(&self, tokens: Tokens, f: impl FnGhost + for<'a> FnOnce(&'a mut T) -> A) -> A {
334 panic!("Should not be called outside ghost code")
335 }
336
337 /// Open the invariant to get the data stored inside. The
338 /// [protocol](Protocol) must be restored by the end of the returned
339 /// borrow's lifetime.
340 ///
341 /// This requires a mutable borrow on the invariant, but in exchange, you
342 /// are allowed to change the public part of the invariant.
343 ///
344 /// See [`Self::open`] for a version that only need a shared borrow,
345 /// but cannot change the public part.
346 #[trusted]
347 #[check(ghost)]
348 #[ensures(result.inner.public() == self.public())]
349 #[ensures((^result.inner).public() == (^self).public())]
350 #[ensures((^self).namespace() == (*self).namespace())]
351 pub fn open_mut(&mut self) -> Guarded<&mut T, OpenMutGuard> {
352 unreachable!("ghost code only")
353 }
354}
355
356/// A shareable invariant for atomic accesses between threads.
357///
358/// If you need _sequentially consistent_ accesses, use [`AtomicInvariant`].
359///
360/// If you do not need to share the invariant across threads, see
361/// [`NonAtomicInvariant`].
362#[opaque]
363pub struct AtomicInvariant<T>(PhantomData<*mut T>);
364
365// TODO: Find a real hack to achieve this.
366#[cfg(creusot)]
367#[trusted]
368unsafe impl<T: Send + Objective> Sync for AtomicInvariant<T> {}
369#[cfg(not(creusot))]
370unsafe impl<T: Send> Sync for AtomicInvariant<T> {}
371
372#[trusted]
373unsafe impl<T: Send> Send for AtomicInvariant<T> {}
374
375impl<T: Protocol> AtomicInvariant<T> {
376 /// Construct a `AtomicInvariant`
377 ///
378 /// # Parameters
379 /// - `value`: the actual data contained in the invariant. Use [`Self::open`] to
380 /// access it. Also called the 'private' part of the invariant.
381 /// - `namespace`: the namespace of the invariant.
382 /// This is required to avoid [open](Self::open)ing the same invariant twice.
383 #[trusted]
384 #[requires(value.protocol())]
385 #[ensures(result.public() == value.public())]
386 #[ensures(result.namespace() == *namespace)]
387 #[check(ghost)]
388 pub fn new(value: Ghost<T>, namespace: Snapshot<Namespace>) -> Ghost<Self> {
389 Ghost::conjure()
390 }
391
392 /// Get the namespace associated with this invariant.
393 #[logic(opaque)]
394 pub fn namespace(self) -> Namespace {
395 dead
396 }
397
398 /// Get the 'public' part of this invariant.
399 #[logic(opaque)]
400 pub fn public(self) -> T::Public {
401 dead
402 }
403
404 /// Gives the actual invariant held by the `AtomicInvariant`.
405 #[trusted]
406 #[ensures(result.public() == self.public() && result.protocol())]
407 #[check(ghost)]
408 pub fn into_inner(self) -> T {
409 panic!("Should not be called outside ghost code")
410 }
411
412 /// Open the invariant to get the data stored inside.
413 ///
414 /// This will call the closure `f` with the inner data. You must restore the
415 /// contained [`Protocol`] before returning from the closure.
416 ///
417 /// NOTE: This function can only be called from ghost code, because atomic
418 /// invariants are always wrapped in `Ghost`. This guarantees atomicity.
419 #[trusted]
420 #[requires(tokens.contains(self.namespace()))]
421 #[requires(forall<t: &mut T> t.public() == self.public() && t.protocol() && inv(t) ==>
422 f.precondition((t,)) &&
423 // f must restore the invariant
424 (forall<res: A> f.postcondition_once((t,), res) ==> (^t).public() == self.public() && (^t).protocol()))]
425 #[ensures(exists<t: &mut T> t.public() == self.public() && t.protocol() && inv(t) &&
426 f.postcondition_once((t,), result))]
427 #[check(ghost)]
428 pub fn open<A>(&self, tokens: Tokens, f: impl FnGhost + for<'a> FnOnce(&'a mut T) -> A) -> A {
429 panic!("Should not be called outside ghost code")
430 }
431
432 /// Open the invariant to get the data stored inside. The
433 /// [protocol](Protocol) must be restored by the end of the returned
434 /// borrow's lifetime.
435 ///
436 /// This requires a mutable borrow on the invariant, but in exchange, you
437 /// are allowed to change the public part of the invariant.
438 ///
439 /// See [`Self::open`] for a version that only need a shared borrow,
440 /// but cannot change the public part.
441 #[trusted]
442 #[check(ghost)]
443 #[ensures(result.inner.public() == self.public())]
444 #[ensures((^result.inner).public() == (^self).public())]
445 #[ensures((^self).namespace() == (*self).namespace())]
446 pub fn open_mut(&mut self) -> Guarded<&mut T, OpenMutGuard> {
447 unreachable!("ghost code only")
448 }
449}
450
451/// A ghost structure, that holds a piece of data (`T`) together with an
452/// [protocol](Protocol).
453///
454/// # Note
455///
456/// `NonAtomicInvariant` is not [`Sync`], and is invariant in the underlying data.
457/// - It is not `Sync` precisely because it is non-atomic, so access to the data is unsynchronized.
458/// - It is invariant because it gives access to a mutable borrow of this data.
459///
460/// If you need to share an invariant across threads, consider
461/// `AtomicInvariantSC` or [`AtomicInvariant`].
462#[opaque]
463pub struct NonAtomicInvariant<T: Protocol>(PhantomData<*mut T>);
464
465#[trusted]
466unsafe impl<T: Protocol> Send for NonAtomicInvariant<T> {}
467
468/// Guard for [`NonAtomicInvariant::open`].
469///
470/// This contains the public value, that must be unchanged for the
471/// borrow. Additionally, the guard asserts that the borrow satisfies its
472/// [protocol](Protocol).
473pub struct OpenGuard<T: Protocol>(pub T::Public);
474
475impl<T: Protocol> GuardRef<T> for OpenGuard<T> {
476 #[logic(open, prophetic, inline)]
477 fn guards_ref(self, b: T) -> bool {
478 b.public() == self.0 && b.protocol()
479 }
480}
481
482/// Guard for [`NonAtomicInvariant::open_mut`].
483pub struct OpenMutGuard;
484impl<T: Protocol> GuardRef<T> for OpenMutGuard {
485 #[logic(open, prophetic, inline)]
486 fn guards_ref(self, x: T) -> bool {
487 x.protocol()
488 }
489}
490
491impl<T: Protocol> NonAtomicInvariant<T> {
492 /// Construct a `NonAtomicInvariant`
493 ///
494 /// # Parameters
495 ///
496 /// - `value`: the actual data contained in the invariant. Use [`Self::open`] to
497 /// access it. Also called the 'private' part of the invariant.
498 /// - `namespace`: the namespace of the invariant.
499 /// This is required to avoid [open](Self::open)ing the same invariant twice.
500 #[trusted]
501 #[requires(value.protocol())]
502 #[ensures(result.public() == value.public())]
503 #[ensures(result.namespace() == *namespace)]
504 #[check(ghost)]
505 pub fn new(value: Ghost<T>, namespace: Snapshot<Namespace>) -> Ghost<Self> {
506 Ghost::conjure()
507 }
508
509 /// Gives the actual invariant held by the `NonAtomicInvariant`.
510 #[trusted]
511 #[ensures(result.public() == self.public() && result.protocol())]
512 #[check(ghost)]
513 pub fn into_inner(self) -> T {
514 panic!("Should not be called outside ghost code")
515 }
516
517 /// Get the namespace associated with this invariant.
518 #[logic(opaque)]
519 pub fn namespace(self) -> Namespace {
520 dead
521 }
522
523 /// Get the 'public' part of this invariant.
524 #[logic(opaque)]
525 pub fn public(self) -> T::Public {
526 dead
527 }
528
529 /// Open the invariant to get the data stored inside.
530 ///
531 /// The returned borrow satisfies the [protocol](Protocol) on `T`.
532 /// This protocol must be re-established before this borrow ends, with the same [public value](Protocol::public).
533 ///
534 /// # Notes on `ghost_let`
535 ///
536 /// The [`Guarded`] type can assert its type invariant at inconvenient times.
537 /// To work around this, it is often desirable to use a [`ghost_let`] to extract the inner borrow, and be able to freely break the protocol during its lifetime:
538 /// ```
539 /// use creusot_std::{
540 /// ghost::invariant::{NonAtomicInvariant, Protocol, Tokens, declare_namespace},
541 /// prelude::*,
542 /// };
543 /// struct Gt0(i32);
544 /// impl Protocol for Gt0 {
545 /// type Public = ();
546 /// #[logic] fn public(self) {}
547 /// #[logic] fn protocol(self) -> bool { self.0 > 0i32 }
548 /// }
549 ///
550 /// declare_namespace! { NS }
551 ///
552 /// #[requires(tokens.contains(NS()))]
553 /// fn foo(tokens: Ghost<Tokens>) {
554 /// let inv = NonAtomicInvariant::new(ghost!(Gt0(1i32)), snapshot!(NS()));
555 /// // ...
556 /// ghost_let!(mut gt = &mut *inv.open(tokens.into_inner()).inner);
557 ///
558 /// ghost! { gt.0 = -1 };
559 /// // ... maybe do some non-ghost operations here ...
560 /// ghost! { gt.0 = 2 };
561 /// }
562 /// ```
563 ///
564 /// If we were using the `guard` variable directly, the type invariant (and
565 /// thus the protocol) would be asserted at the end of each `ghost! { gt.0 =
566 /// ... }` block, and the first would fail.
567 #[trusted]
568 #[requires(tokens.contains(self.namespace()))]
569 #[ensures(result.guard().0 == self.public())]
570 #[check(ghost)]
571 pub fn open<'a>(&'a self, tokens: Tokens<'a>) -> Guarded<&'a mut T, OpenGuard<T>> {
572 panic!("Should not be called outside ghost code")
573 }
574
575 /// Open the invariant to get the data stored inside, immutably.
576 /// This allows reentrant access to the invariant.
577 #[trusted]
578 #[requires(tokens.contains(self.namespace()))]
579 #[ensures(result.public() == self.public() && result.protocol())]
580 #[check(ghost)]
581 pub fn open_const<'a>(&'a self, tokens: &'a Tokens) -> &'a T {
582 panic!("Should not be called outside ghost code")
583 }
584
585 /// Open the invariant to get the data stored inside. The
586 /// [protocol](Protocol) must be restored by the end of the returned
587 /// borrow's lifetime.
588 ///
589 /// This requires a mutable borrow on the invariant, but in exchange, you
590 /// are allowed to change the public part of the invariant.
591 ///
592 /// See [`Self::open`] for a version that only need a shared borrow,
593 /// but cannot change the public part.
594 #[trusted]
595 #[check(ghost)]
596 #[ensures(result.inner.public() == self.public())]
597 #[ensures((^result.inner).public() == (^self).public())]
598 #[ensures((^self).namespace() == (*self).namespace())]
599 pub fn open_mut(&mut self) -> Guarded<&mut T, OpenMutGuard> {
600 unreachable!("ghost code only")
601 }
602}