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