|
| 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]. |
| 17 | +pub trait Invariants: Sealed { |
| 18 | + type Aliasing: Aliasing; |
| 19 | + type Alignment: Alignment; |
| 20 | + type Validity: Validity; |
| 21 | +} |
| 22 | + |
| 23 | +impl<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 | +pub trait Aliasing: Sealed { |
| 31 | + /// Is `Self` [`Exclusive`]? |
| 32 | + #[doc(hidden)] |
| 33 | + const IS_EXCLUSIVE: bool; |
| 34 | +} |
| 35 | + |
| 36 | +/// The alignment invariant of a [`Ptr`][super::Ptr]. |
| 37 | +pub trait Alignment: Sealed {} |
| 38 | + |
| 39 | +/// The validity invariant of a [`Ptr`][super::Ptr]. |
| 40 | +pub trait Validity: Sealed {} |
| 41 | + |
| 42 | +/// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`]. |
| 43 | +/// |
| 44 | +/// # Safety |
| 45 | +/// |
| 46 | +/// Given `A: Reference`, callers may assume that either `A = Shared` or `A = |
| 47 | +/// Exclusive`. |
| 48 | +pub trait Reference: Aliasing + Sealed {} |
| 49 | + |
| 50 | +/// No requirement - any invariant is allowed. |
| 51 | +pub enum Any {} |
| 52 | +impl Aliasing for Any { |
| 53 | + const IS_EXCLUSIVE: bool = false; |
| 54 | +} |
| 55 | +impl Alignment for Any {} |
| 56 | +impl Validity for Any {} |
| 57 | + |
| 58 | +/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. |
| 59 | +/// |
| 60 | +/// The referent of a shared-aliased `Ptr` may be concurrently referenced by any |
| 61 | +/// number of shared-aliased `Ptr` or `&T` references, and may not be |
| 62 | +/// concurrently referenced by any exclusively-aliased `Ptr`s or `&mut T` |
| 63 | +/// references. The referent must not be mutated, except via [`UnsafeCell`]s. |
| 64 | +/// |
| 65 | +/// [`UnsafeCell`]: core::cell::UnsafeCell |
| 66 | +pub enum Shared {} |
| 67 | +impl Aliasing for Shared { |
| 68 | + const IS_EXCLUSIVE: bool = false; |
| 69 | +} |
| 70 | +impl Reference for Shared {} |
| 71 | + |
| 72 | +/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`. |
| 73 | +/// |
| 74 | +/// The referent of an exclusively-aliased `Ptr` may not be concurrently |
| 75 | +/// referenced by any other `Ptr`s or references, and may not be accessed (read |
| 76 | +/// or written) other than via this `Ptr`. |
| 77 | +pub enum Exclusive {} |
| 78 | +impl Aliasing for Exclusive { |
| 79 | + const IS_EXCLUSIVE: bool = true; |
| 80 | +} |
| 81 | +impl Reference for Exclusive {} |
| 82 | + |
| 83 | +/// The referent is aligned: for `Ptr<T>`, the referent's address is a multiple |
| 84 | +/// of the `T`'s alignment. |
| 85 | +pub enum Aligned {} |
| 86 | +impl Alignment for Aligned {} |
| 87 | + |
| 88 | +/// The byte ranges initialized in `T` are also initialized in the referent. |
| 89 | +/// |
| 90 | +/// Formally: uninitialized bytes may only be present in `Ptr<T>`'s referent |
| 91 | +/// where they are guaranteed to be present in `T`. This is a dynamic property: |
| 92 | +/// if, at a particular byte offset, a valid enum discriminant is set, the |
| 93 | +/// subsequent bytes may only have uninitialized bytes as specificed by the |
| 94 | +/// corresponding enum. |
| 95 | +/// |
| 96 | +/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in |
| 97 | +/// the range `[0, len)`: |
| 98 | +/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t` |
| 99 | +/// is initialized, then the byte at offset `b` within `*ptr` must be |
| 100 | +/// initialized. |
| 101 | +/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be |
| 102 | +/// the subset of valid instances of `T` of length `len` which contain `c` in |
| 103 | +/// the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte |
| 104 | +/// at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr` |
| 105 | +/// must be initialized. |
| 106 | +/// |
| 107 | +/// Pragmatically, this means that if `*ptr` is guaranteed to contain an enum |
| 108 | +/// type at a particular offset, and the enum discriminant stored in `*ptr` |
| 109 | +/// corresponds to a valid variant of that enum type, then it is guaranteed |
| 110 | +/// that the appropriate bytes of `*ptr` are initialized as defined by that |
| 111 | +/// variant's bit validity (although note that the variant may contain another |
| 112 | +/// enum type, in which case the same rules apply depending on the state of |
| 113 | +/// its discriminant, and so on recursively). |
| 114 | +pub enum AsInitialized {} |
| 115 | +impl Validity for AsInitialized {} |
| 116 | + |
| 117 | +/// The byte ranges in the referent are fully initialized. In other words, if |
| 118 | +/// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`. |
| 119 | +pub enum Initialized {} |
| 120 | +impl Validity for Initialized {} |
| 121 | + |
| 122 | +/// The referent is bit-valid for `T`. |
| 123 | +pub enum Valid {} |
| 124 | +impl Validity for Valid {} |
| 125 | + |
| 126 | +pub mod aliasing_safety { |
| 127 | + use super::*; |
| 128 | + use crate::Immutable; |
| 129 | + |
| 130 | + /// Pointer conversions which do not violate aliasing. |
| 131 | + /// |
| 132 | + /// `U: AliasingSafe<T, A, R>` implies that a pointer conversion from `T` to |
| 133 | + /// `U` does not violate the aliasing invariant, `A`. This can be because |
| 134 | + /// `A` is [`Exclusive`] or because neither `T` nor `U` permit interior |
| 135 | + /// mutability. |
| 136 | + /// |
| 137 | + /// # Safety |
| 138 | + /// |
| 139 | + /// `U: AliasingSafe<T, A, R>` if either of the following conditions holds: |
| 140 | + /// - `A` is [`Exclusive`] |
| 141 | + /// - `T` and `U` both implement [`Immutable`] |
| 142 | + #[doc(hidden)] |
| 143 | + pub unsafe trait AliasingSafe<T: ?Sized, A: Aliasing, R: AliasingSafeReason> {} |
| 144 | + |
| 145 | + #[doc(hidden)] |
| 146 | + pub trait AliasingSafeReason: sealed::Sealed {} |
| 147 | + impl<R: AliasingSafeReason> AliasingSafeReason for (R,) {} |
| 148 | + |
| 149 | + /// The conversion is safe because only one live `Ptr` or reference may exist to |
| 150 | + /// the referent bytes at a time. |
| 151 | + #[derive(Copy, Clone, Debug)] |
| 152 | + #[doc(hidden)] |
| 153 | + pub enum BecauseExclusive {} |
| 154 | + impl AliasingSafeReason for BecauseExclusive {} |
| 155 | + |
| 156 | + /// The conversion is safe because no live `Ptr`s or references permit mutation. |
| 157 | + #[derive(Copy, Clone, Debug)] |
| 158 | + #[doc(hidden)] |
| 159 | + pub enum BecauseImmutable {} |
| 160 | + impl AliasingSafeReason for BecauseImmutable {} |
| 161 | + |
| 162 | + /// SAFETY: `T: AliasingSafe<Exclusive, BecauseExclusive>` because for all |
| 163 | + /// `Ptr<'a, T, I>` such that `I::Aliasing = Exclusive`, there cannot exist |
| 164 | + /// other live references to the memory referenced by `Ptr`. |
| 165 | + unsafe impl<T: ?Sized, U: ?Sized> AliasingSafe<T, Exclusive, BecauseExclusive> for U {} |
| 166 | + |
| 167 | + /// SAFETY: `U: AliasingSafe<T, A, BecauseNoCell>` because for all `Ptr<'a, T, |
| 168 | + /// I>` and `Ptr<'a, U, I>` such that `I::Aliasing = A`, all live references and |
| 169 | + /// live `Ptr`s agree, by invariant on `Immutable`, that the referenced bytes |
| 170 | + /// contain no `UnsafeCell`s, and thus do not permit mutation except via |
| 171 | + /// exclusive aliasing. |
| 172 | + unsafe impl<A, T: ?Sized, U: ?Sized> AliasingSafe<T, A, BecauseImmutable> for U |
| 173 | + where |
| 174 | + A: Aliasing, |
| 175 | + T: Immutable, |
| 176 | + U: Immutable, |
| 177 | + { |
| 178 | + } |
| 179 | + |
| 180 | + /// This ensures that `U: AliasingSafe<T, A>` implies `T: AliasingSafe<U, A>` in |
| 181 | + /// a manner legible to rustc, which in turn means we can write simpler bounds in |
| 182 | + /// some places. |
| 183 | + /// |
| 184 | + /// SAFETY: Per `U: AliasingSafe<T, A, R>`, either: |
| 185 | + /// - `A` is `Exclusive` |
| 186 | + /// - `T` and `U` both implement `Immutable` |
| 187 | + /// |
| 188 | + /// Neither property depends on which of `T` and `U` are in the `Self` position |
| 189 | + /// vs the first type parameter position. |
| 190 | + unsafe impl<A, T: ?Sized, U: ?Sized, R> AliasingSafe<U, A, (R,)> for T |
| 191 | + where |
| 192 | + A: Aliasing, |
| 193 | + R: AliasingSafeReason, |
| 194 | + U: AliasingSafe<T, A, R>, |
| 195 | + { |
| 196 | + } |
| 197 | +} |
| 198 | + |
| 199 | +use sealed::Sealed; |
| 200 | +mod sealed { |
| 201 | + use super::*; |
| 202 | + |
| 203 | + pub trait Sealed {} |
| 204 | + |
| 205 | + impl Sealed for Any {} |
| 206 | + |
| 207 | + impl Sealed for Shared {} |
| 208 | + impl Sealed for Exclusive {} |
| 209 | + |
| 210 | + impl Sealed for Aligned {} |
| 211 | + |
| 212 | + impl Sealed for AsInitialized {} |
| 213 | + impl Sealed for Initialized {} |
| 214 | + impl Sealed for Valid {} |
| 215 | + |
| 216 | + impl<A: Sealed, AA: Sealed, V: Sealed> Sealed for (A, AA, V) {} |
| 217 | + |
| 218 | + impl Sealed for super::aliasing_safety::BecauseExclusive {} |
| 219 | + impl Sealed for super::aliasing_safety::BecauseImmutable {} |
| 220 | + impl<S: Sealed> Sealed for (S,) {} |
| 221 | +} |
0 commit comments