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