|
| 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 | +use core::{ |
| 10 | + cell::UnsafeCell, |
| 11 | + mem::{ManuallyDrop, MaybeUninit}, |
| 12 | + num::Wrapping, |
| 13 | +}; |
| 14 | + |
| 15 | +use crate::{ |
| 16 | + pointer::invariant::{self, Invariants}, |
| 17 | + Unalign, |
| 18 | +}; |
| 19 | + |
| 20 | +/// A type which has the same layout as the type it wraps. |
| 21 | +/// |
| 22 | +/// # Safety |
| 23 | +/// |
| 24 | +/// `T: TransparentWrapper` implies that `T` has the same size as [`T::Inner`]. |
| 25 | +/// Further, `T: TransparentWrapper<I>` implies that: |
| 26 | +/// - If `T::UnsafeCellVariance = Covariant`, then `T` has `UnsafeCell`s |
| 27 | +/// covering the same byte ranges as `T::Inner`. |
| 28 | +/// - If a `T` pointer satisfies the alignment invariant `I::Alignment`, then |
| 29 | +/// that same pointer, cast to `T::Inner`, satisfies the alignment invariant |
| 30 | +/// `<T::AlignmentVariance as AlignmentVariance<I::Alignment>>::Applied`. |
| 31 | +/// - If a `T` pointer satisfies the validity invariant `I::Validity`, then that |
| 32 | +/// same pointer, cast to `T::Inner`, satisfies the validity invariant |
| 33 | +/// `<T::ValidityVariance as ValidityVariance<I::Validity>>::Applied`. |
| 34 | +/// |
| 35 | +/// [`T::Inner`]: TransparentWrapper::Inner |
| 36 | +/// [`UnsafeCell`]: core::cell::UnsafeCell |
| 37 | +/// [`T::AlignmentVariance`]: TransparentWrapper::AlignmentVariance |
| 38 | +/// [`T::ValidityVariance`]: TransparentWrapper::ValidityVariance |
| 39 | +#[doc(hidden)] |
| 40 | +pub unsafe trait TransparentWrapper<I: Invariants> { |
| 41 | + type Inner: ?Sized; |
| 42 | + |
| 43 | + type UnsafeCellVariance; |
| 44 | + type AlignmentVariance: AlignmentVariance<I::Alignment>; |
| 45 | + type ValidityVariance: ValidityVariance<I::Validity>; |
| 46 | + |
| 47 | + /// Casts a wrapper pointer to an inner pointer. |
| 48 | + /// |
| 49 | + /// # Safety |
| 50 | + /// |
| 51 | + /// The resulting pointer has the same address and provenance as `ptr`, and |
| 52 | + /// addresses the same number of bytes. |
| 53 | + fn cast_into_inner(ptr: *mut Self) -> *mut Self::Inner; |
| 54 | + |
| 55 | + /// Casts an inner pointer to a wrapper pointer. |
| 56 | + /// |
| 57 | + /// # Safety |
| 58 | + /// |
| 59 | + /// The resulting pointer has the same address and provenance as `ptr`, and |
| 60 | + /// addresses the same number of bytes. |
| 61 | + fn cast_from_inner(ptr: *mut Self::Inner) -> *mut Self; |
| 62 | +} |
| 63 | + |
| 64 | +#[allow(unreachable_pub)] |
| 65 | +#[doc(hidden)] |
| 66 | +pub trait AlignmentVariance<I: invariant::Alignment> { |
| 67 | + type Applied: invariant::Alignment; |
| 68 | +} |
| 69 | + |
| 70 | +#[allow(unreachable_pub)] |
| 71 | +#[doc(hidden)] |
| 72 | +pub trait ValidityVariance<I: invariant::Validity> { |
| 73 | + type Applied: invariant::Validity; |
| 74 | +} |
| 75 | + |
| 76 | +#[doc(hidden)] |
| 77 | +#[allow(missing_copy_implementations, missing_debug_implementations)] |
| 78 | +pub enum Covariant {} |
| 79 | + |
| 80 | +impl<I: invariant::Alignment> AlignmentVariance<I> for Covariant { |
| 81 | + type Applied = I; |
| 82 | +} |
| 83 | + |
| 84 | +impl<I: invariant::Validity> ValidityVariance<I> for Covariant { |
| 85 | + type Applied = I; |
| 86 | +} |
| 87 | + |
| 88 | +#[doc(hidden)] |
| 89 | +#[allow(missing_copy_implementations, missing_debug_implementations)] |
| 90 | +pub enum Invariant {} |
| 91 | + |
| 92 | +impl<I: invariant::Alignment> AlignmentVariance<I> for Invariant { |
| 93 | + type Applied = invariant::Unknown; |
| 94 | +} |
| 95 | + |
| 96 | +impl<I: invariant::Validity> ValidityVariance<I> for Invariant { |
| 97 | + type Applied = invariant::Unknown; |
| 98 | +} |
| 99 | + |
| 100 | +// SAFETY: |
| 101 | +// - Per [1], `MaybeUninit<T>` has the same size as `T`. |
| 102 | +// - See inline comments for other safety justifications. |
| 103 | +// |
| 104 | +// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: |
| 105 | +// |
| 106 | +// `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as |
| 107 | +// `T` |
| 108 | +unsafe impl<T, I: Invariants> TransparentWrapper<I> for MaybeUninit<T> { |
| 109 | + type Inner = T; |
| 110 | + |
| 111 | + // SAFETY: `MaybeUninit<T>` has `UnsafeCell`s covering the same byte ranges |
| 112 | + // as `Inner = T`. This is not explicitly documented, but it can be |
| 113 | + // inferred. Per [1] in the preceding safety comment, `MaybeUninit<T>` has |
| 114 | + // the same size as `T`. Further, note the signature of |
| 115 | + // `MaybeUninit::assume_init_ref` [2]: |
| 116 | + // |
| 117 | + // pub unsafe fn assume_init_ref(&self) -> &T |
| 118 | + // |
| 119 | + // If the argument `&MaybeUninit<T>` and the returned `&T` had `UnsafeCell`s |
| 120 | + // at different offsets, this would be unsound. Its existence is proof that |
| 121 | + // this is not the case. |
| 122 | + // |
| 123 | + // [2] https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#method.assume_init_ref |
| 124 | + type UnsafeCellVariance = Covariant; |
| 125 | + // SAFETY: Per [1], `MaybeUninit<T>` has the same layout as `T`, and thus |
| 126 | + // has the same alignment as `T`. |
| 127 | + // |
| 128 | + // [1] Per https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#layout-1: |
| 129 | + // |
| 130 | + // `MaybeUninit<T>` is guaranteed to have the same size, alignment, and |
| 131 | + // ABI as `T`. |
| 132 | + type AlignmentVariance = Covariant; |
| 133 | + // SAFETY: `MaybeUninit` has no validity invariants. Thus, a valid |
| 134 | + // `MaybeUninit<T>` is not necessarily a valid `T`. |
| 135 | + type ValidityVariance = Invariant; |
| 136 | + |
| 137 | + #[inline(always)] |
| 138 | + fn cast_into_inner(ptr: *mut MaybeUninit<T>) -> *mut T { |
| 139 | + // SAFETY: Per [1] (from comment above), `MaybeUninit<T>` has the same |
| 140 | + // layout as `T`. Thus, this cast preserves size. |
| 141 | + // |
| 142 | + // This cast trivially preserves provenance. |
| 143 | + ptr.cast::<T>() |
| 144 | + } |
| 145 | + |
| 146 | + #[inline(always)] |
| 147 | + fn cast_from_inner(ptr: *mut T) -> *mut MaybeUninit<T> { |
| 148 | + // SAFETY: Per [1] (from comment above), `MaybeUninit<T>` has the same |
| 149 | + // layout as `T`. Thus, this cast preserves size. |
| 150 | + // |
| 151 | + // This cast trivially preserves provenance. |
| 152 | + ptr.cast::<MaybeUninit<T>>() |
| 153 | + } |
| 154 | +} |
| 155 | + |
| 156 | +// SAFETY: |
| 157 | +// - Per [1], `ManuallyDrop<T>` has the same size as `T`. |
| 158 | +// - See inline comments for other safety justifications. |
| 159 | +// |
| 160 | +// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: |
| 161 | +// |
| 162 | +// `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as |
| 163 | +// `T` |
| 164 | +unsafe impl<T: ?Sized, I: Invariants> TransparentWrapper<I> for ManuallyDrop<T> { |
| 165 | + type Inner = T; |
| 166 | + |
| 167 | + // SAFETY: Per [1], `ManuallyDrop<T>` has `UnsafeCell`s covering the same |
| 168 | + // byte ranges as `Inner = T`. |
| 169 | + // |
| 170 | + // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: |
| 171 | + // |
| 172 | + // `ManuallyDrop<T>` is guaranteed to have the same layout and bit |
| 173 | + // validity as `T`, and is subject to the same layout optimizations as |
| 174 | + // `T`. As a consequence, it has no effect on the assumptions that the |
| 175 | + // compiler makes about its contents. |
| 176 | + type UnsafeCellVariance = Covariant; |
| 177 | + // SAFETY: Per [1], `ManuallyDrop<T>` has the same layout as `T`, and thus |
| 178 | + // has the same alignment as `T`. |
| 179 | + // |
| 180 | + // [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: |
| 181 | + // |
| 182 | + // `ManuallyDrop<T>` is guaranteed to have the same layout and bit |
| 183 | + // validity as `T` |
| 184 | + type AlignmentVariance = Covariant; |
| 185 | + |
| 186 | + // SAFETY: Per [1] (from comment above), `ManuallyDrop<T>` has the same bit |
| 187 | + // validity as `T`. |
| 188 | + type ValidityVariance = Covariant; |
| 189 | + |
| 190 | + #[inline(always)] |
| 191 | + fn cast_into_inner(ptr: *mut ManuallyDrop<T>) -> *mut T { |
| 192 | + // SAFETY: Per [1] (from comment above), `ManuallyDrop<T>` has the same |
| 193 | + // layout as `T`. Thus, this cast preserves size even if `T` is unsized. |
| 194 | + // |
| 195 | + // This cast trivially preserves provenance. |
| 196 | + #[allow(clippy::as_conversions)] |
| 197 | + return ptr as *mut T; |
| 198 | + } |
| 199 | + |
| 200 | + #[inline(always)] |
| 201 | + fn cast_from_inner(ptr: *mut T) -> *mut ManuallyDrop<T> { |
| 202 | + // SAFETY: Per [1] (from comment above), `ManuallyDrop<T>` has the same |
| 203 | + // layout as `T`. Thus, this cast preserves size even if `T` is unsized. |
| 204 | + // |
| 205 | + // This cast trivially preserves provenance. |
| 206 | + #[allow(clippy::as_conversions)] |
| 207 | + return ptr as *mut ManuallyDrop<T>; |
| 208 | + } |
| 209 | +} |
| 210 | + |
| 211 | +// SAFETY: |
| 212 | +// - Per [1], `Wrapping<T>` has the same size as `T`. |
| 213 | +// - See inline comments for other safety justifications. |
| 214 | +// |
| 215 | +// [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: |
| 216 | +// |
| 217 | +// `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`. |
| 218 | +unsafe impl<T, I: Invariants> TransparentWrapper<I> for Wrapping<T> { |
| 219 | + type Inner = T; |
| 220 | + |
| 221 | + // SAFETY: Per [1], `Wrapping<T>` has the same layout as `T`. Since its |
| 222 | + // single field (of type `T`) is public, it would be a breaking change to |
| 223 | + // add or remove fields. Thus, we know that `Wrapping<T>` contains a `T` (as |
| 224 | + // opposed to just having the same size and alignment as `T`) with no pre- |
| 225 | + // or post-padding. Thus, `Wrapping<T>` must have `UnsafeCell`s covering the |
| 226 | + // same byte ranges as `Inner = T`. |
| 227 | + // |
| 228 | + // [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: |
| 229 | + // |
| 230 | + // `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`. |
| 231 | + type UnsafeCellVariance = Covariant; |
| 232 | + // SAFETY: Per [1], `Wrapping<T>` has the same layout as `T`, and thus has |
| 233 | + // the same alignment as `T`. |
| 234 | + // |
| 235 | + // [1] Per https://doc.rust-lang.org/core/num/struct.Wrapping.html#layout-1: |
| 236 | + // |
| 237 | + // `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`. |
| 238 | + type AlignmentVariance = Covariant; |
| 239 | + |
| 240 | + // SAFETY: `Wrapping<T>` has only one field, which is `pub` [2]. We are also |
| 241 | + // guaranteed per [1] (from the comment above) that `Wrapping<T>` has the |
| 242 | + // same layout as `T`. The only way for both of these to be true |
| 243 | + // simultaneously is for `Wrapping<T>` to have the same bit validity as `T`. |
| 244 | + // In particular, in order to change the bit validity, one of the following |
| 245 | + // would need to happen: |
| 246 | + // - `Wrapping` could change its `repr`, but this would violate the layout |
| 247 | + // guarantee. |
| 248 | + // - `Wrapping` could add or change its fields, but this would be a |
| 249 | + // stability-breaking change. |
| 250 | + // |
| 251 | + // [2] https://doc.rust-lang.org/core/num/struct.Wrapping.html |
| 252 | + type ValidityVariance = Covariant; |
| 253 | + |
| 254 | + #[inline(always)] |
| 255 | + fn cast_into_inner(ptr: *mut Wrapping<T>) -> *mut T { |
| 256 | + // SAFETY: Per [1] (from comment above), `Wrapping<T>` has the same |
| 257 | + // layout as `T`. Thus, this cast preserves size. |
| 258 | + // |
| 259 | + // This cast trivially preserves provenance. |
| 260 | + ptr.cast::<T>() |
| 261 | + } |
| 262 | + |
| 263 | + #[inline(always)] |
| 264 | + fn cast_from_inner(ptr: *mut T) -> *mut Wrapping<T> { |
| 265 | + // SAFETY: Per [1] (from comment above), `Wrapping<T>` has the same |
| 266 | + // layout as `T`. Thus, this cast preserves size. |
| 267 | + // |
| 268 | + // This cast trivially preserves provenance. |
| 269 | + ptr.cast::<Wrapping<T>>() |
| 270 | + } |
| 271 | +} |
| 272 | + |
| 273 | +// SAFETY: |
| 274 | +// - Per [1], `UnsafeCell<T>` has the same size as `T`. |
| 275 | +// - See inline comments for other safety justifications. |
| 276 | +// |
| 277 | +// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: |
| 278 | +// |
| 279 | +// `UnsafeCell<T>` has the same in-memory representation as its inner type |
| 280 | +// `T`. |
| 281 | +unsafe impl<T: ?Sized, I: Invariants> TransparentWrapper<I> for UnsafeCell<T> { |
| 282 | + type Inner = T; |
| 283 | + |
| 284 | + // SAFETY: Since we set this to `Invariant`, we make no safety claims. |
| 285 | + type UnsafeCellVariance = Invariant; |
| 286 | + |
| 287 | + // SAFETY: Per [1] (from comment on impl), `Unalign<T>` has the same |
| 288 | + // representation as `T`, and thus has the same alignment as `T`. |
| 289 | + type AlignmentVariance = Covariant; |
| 290 | + |
| 291 | + // SAFETY: Per [1], `Unalign<T>` has the same bit validity as `T`. |
| 292 | + // Technically the term "representation" doesn't guarantee this, but the |
| 293 | + // subsequent sentence in the documentation makes it clear that this is the |
| 294 | + // intention. |
| 295 | + // |
| 296 | + // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: |
| 297 | + // |
| 298 | + // `UnsafeCell<T>` has the same in-memory representation as its inner type |
| 299 | + // `T`. A consequence of this guarantee is that it is possible to convert |
| 300 | + // between `T` and `UnsafeCell<T>`. |
| 301 | + type ValidityVariance = Covariant; |
| 302 | + |
| 303 | + #[inline(always)] |
| 304 | + fn cast_into_inner(ptr: *mut UnsafeCell<T>) -> *mut T { |
| 305 | + // SAFETY: Per [1] (from comment above), `UnsafeCell<T>` has the same |
| 306 | + // representation as `T`. Thus, this cast preserves size. |
| 307 | + // |
| 308 | + // This cast trivially preserves provenance. |
| 309 | + #[allow(clippy::as_conversions)] |
| 310 | + return ptr as *mut T; |
| 311 | + } |
| 312 | + |
| 313 | + #[inline(always)] |
| 314 | + fn cast_from_inner(ptr: *mut T) -> *mut UnsafeCell<T> { |
| 315 | + // SAFETY: Per [1] (from comment above), `UnsafeCell<T>` has the same |
| 316 | + // representation as `T`. Thus, this cast preserves size. |
| 317 | + // |
| 318 | + // This cast trivially preserves provenance. |
| 319 | + #[allow(clippy::as_conversions)] |
| 320 | + return ptr as *mut UnsafeCell<T>; |
| 321 | + } |
| 322 | +} |
| 323 | + |
| 324 | +// SAFETY: `Unalign<T>` promises to have the same size as `T`. |
| 325 | +// |
| 326 | +// See inline comments for other safety justifications. |
| 327 | +unsafe impl<T, I: Invariants> TransparentWrapper<I> for Unalign<T> { |
| 328 | + type Inner = T; |
| 329 | + |
| 330 | + // SAFETY: `Unalign<T>` promises to have `UnsafeCell`s covering the same |
| 331 | + // byte ranges as `Inner = T`. |
| 332 | + type UnsafeCellVariance = Covariant; |
| 333 | + |
| 334 | + // SAFETY: Since `Unalign<T>` promises to have alignment 1 regardless of |
| 335 | + // `T`'s alignment. Thus, an aligned pointer to `Unalign<T>` is not |
| 336 | + // necessarily an aligned pointer to `T`. |
| 337 | + type AlignmentVariance = Invariant; |
| 338 | + |
| 339 | + // SAFETY: `Unalign<T>` promises to have the same validity as `T`. |
| 340 | + type ValidityVariance = Covariant; |
| 341 | + |
| 342 | + #[inline(always)] |
| 343 | + fn cast_into_inner(ptr: *mut Unalign<T>) -> *mut T { |
| 344 | + // SAFETY: Per the safety comment on the impl block, `Unalign<T>` has |
| 345 | + // the size as `T`. Thus, this cast preserves size. |
| 346 | + // |
| 347 | + // This cast trivially preserves provenance. |
| 348 | + ptr.cast::<T>() |
| 349 | + } |
| 350 | + |
| 351 | + #[inline(always)] |
| 352 | + fn cast_from_inner(ptr: *mut T) -> *mut Unalign<T> { |
| 353 | + // SAFETY: Per the safety comment on the impl block, `Unalign<T>` has |
| 354 | + // the size as `T`. Thus, this cast preserves size. |
| 355 | + // |
| 356 | + // This cast trivially preserves provenance. |
| 357 | + ptr.cast::<Unalign<T>>() |
| 358 | + } |
| 359 | +} |
0 commit comments