| 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 | //! Machinery for statically proving the "aliasing-safety" of a `Ptr`. |
| 10 | |
| 11 | use crate::{invariant, Immutable}; |
| 12 | |
| 13 | /// Pointer conversions which do not violate aliasing. |
| 14 | /// |
| 15 | /// `U: AliasingSafe<T, A, R>` implies that a pointer conversion from `T` to `U` |
| 16 | /// does not violate the aliasing invariant, `A`. This can be because `A` is |
| 17 | /// [`Exclusive`] or because neither `T` nor `U` permit interior mutability. |
| 18 | /// |
| 19 | /// # Safety |
| 20 | /// |
| 21 | /// `U: AliasingSafe<T, A, R>` if either of the following conditions holds: |
| 22 | /// - `A` is [`Exclusive`] |
| 23 | /// - `T` and `U` both implement [`Immutable`] |
| 24 | /// |
| 25 | /// [`Exclusive`]: crate::pointer::invariant::Exclusive |
| 26 | #[doc (hidden)] |
| 27 | pub unsafe trait AliasingSafe<T: ?Sized, A: invariant::Aliasing, R: AliasingSafeReason> {} |
| 28 | |
| 29 | /// Used to prevent user implementations of `AliasingSafeReason`. |
| 30 | mod sealed { |
| 31 | pub trait Sealed {} |
| 32 | |
| 33 | impl Sealed for super::BecauseExclusive {} |
| 34 | impl Sealed for super::BecauseImmutable {} |
| 35 | impl<S: Sealed> Sealed for (S,) {} |
| 36 | } |
| 37 | |
| 38 | #[doc (hidden)] |
| 39 | pub trait AliasingSafeReason: sealed::Sealed {} |
| 40 | impl<R: AliasingSafeReason> AliasingSafeReason for (R,) {} |
| 41 | |
| 42 | /// The conversion is safe because only one live `Ptr` or reference may exist to |
| 43 | /// the referent bytes at a time. |
| 44 | #[derive (Copy, Clone, Debug)] |
| 45 | #[doc (hidden)] |
| 46 | pub enum BecauseExclusive {} |
| 47 | impl AliasingSafeReason for BecauseExclusive {} |
| 48 | |
| 49 | /// The conversion is safe because no live `Ptr`s or references permit mutation. |
| 50 | #[derive (Copy, Clone, Debug)] |
| 51 | #[doc (hidden)] |
| 52 | pub enum BecauseImmutable {} |
| 53 | impl AliasingSafeReason for BecauseImmutable {} |
| 54 | |
| 55 | /// SAFETY: `T: AliasingSafe<Exclusive, BecauseExclusive>` because for all |
| 56 | /// `Ptr<'a, T, I>` such that `I::Aliasing = Exclusive`, there cannot exist |
| 57 | /// other live references to the memory referenced by `Ptr`. |
| 58 | unsafe impl<T: ?Sized, U: ?Sized> AliasingSafe<T, invariant::Exclusive, BecauseExclusive> for U {} |
| 59 | |
| 60 | /// SAFETY: `U: AliasingSafe<T, A, BecauseNoCell>` because for all `Ptr<'a, T, |
| 61 | /// I>` and `Ptr<'a, U, I>` such that `I::Aliasing = A`, all live references and |
| 62 | /// live `Ptr`s agree, by invariant on `Immutable`, that the referenced bytes |
| 63 | /// contain no `UnsafeCell`s, and thus do not permit mutation except via |
| 64 | /// exclusive aliasing. |
| 65 | unsafe impl<A, T: ?Sized, U: ?Sized> AliasingSafe<T, A, BecauseImmutable> for U |
| 66 | where |
| 67 | A: invariant::Aliasing, |
| 68 | T: Immutable, |
| 69 | U: Immutable, |
| 70 | { |
| 71 | } |
| 72 | |
| 73 | /// This ensures that `U: AliasingSafe<T, A>` implies `T: AliasingSafe<U, A>` in |
| 74 | /// a manner legible to rustc, which in turn means we can write simpler bounds in |
| 75 | /// some places. |
| 76 | /// |
| 77 | /// SAFETY: Per `U: AliasingSafe<T, A, R>`, either: |
| 78 | /// - `A` is `Exclusive` |
| 79 | /// - `T` and `U` both implement `Immutable` |
| 80 | /// |
| 81 | /// Neither property depends on which of `T` and `U` are in the `Self` position |
| 82 | /// vs the first type parameter position. |
| 83 | unsafe impl<A, T: ?Sized, U: ?Sized, R> AliasingSafe<U, A, (R,)> for T |
| 84 | where |
| 85 | A: invariant::Aliasing, |
| 86 | R: AliasingSafeReason, |
| 87 | U: AliasingSafe<T, A, R>, |
| 88 | { |
| 89 | } |
| 90 | |