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