xref: /linux/rust/zerocopy/src/pointer/invariant.rs (revision 12d5fc96ebbb3b948861805b32a4c3a96105ccd9)
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].
19 pub trait Invariants: Sealed {
20     type Aliasing: Aliasing;
21     type Alignment: Alignment;
22     type Validity: Validity;
23 }
24 
25 impl<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
37 pub 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].
44 pub 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.
100 pub unsafe trait Validity: Sealed {
101     const KIND: ValidityKind;
102 }
103 
104 pub 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`.
117 pub 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
129 pub enum Shared {}
130 impl Aliasing for Shared {
131     const IS_EXCLUSIVE: bool = false;
132 }
133 impl 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`.
140 pub enum Exclusive {}
141 impl Aliasing for Exclusive {
142     const IS_EXCLUSIVE: bool = true;
143 }
144 impl Reference for Exclusive {}
145 
146 /// It is unknown whether the pointer is aligned.
147 pub enum Unaligned {}
148 
149 impl 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.
163 pub enum Aligned {}
164 impl 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.
178 pub 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).
183 unsafe 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).
214 pub 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.
217 unsafe 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]`.
223 pub 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).
228 unsafe 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.
234 pub 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.
237 unsafe 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`.
252 pub unsafe trait CastableFrom<ST: ?Sized, SV, DV> {}
253 
254 // SAFETY: `SV = DV = Uninit`.
255 unsafe impl<ST: ?Sized, DT: ?Sized> CastableFrom<ST, Uninit, Uninit> for DT {}
256 // SAFETY: `SV = DV = Initialized`.
257 unsafe 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.
273 pub trait Read<A: Aliasing, R> {}
274 
275 impl<A: Aliasing, T: ?Sized + crate::Immutable> Read<A, BecauseImmutable> for T {}
276 impl<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)]
281 pub 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)]
286 pub enum BecauseImmutable {}
287 
288 use sealed::Sealed;
289 mod 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 }
310