zerocopy/pointer/
invariant.rs

1// Copyright 2024 The Fuchsia Authors
2//
3// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6// This file may not be copied, modified, or distributed except according to
7// those terms.
8
9#![allow(missing_copy_implementations, missing_debug_implementations)]
10
11//! The parameterized invariants of a [`Ptr`][super::Ptr].
12//!
13//! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`])
14//! triples implementing the [`Invariants`] trait.
15
16/// The invariants of a [`Ptr`][super::Ptr].
17pub trait Invariants: Sealed {
18    type Aliasing: Aliasing;
19    type Alignment: Alignment;
20    type Validity: Validity;
21}
22
23impl<A: Aliasing, AA: Alignment, V: Validity> Invariants for (A, AA, V) {
24    type Aliasing = A;
25    type Alignment = AA;
26    type Validity = V;
27}
28
29/// The aliasing invariant of a [`Ptr`][super::Ptr].
30///
31/// All aliasing invariants must permit reading from the bytes of a pointer's
32/// referent which are not covered by [`UnsafeCell`]s.
33///
34/// [`UnsafeCell`]: core::cell::UnsafeCell
35pub trait Aliasing: Sealed {
36    /// Is `Self` [`Exclusive`]?
37    #[doc(hidden)]
38    const IS_EXCLUSIVE: bool;
39}
40
41/// The alignment invariant of a [`Ptr`][super::Ptr].
42pub trait Alignment: Sealed {}
43
44/// The validity invariant of a [`Ptr`][super::Ptr].
45///
46/// # Safety
47///
48/// In this section, we will use `Ptr<T, V>` as a shorthand for `Ptr<T, I:
49/// Invariants<Validity = V>>` for brevity.
50///
51/// Each `V: Validity` defines a set of bit values which may appear in the
52/// referent of a `Ptr<T, V>`, denoted `S(T, V)`. Each `V: Validity`, in its
53/// documentation, provides a definition of `S(T, V)` which must be valid for
54/// all `T: ?Sized`. Any `V: Validity` must guarantee that this set is only a
55/// function of the *bit validity* of the referent type, `T`, and not of any
56/// other property of `T`. As a consequence, given `V: Validity`, `T`, and `U`
57/// where `T` and `U` have the same bit validity, `S(V, T) = S(V, U)`.
58///
59/// It is guaranteed that the referent of any `ptr: Ptr<T, V>` is a member of
60/// `S(T, V)`. Unsafe code must ensure that this guarantee will be upheld for
61/// any existing `Ptr`s or any `Ptr`s that that code creates.
62///
63/// An important implication of this guarantee is that it restricts what
64/// transmutes are sound, where "transmute" is used in this context to refer to
65/// changing the referent type or validity invariant of a `Ptr`, as either
66/// change may change the set of bit values permitted to appear in the referent.
67/// In particular, the following are necessary (but not sufficient) conditions
68/// in order for a transmute from `src: Ptr<T, V>` to `dst: Ptr<U, W>` to be
69/// sound:
70/// - If `S(T, V) = S(U, W)`, then no restrictions apply; otherwise,
71/// - If `dst` permits mutation of its referent (e.g. via `Exclusive` aliasing
72///   or interior mutation under `Shared` aliasing), then it must hold that
73///   `S(T, V) ⊇ S(U, W)` - in other words, the transmute must not expand the
74///   set of allowed referent bit patterns. A violation of this requirement
75///   would permit using `dst` to write `x` where `x ∈ S(U, W)` but `x ∉ S(T,
76///   V)`, which would violate the guarantee that `src`'s referent may only
77///   contain values in `S(T, V)`.
78/// - If the referent may be mutated without going through `dst` while `dst` is
79///   live (e.g. via interior mutation on a `Shared`-aliased `Ptr` or `&`
80///   reference), then it must hold that `S(T, V) ⊆ S(U, W)` - in other words,
81///   the transmute must not shrink the set of allowed referent bit patterns. A
82///   violation of this requirement would permit using `src` or another
83///   mechanism (e.g. a `&` reference used to derive `src`) to write `x` where
84///   `x ∈ S(T, V)` but `x ∉ S(U, W)`, which would violate the guarantee that
85///   `dst`'s referent may only contain values in `S(U, W)`.
86pub unsafe trait Validity: Sealed {}
87
88/// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`].
89///
90/// # Safety
91///
92/// Given `A: Reference`, callers may assume that either `A = Shared` or `A =
93/// Exclusive`.
94pub trait Reference: Aliasing + Sealed {}
95
96/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`.
97///
98/// The referent of a shared-aliased `Ptr` may be concurrently referenced by any
99/// number of shared-aliased `Ptr` or `&T` references, or by any number of
100/// `Ptr<U>` or `&U` references as permitted by `T`'s library safety invariants,
101/// and may not be concurrently referenced by any exclusively-aliased `Ptr`s or
102/// `&mut` references. The referent must not be mutated, except via
103/// [`UnsafeCell`]s, and only when permitted by `T`'s library safety invariants.
104///
105/// [`UnsafeCell`]: core::cell::UnsafeCell
106pub enum Shared {}
107impl Aliasing for Shared {
108    const IS_EXCLUSIVE: bool = false;
109}
110impl Reference for Shared {}
111
112/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`.
113///
114/// The referent of an exclusively-aliased `Ptr` may not be concurrently
115/// referenced by any other `Ptr`s or references, and may not be accessed (read
116/// or written) other than via this `Ptr`.
117pub enum Exclusive {}
118impl Aliasing for Exclusive {
119    const IS_EXCLUSIVE: bool = true;
120}
121impl Reference for Exclusive {}
122
123/// It is unknown whether the pointer is aligned.
124pub enum Unaligned {}
125
126impl Alignment for Unaligned {}
127
128/// The referent is aligned: for `Ptr<T>`, the referent's address is a multiple
129/// of the `T`'s alignment.
130pub enum Aligned {}
131impl Alignment for Aligned {}
132
133/// Any bit pattern is allowed in the `Ptr`'s referent, including uninitialized
134/// bytes.
135pub enum Uninit {}
136// SAFETY: `Uninit`'s validity is well-defined for all `T: ?Sized`, and is not a
137// function of any property of `T` other than its bit validity (in fact, it's
138// not even a property of `T`'s bit validity, but this is more than we are
139// required to uphold).
140unsafe impl Validity for Uninit {}
141
142/// The byte ranges initialized in `T` are also initialized in the referent of a
143/// `Ptr<T>`.
144///
145/// Formally: uninitialized bytes may only be present in `Ptr<T>`'s referent
146/// where they are guaranteed to be present in `T`. This is a dynamic property:
147/// if, at a particular byte offset, a valid enum discriminant is set, the
148/// subsequent bytes may only have uninitialized bytes as specificed by the
149/// corresponding enum.
150///
151/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in
152/// the range `[0, len)`:
153/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t`
154///   is initialized, then the byte at offset `b` within `*ptr` must be
155///   initialized.
156/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be
157///   the subset of valid instances of `T` of length `len` which contain `c` in
158///   the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte
159///   at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr`
160///   must be initialized.
161///
162///   Pragmatically, this means that if `*ptr` is guaranteed to contain an enum
163///   type at a particular offset, and the enum discriminant stored in `*ptr`
164///   corresponds to a valid variant of that enum type, then it is guaranteed
165///   that the appropriate bytes of `*ptr` are initialized as defined by that
166///   variant's bit validity (although note that the variant may contain another
167///   enum type, in which case the same rules apply depending on the state of
168///   its discriminant, and so on recursively).
169pub enum AsInitialized {}
170// SAFETY: `AsInitialized`'s validity is well-defined for all `T: ?Sized`, and
171// is not a function of any property of `T` other than its bit validity.
172unsafe impl Validity for AsInitialized {}
173
174/// The byte ranges in the referent are fully initialized. In other words, if
175/// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`.
176pub enum Initialized {}
177// SAFETY: `Initialized`'s validity is well-defined for all `T: ?Sized`, and is
178// not a function of any property of `T` other than its bit validity (in fact,
179// it's not even a property of `T`'s bit validity, but this is more than we are
180// required to uphold).
181unsafe impl Validity for Initialized {}
182
183/// The referent of a `Ptr<T>` is valid for `T`, upholding bit validity and any
184/// library safety invariants.
185pub enum Valid {}
186// SAFETY: `Valid`'s validity is well-defined for all `T: ?Sized`, and is not a
187// function of any property of `T` other than its bit validity.
188unsafe impl Validity for Valid {}
189
190/// # Safety
191///
192/// `DT: CastableFrom<ST, SV, DV>` is sound if `SV = DV = Uninit` or `SV = DV =
193/// Initialized`.
194pub unsafe trait CastableFrom<ST: ?Sized, SV, DV> {}
195
196// SAFETY: `SV = DV = Uninit`.
197unsafe impl<ST: ?Sized, DT: ?Sized> CastableFrom<ST, Uninit, Uninit> for DT {}
198// SAFETY: `SV = DV = Initialized`.
199unsafe impl<ST: ?Sized, DT: ?Sized> CastableFrom<ST, Initialized, Initialized> for DT {}
200
201/// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations.
202///
203/// `T: Read<A, R>` implies that a pointer to `T` with aliasing `A` permits
204/// unsynchronized read oeprations. This can be because `A` is [`Exclusive`] or
205/// because `T` does not permit interior mutation.
206///
207/// # Safety
208///
209/// `T: Read<A, R>` if either of the following conditions holds:
210/// - `A` is [`Exclusive`]
211/// - `T` implements [`Immutable`](crate::Immutable)
212///
213/// As a consequence, if `T: Read<A, R>`, then any `Ptr<T, (A, ...)>` is
214/// permitted to perform unsynchronized reads from its referent.
215pub trait Read<A: Aliasing, R> {}
216
217impl<A: Aliasing, T: ?Sized + crate::Immutable> Read<A, BecauseImmutable> for T {}
218impl<T: ?Sized> Read<Exclusive, BecauseExclusive> for T {}
219
220/// Unsynchronized reads are permitted because only one live [`Ptr`](crate::Ptr)
221/// or reference may exist to the referent bytes at a time.
222#[derive(Copy, Clone, Debug)]
223#[doc(hidden)]
224pub enum BecauseExclusive {}
225
226/// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s or
227/// references permit interior mutation.
228#[derive(Copy, Clone, Debug)]
229#[doc(hidden)]
230pub enum BecauseImmutable {}
231
232use sealed::Sealed;
233mod sealed {
234    use super::*;
235
236    pub trait Sealed {}
237
238    impl Sealed for Shared {}
239    impl Sealed for Exclusive {}
240
241    impl Sealed for Unaligned {}
242    impl Sealed for Aligned {}
243
244    impl Sealed for Uninit {}
245    impl Sealed for AsInitialized {}
246    impl Sealed for Initialized {}
247    impl Sealed for Valid {}
248
249    impl<A: Sealed, AA: Sealed, V: Sealed> Sealed for (A, AA, V) {}
250
251    impl Sealed for BecauseImmutable {}
252    impl Sealed for BecauseExclusive {}
253}