| 1 | // Copyright 2023 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 | #[ path= "third_party/rust/layout.rs"] | 
|---|
| 10 | pub(crate) mod core_layout; | 
|---|
| 11 |  | 
|---|
| 12 | use core::{mem, num::NonZeroUsize}; | 
|---|
| 13 |  | 
|---|
| 14 | pub(crate) mod ptr { | 
|---|
| 15 | use core::{ | 
|---|
| 16 | fmt::{Debug, Formatter}, | 
|---|
| 17 | marker::PhantomData, | 
|---|
| 18 | ptr::NonNull, | 
|---|
| 19 | }; | 
|---|
| 20 |  | 
|---|
| 21 | use crate::{util::AsAddress, KnownLayout, _CastType}; | 
|---|
| 22 |  | 
|---|
| 23 | /// A raw pointer with more restrictions. | 
|---|
| 24 | /// | 
|---|
| 25 | /// `Ptr<T>` is similar to `NonNull<T>`, but it is more restrictive in the | 
|---|
| 26 | /// following ways: | 
|---|
| 27 | /// - It must derive from a valid allocation | 
|---|
| 28 | /// - It must reference a byte range which is contained inside the | 
|---|
| 29 | ///   allocation from which it derives | 
|---|
| 30 | ///   - As a consequence, the byte range it references must have a size | 
|---|
| 31 | ///     which does not overflow `isize` | 
|---|
| 32 | /// - It must satisfy `T`'s alignment requirement | 
|---|
| 33 | /// | 
|---|
| 34 | /// Thanks to these restrictions, it is easier to prove the soundness of | 
|---|
| 35 | /// some operations using `Ptr`s. | 
|---|
| 36 | /// | 
|---|
| 37 | /// `Ptr<'a, T>` is [covariant] in `'a` and `T`. | 
|---|
| 38 | /// | 
|---|
| 39 | /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html | 
|---|
| 40 | pub struct Ptr<'a, T: 'a + ?Sized> { | 
|---|
| 41 | // INVARIANTS: | 
|---|
| 42 | // 1. `ptr` is derived from some valid Rust allocation, `A` | 
|---|
| 43 | // 2. `ptr` has the same provenance as `A` | 
|---|
| 44 | // 3. `ptr` addresses a byte range which is entirely contained in `A` | 
|---|
| 45 | // 4. `ptr` addresses a byte range whose length fits in an `isize` | 
|---|
| 46 | // 5. `ptr` addresses a byte range which does not wrap around the address | 
|---|
| 47 | //     space | 
|---|
| 48 | // 6. `ptr` is validly-aligned for `T` | 
|---|
| 49 | // 7. `A` is guaranteed to live for at least `'a` | 
|---|
| 50 | // 8. `T: 'a` | 
|---|
| 51 | ptr: NonNull<T>, | 
|---|
| 52 | _lifetime: PhantomData<&'a ()>, | 
|---|
| 53 | } | 
|---|
| 54 |  | 
|---|
| 55 | impl<'a, T: ?Sized> Copy for Ptr<'a, T> {} | 
|---|
| 56 | impl<'a, T: ?Sized> Clone for Ptr<'a, T> { | 
|---|
| 57 | #[ inline] | 
|---|
| 58 | fn clone(&self) -> Self { | 
|---|
| 59 | *self | 
|---|
| 60 | } | 
|---|
| 61 | } | 
|---|
| 62 |  | 
|---|
| 63 | impl<'a, T: ?Sized> Ptr<'a, T> { | 
|---|
| 64 | /// Returns a shared reference to the value. | 
|---|
| 65 | /// | 
|---|
| 66 | /// # Safety | 
|---|
| 67 | /// | 
|---|
| 68 | /// For the duration of `'a`: | 
|---|
| 69 | /// - The referenced memory must contain a validly-initialized `T` for | 
|---|
| 70 | ///   the duration of `'a`. | 
|---|
| 71 | /// - The referenced memory must not also be referenced by any mutable | 
|---|
| 72 | ///   references. | 
|---|
| 73 | /// - The referenced memory must not be mutated, even via an | 
|---|
| 74 | ///   [`UnsafeCell`]. | 
|---|
| 75 | /// - There must not exist any references to the same memory region | 
|---|
| 76 | ///   which contain `UnsafeCell`s at byte ranges which are not identical | 
|---|
| 77 | ///   to the byte ranges at which `T` contains `UnsafeCell`s. | 
|---|
| 78 | /// | 
|---|
| 79 | /// [`UnsafeCell`]: core::cell::UnsafeCell | 
|---|
| 80 | // TODO(#429): The safety requirements are likely overly-restrictive. | 
|---|
| 81 | // Notably, mutation via `UnsafeCell`s is probably fine. Once the rules | 
|---|
| 82 | // are more clearly defined, we should relax the safety requirements. | 
|---|
| 83 | // For an example of why this is subtle, see: | 
|---|
| 84 | // https://github.com/rust-lang/unsafe-code-guidelines/issues/463#issuecomment-1736771593 | 
|---|
| 85 | #[ allow(unused)] | 
|---|
| 86 | pub(crate) unsafe fn as_ref(&self) -> &'a T { | 
|---|
| 87 | // SAFETY: | 
|---|
| 88 | // - By invariant, `self.ptr` is properly-aligned for `T`. | 
|---|
| 89 | // - By invariant, `self.ptr` is "dereferenceable" in that it points | 
|---|
| 90 | //   to a single allocation. | 
|---|
| 91 | // - By invariant, the allocation is live for `'a`. | 
|---|
| 92 | // - The caller promises that no mutable references exist to this | 
|---|
| 93 | //   region during `'a`. | 
|---|
| 94 | // - The caller promises that `UnsafeCell`s match exactly. | 
|---|
| 95 | // - The caller promises that no mutation will happen during `'a`, | 
|---|
| 96 | //   even via `UnsafeCell`s. | 
|---|
| 97 | // - The caller promises that the memory region contains a | 
|---|
| 98 | //   validly-intialized `T`. | 
|---|
| 99 | unsafe { self.ptr.as_ref() } | 
|---|
| 100 | } | 
|---|
| 101 |  | 
|---|
| 102 | /// Casts to a different (unsized) target type. | 
|---|
| 103 | /// | 
|---|
| 104 | /// # Safety | 
|---|
| 105 | /// | 
|---|
| 106 | /// The caller promises that | 
|---|
| 107 | /// - `cast(p)` is implemented exactly as follows: `|p: *mut T| p as | 
|---|
| 108 | ///   *mut U`. | 
|---|
| 109 | /// - The size of the object referenced by the resulting pointer is less | 
|---|
| 110 | ///   than or equal to the size of the object referenced by `self`. | 
|---|
| 111 | /// - The alignment of `U` is less than or equal to the alignment of | 
|---|
| 112 | ///   `T`. | 
|---|
| 113 | pub(crate) unsafe fn cast_unsized<U: 'a + ?Sized, F: FnOnce(*mut T) -> *mut U>( | 
|---|
| 114 | self, | 
|---|
| 115 | cast: F, | 
|---|
| 116 | ) -> Ptr<'a, U> { | 
|---|
| 117 | let ptr = cast(self.ptr.as_ptr()); | 
|---|
| 118 | // SAFETY: Caller promises that `cast` is just an `as` cast. We call | 
|---|
| 119 | // `cast` on `self.ptr.as_ptr()`, which is non-null by construction. | 
|---|
| 120 | let ptr = unsafe { NonNull::new_unchecked(ptr) }; | 
|---|
| 121 | // SAFETY: | 
|---|
| 122 | // - By invariant, `self.ptr` is derived from some valid Rust | 
|---|
| 123 | //   allocation, and since `ptr` is just `self.ptr as *mut U`, so is | 
|---|
| 124 | //   `ptr`. | 
|---|
| 125 | // - By invariant, `self.ptr` has the same provenance as `A`, and so | 
|---|
| 126 | //   the same is true of `ptr`. | 
|---|
| 127 | // - By invariant, `self.ptr` addresses a byte range which is | 
|---|
| 128 | //   entirely contained in `A`, and so the same is true of `ptr`. | 
|---|
| 129 | // - By invariant, `self.ptr` addresses a byte range whose length | 
|---|
| 130 | //   fits in an `isize`, and so the same is true of `ptr`. | 
|---|
| 131 | // - By invariant, `self.ptr` addresses a byte range which does not | 
|---|
| 132 | //   wrap around the address space, and so the same is true of | 
|---|
| 133 | //   `ptr`. | 
|---|
| 134 | // - By invariant, `self.ptr` is validly-aligned for `T`. Since | 
|---|
| 135 | //   `ptr` has the same address, and since the caller promises that | 
|---|
| 136 | //   the alignment of `U` is less than or equal to the alignment of | 
|---|
| 137 | //   `T`, `ptr` is validly-aligned for `U`. | 
|---|
| 138 | // - By invariant, `A` is guaranteed to live for at least `'a`. | 
|---|
| 139 | // - `U: 'a` | 
|---|
| 140 | Ptr { ptr, _lifetime: PhantomData } | 
|---|
| 141 | } | 
|---|
| 142 | } | 
|---|
| 143 |  | 
|---|
| 144 | impl<'a> Ptr<'a, [u8]> { | 
|---|
| 145 | /// Attempts to cast `self` to a `U` using the given cast type. | 
|---|
| 146 | /// | 
|---|
| 147 | /// Returns `None` if the resulting `U` would be invalidly-aligned or if | 
|---|
| 148 | /// no `U` can fit in `self`. On success, returns a pointer to the | 
|---|
| 149 | /// largest-possible `U` which fits in `self`. | 
|---|
| 150 | /// | 
|---|
| 151 | /// # Safety | 
|---|
| 152 | /// | 
|---|
| 153 | /// The caller may assume that this implementation is correct, and may | 
|---|
| 154 | /// rely on that assumption for the soundness of their code. In | 
|---|
| 155 | /// particular, the caller may assume that, if `try_cast_into` returns | 
|---|
| 156 | /// `Some((ptr, split_at))`, then: | 
|---|
| 157 | /// - If this is a prefix cast, `ptr` refers to the byte range `[0, | 
|---|
| 158 | ///   split_at)` in `self`. | 
|---|
| 159 | /// - If this is a suffix cast, `ptr` refers to the byte range | 
|---|
| 160 | ///   `[split_at, self.len())` in `self`. | 
|---|
| 161 | /// | 
|---|
| 162 | /// # Panics | 
|---|
| 163 | /// | 
|---|
| 164 | /// Panics if `U` is a DST whose trailing slice element is zero-sized. | 
|---|
| 165 | pub(crate) fn try_cast_into<U: 'a + ?Sized + KnownLayout>( | 
|---|
| 166 | &self, | 
|---|
| 167 | cast_type: _CastType, | 
|---|
| 168 | ) -> Option<(Ptr<'a, U>, usize)> { | 
|---|
| 169 | // PANICS: By invariant, the byte range addressed by `self.ptr` does | 
|---|
| 170 | // not wrap around the address space. This implies that the sum of | 
|---|
| 171 | // the address (represented as a `usize`) and length do not overflow | 
|---|
| 172 | // `usize`, as required by `validate_cast_and_convert_metadata`. | 
|---|
| 173 | // Thus, this call to `validate_cast_and_convert_metadata` won't | 
|---|
| 174 | // panic. | 
|---|
| 175 | let (elems, split_at) = U::LAYOUT.validate_cast_and_convert_metadata( | 
|---|
| 176 | AsAddress::addr(self.ptr.as_ptr()), | 
|---|
| 177 | self.len(), | 
|---|
| 178 | cast_type, | 
|---|
| 179 | )?; | 
|---|
| 180 | let offset = match cast_type { | 
|---|
| 181 | _CastType::_Prefix => 0, | 
|---|
| 182 | _CastType::_Suffix => split_at, | 
|---|
| 183 | }; | 
|---|
| 184 |  | 
|---|
| 185 | let ptr = self.ptr.cast::<u8>().as_ptr(); | 
|---|
| 186 | // SAFETY: `offset` is either `0` or `split_at`. | 
|---|
| 187 | // `validate_cast_and_convert_metadata` promises that `split_at` is | 
|---|
| 188 | // in the range `[0, self.len()]`. Thus, in both cases, `offset` is | 
|---|
| 189 | // in `[0, self.len()]`. Thus: | 
|---|
| 190 | // - The resulting pointer is in or one byte past the end of the | 
|---|
| 191 | //   same byte range as `self.ptr`. Since, by invariant, `self.ptr` | 
|---|
| 192 | //   addresses a byte range entirely contained within a single | 
|---|
| 193 | //   allocation, the pointer resulting from this operation is within | 
|---|
| 194 | //   or one byte past the end of that same allocation. | 
|---|
| 195 | // - By invariant, `self.len() <= isize::MAX`. Since `offset <= | 
|---|
| 196 | //   self.len()`, `offset <= isize::MAX`. | 
|---|
| 197 | // - By invariant, `self.ptr` addresses a byte range which does not | 
|---|
| 198 | //   wrap around the address space. This means that the base pointer | 
|---|
| 199 | //   plus the `self.len()` does not overflow `usize`. Since `offset | 
|---|
| 200 | //   <= self.len()`, this addition does not overflow `usize`. | 
|---|
| 201 | let base = unsafe { ptr.add(offset) }; | 
|---|
| 202 | // SAFETY: Since `add` is not allowed to wrap around, the preceding line | 
|---|
| 203 | // produces a pointer whose address is greater than or equal to that of | 
|---|
| 204 | // `ptr`. Since `ptr` is a `NonNull`, `base` is also non-null. | 
|---|
| 205 | let base = unsafe { NonNull::new_unchecked(base) }; | 
|---|
| 206 | let ptr = U::raw_from_ptr_len(base, elems); | 
|---|
| 207 | // SAFETY: | 
|---|
| 208 | // - By invariant, `self.ptr` is derived from some valid Rust | 
|---|
| 209 | //   allocation, `A`, and has the same provenance as `A`. All | 
|---|
| 210 | //   operations performed on `self.ptr` and values derived from it | 
|---|
| 211 | //   in this method preserve provenance, so: | 
|---|
| 212 | //   - `ptr` is derived from a valid Rust allocation, `A`. | 
|---|
| 213 | //   - `ptr` has the same provenance as `A`. | 
|---|
| 214 | // - `validate_cast_and_convert_metadata` promises that the object | 
|---|
| 215 | //   described by `elems` and `split_at` lives at a byte range which | 
|---|
| 216 | //   is a subset of the input byte range. Thus: | 
|---|
| 217 | //   - Since, by invariant, `self.ptr` addresses a byte range | 
|---|
| 218 | //     entirely contained in `A`, so does `ptr`. | 
|---|
| 219 | //   - Since, by invariant, `self.ptr` addresses a range whose | 
|---|
| 220 | //     length is not longer than `isize::MAX` bytes, so does `ptr`. | 
|---|
| 221 | //   - Since, by invariant, `self.ptr` addresses a range which does | 
|---|
| 222 | //     not wrap around the address space, so does `ptr`. | 
|---|
| 223 | // - `validate_cast_and_convert_metadata` promises that the object | 
|---|
| 224 | //   described by `split_at` is validly-aligned for `U`. | 
|---|
| 225 | // - By invariant on `self`, `A` is guaranteed to live for at least | 
|---|
| 226 | //   `'a`. | 
|---|
| 227 | // - `U: 'a` by trait bound. | 
|---|
| 228 | Some((Ptr { ptr, _lifetime: PhantomData }, split_at)) | 
|---|
| 229 | } | 
|---|
| 230 |  | 
|---|
| 231 | /// Attempts to cast `self` into a `U`, failing if all of the bytes of | 
|---|
| 232 | /// `self` cannot be treated as a `U`. | 
|---|
| 233 | /// | 
|---|
| 234 | /// In particular, this method fails if `self` is not validly-aligned | 
|---|
| 235 | /// for `U` or if `self`'s size is not a valid size for `U`. | 
|---|
| 236 | /// | 
|---|
| 237 | /// # Safety | 
|---|
| 238 | /// | 
|---|
| 239 | /// On success, the caller may assume that the returned pointer | 
|---|
| 240 | /// references the same byte range as `self`. | 
|---|
| 241 | #[ allow(unused)] | 
|---|
| 242 | #[ inline(always)] | 
|---|
| 243 | pub(crate) fn try_cast_into_no_leftover<U: 'a + ?Sized + KnownLayout>( | 
|---|
| 244 | &self, | 
|---|
| 245 | ) -> Option<Ptr<'a, U>> { | 
|---|
| 246 | // TODO(#67): Remove this allow. See NonNulSlicelExt for more | 
|---|
| 247 | // details. | 
|---|
| 248 | #[ allow(unstable_name_collisions)] | 
|---|
| 249 | match self.try_cast_into(_CastType::_Prefix) { | 
|---|
| 250 | Some((slf, split_at)) if split_at == self.len() => Some(slf), | 
|---|
| 251 | Some(_) | None => None, | 
|---|
| 252 | } | 
|---|
| 253 | } | 
|---|
| 254 | } | 
|---|
| 255 |  | 
|---|
| 256 | impl<'a, T> Ptr<'a, [T]> { | 
|---|
| 257 | /// The number of slice elements referenced by `self`. | 
|---|
| 258 | /// | 
|---|
| 259 | /// # Safety | 
|---|
| 260 | /// | 
|---|
| 261 | /// Unsafe code my rely on `len` satisfying the above contract. | 
|---|
| 262 | fn len(&self) -> usize { | 
|---|
| 263 | #[ allow(clippy::as_conversions)] | 
|---|
| 264 | let slc = self.ptr.as_ptr() as *const [()]; | 
|---|
| 265 | // SAFETY: | 
|---|
| 266 | // - `()` has alignment 1, so `slc` is trivially aligned. | 
|---|
| 267 | // - `slc` was derived from a non-null pointer. | 
|---|
| 268 | // - The size is 0 regardless of the length, so it is sound to | 
|---|
| 269 | //   materialize a reference regardless of location. | 
|---|
| 270 | // - By invariant, `self.ptr` has valid provenance. | 
|---|
| 271 | let slc = unsafe { &*slc }; | 
|---|
| 272 | // This is correct because the preceding `as` cast preserves the | 
|---|
| 273 | // number of slice elements. Per | 
|---|
| 274 | // https://doc.rust-lang.org/nightly/reference/expressions/operator-expr.html#slice-dst-pointer-to-pointer-cast: | 
|---|
| 275 | // | 
|---|
| 276 | //   For slice types like `[T]` and `[U]`, the raw pointer types | 
|---|
| 277 | //   `*const [T]`, `*mut [T]`, `*const [U]`, and `*mut [U]` encode | 
|---|
| 278 | //   the number of elements in this slice. Casts between these raw | 
|---|
| 279 | //   pointer types preserve the number of elements. Note that, as a | 
|---|
| 280 | //   consequence, such casts do *not* necessarily preserve the size | 
|---|
| 281 | //   of the pointer's referent (e.g., casting `*const [u16]` to | 
|---|
| 282 | //   `*const [u8]` will result in a raw pointer which refers to an | 
|---|
| 283 | //   object of half the size of the original). The same holds for | 
|---|
| 284 | //   `str` and any compound type whose unsized tail is a slice type, | 
|---|
| 285 | //   such as struct `Foo(i32, [u8])` or `(u64, Foo)`. | 
|---|
| 286 | // | 
|---|
| 287 | // TODO(#429), | 
|---|
| 288 | // TODO(https://github.com/rust-lang/reference/pull/1417): Once this | 
|---|
| 289 | // text is available on the Stable docs, cite those instead of the | 
|---|
| 290 | // Nightly docs. | 
|---|
| 291 | slc.len() | 
|---|
| 292 | } | 
|---|
| 293 |  | 
|---|
| 294 | pub(crate) fn iter(&self) -> impl Iterator<Item = Ptr<'a, T>> { | 
|---|
| 295 | // TODO(#429): Once `NonNull::cast` documents that it preserves | 
|---|
| 296 | // provenance, cite those docs. | 
|---|
| 297 | let base = self.ptr.cast::<T>().as_ptr(); | 
|---|
| 298 | (0..self.len()).map(move |i| { | 
|---|
| 299 | // TODO(https://github.com/rust-lang/rust/issues/74265): Use | 
|---|
| 300 | // `NonNull::get_unchecked_mut`. | 
|---|
| 301 |  | 
|---|
| 302 | // SAFETY: If the following conditions are not satisfied | 
|---|
| 303 | // `pointer::cast` may induce Undefined Behavior [1]: | 
|---|
| 304 | // > 1. Both the starting and resulting pointer must be either | 
|---|
| 305 | // >    in bounds or one byte past the end of the same allocated | 
|---|
| 306 | // >    object. | 
|---|
| 307 | // > 2. The computed offset, in bytes, cannot overflow an | 
|---|
| 308 | // >    `isize`. | 
|---|
| 309 | // > 3. The offset being in bounds cannot rely on “wrapping | 
|---|
| 310 | // >    around” the address space. That is, the | 
|---|
| 311 | // >    infinite-precision sum must fit in a `usize`. | 
|---|
| 312 | // | 
|---|
| 313 | // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add | 
|---|
| 314 | // | 
|---|
| 315 | // We satisfy all three of these conditions here: | 
|---|
| 316 | // 1. `base` (by invariant on `self`) points to an allocated | 
|---|
| 317 | //    object. By contract, `self.len()` accurately reflects the | 
|---|
| 318 | //    number of elements in the slice. `i` is in bounds of | 
|---|
| 319 | //   `c.len()` by construction, and so the result of this | 
|---|
| 320 | //   addition cannot overflow past the end of the allocation | 
|---|
| 321 | //   referred to by `c`. | 
|---|
| 322 | // 2. By invariant on `Ptr`, `self` addresses a byte range whose | 
|---|
| 323 | //    length fits in an `isize`. Since `elem` is contained in | 
|---|
| 324 | //    `self`, the computed offset of `elem` must fit within | 
|---|
| 325 | //    `isize.` | 
|---|
| 326 | // 3. By invariant on `Ptr`, `self` addresses a byte range which | 
|---|
| 327 | //    does not wrap around the address space. Since `elem` is | 
|---|
| 328 | //    contained in `self`, the computed offset of `elem` must | 
|---|
| 329 | //    wrap around the address space. | 
|---|
| 330 | // | 
|---|
| 331 | // TODO(#429): Once `pointer::add` documents that it preserves | 
|---|
| 332 | // provenance, cite those docs. | 
|---|
| 333 | let elem = unsafe { base.add(i) }; | 
|---|
| 334 |  | 
|---|
| 335 | // SAFETY: | 
|---|
| 336 | //  - `elem` must not be null. `base` is constructed from a | 
|---|
| 337 | //    `NonNull` pointer, and the addition that produces `elem` | 
|---|
| 338 | //    must not overflow or wrap around, so `elem >= base > 0`. | 
|---|
| 339 | // | 
|---|
| 340 | // TODO(#429): Once `NonNull::new_unchecked` documents that it | 
|---|
| 341 | // preserves provenance, cite those docs. | 
|---|
| 342 | let elem = unsafe { NonNull::new_unchecked(elem) }; | 
|---|
| 343 |  | 
|---|
| 344 | // SAFETY: The safety invariants of `Ptr` (see definition) are | 
|---|
| 345 | // satisfied: | 
|---|
| 346 | // 1. `elem` is derived from a valid Rust allocation, because | 
|---|
| 347 | //    `self` is derived from a valid Rust allocation, by | 
|---|
| 348 | //    invariant on `Ptr` | 
|---|
| 349 | // 2. `elem` has the same provenance as `self`, because it | 
|---|
| 350 | //    derived from `self` using a series of | 
|---|
| 351 | //    provenance-preserving operations | 
|---|
| 352 | // 3. `elem` is entirely contained in the allocation of `self` | 
|---|
| 353 | //    (see above) | 
|---|
| 354 | // 4. `elem` addresses a byte range whose length fits in an | 
|---|
| 355 | //    `isize` (see above) | 
|---|
| 356 | // 5. `elem` addresses a byte range which does not wrap around | 
|---|
| 357 | //    the address space (see above) | 
|---|
| 358 | // 6. `elem` is validly-aligned for `T`. `self`, which | 
|---|
| 359 | //    represents a `[T]` is validly aligned for `T`, and `elem` | 
|---|
| 360 | //    is an element within that `[T]` | 
|---|
| 361 | // 7. The allocation of `elem` is guaranteed to live for at | 
|---|
| 362 | //    least `'a`, because `elem` is entirely contained in | 
|---|
| 363 | //    `self`, which lives for at least `'a` by invariant on | 
|---|
| 364 | //    `Ptr`. | 
|---|
| 365 | // 8. `T: 'a`, because `elem` is an element within `[T]`, and | 
|---|
| 366 | //    `[T]: 'a` by invariant on `Ptr` | 
|---|
| 367 | Ptr { ptr: elem, _lifetime: PhantomData } | 
|---|
| 368 | }) | 
|---|
| 369 | } | 
|---|
| 370 | } | 
|---|
| 371 |  | 
|---|
| 372 | impl<'a, T: 'a + ?Sized> From<&'a T> for Ptr<'a, T> { | 
|---|
| 373 | #[ inline(always)] | 
|---|
| 374 | fn from(t: &'a T) -> Ptr<'a, T> { | 
|---|
| 375 | // SAFETY: `t` points to a valid Rust allocation, `A`, by | 
|---|
| 376 | // construction. Thus: | 
|---|
| 377 | // - `ptr` is derived from `A` | 
|---|
| 378 | // - Since we use `NonNull::from`, which preserves provenance, `ptr` | 
|---|
| 379 | //   has the same provenance as `A` | 
|---|
| 380 | // - Since `NonNull::from` creates a pointer which addresses the | 
|---|
| 381 | //   same bytes as `t`, `ptr` addresses a byte range entirely | 
|---|
| 382 | //   contained in (in this case, identical to) `A` | 
|---|
| 383 | // - Since `t: &T`, it addresses no more than `isize::MAX` bytes [1] | 
|---|
| 384 | // - Since `t: &T`, it addresses a byte range which does not wrap | 
|---|
| 385 | //   around the address space [2] | 
|---|
| 386 | // - Since it is constructed from a valid `&T`, `ptr` is | 
|---|
| 387 | //   validly-aligned for `T` | 
|---|
| 388 | // - Since `t: &'a T`, the allocation `A` is guaranteed to live for | 
|---|
| 389 | //   at least `'a` | 
|---|
| 390 | // - `T: 'a` by trait bound | 
|---|
| 391 | // | 
|---|
| 392 | // TODO(#429), | 
|---|
| 393 | // TODO(https://github.com/rust-lang/rust/issues/116181): Once it's | 
|---|
| 394 | // documented, reference the guarantee that `NonNull::from` | 
|---|
| 395 | // preserves provenance. | 
|---|
| 396 | // | 
|---|
| 397 | // TODO(#429), | 
|---|
| 398 | // TODO(https://github.com/rust-lang/unsafe-code-guidelines/issues/465): | 
|---|
| 399 | // - [1] Where does the reference document that allocations fit in | 
|---|
| 400 | //   `isize`? | 
|---|
| 401 | // - [2] Where does the reference document that allocations don't | 
|---|
| 402 | //   wrap around the address space? | 
|---|
| 403 | Ptr { ptr: NonNull::from(t), _lifetime: PhantomData } | 
|---|
| 404 | } | 
|---|
| 405 | } | 
|---|
| 406 |  | 
|---|
| 407 | impl<'a, T: 'a + ?Sized> Debug for Ptr<'a, T> { | 
|---|
| 408 | #[ inline] | 
|---|
| 409 | fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { | 
|---|
| 410 | self.ptr.fmt(f) | 
|---|
| 411 | } | 
|---|
| 412 | } | 
|---|
| 413 |  | 
|---|
| 414 | #[ cfg(test)] | 
|---|
| 415 | mod tests { | 
|---|
| 416 | use core::mem::{self, MaybeUninit}; | 
|---|
| 417 |  | 
|---|
| 418 | use super::*; | 
|---|
| 419 | use crate::{util::testutil::AU64, FromBytes}; | 
|---|
| 420 |  | 
|---|
| 421 | #[ test] | 
|---|
| 422 | fn test_ptrtry_cast_into_soundness() { | 
|---|
| 423 | // This test is designed so that if `Ptr::try_cast_into_xxx` are | 
|---|
| 424 | // buggy, it will manifest as unsoundness that Miri can detect. | 
|---|
| 425 |  | 
|---|
| 426 | // - If `size_of::<T>() == 0`, `N == 4` | 
|---|
| 427 | // - Else, `N == 4 * size_of::<T>()` | 
|---|
| 428 | fn test<const N: usize, T: ?Sized + KnownLayout + FromBytes>() { | 
|---|
| 429 | let mut bytes = [MaybeUninit::<u8>::uninit(); N]; | 
|---|
| 430 | let initialized = [MaybeUninit::new(0u8); N]; | 
|---|
| 431 | for start in 0..=bytes.len() { | 
|---|
| 432 | for end in start..=bytes.len() { | 
|---|
| 433 | // Set all bytes to uninitialized other than those in | 
|---|
| 434 | // the range we're going to pass to `try_cast_from`. | 
|---|
| 435 | // This allows Miri to detect out-of-bounds reads | 
|---|
| 436 | // because they read uninitialized memory. Without this, | 
|---|
| 437 | // some out-of-bounds reads would still be in-bounds of | 
|---|
| 438 | // `bytes`, and so might spuriously be accepted. | 
|---|
| 439 | bytes = [MaybeUninit::<u8>::uninit(); N]; | 
|---|
| 440 | let bytes = &mut bytes[start..end]; | 
|---|
| 441 | // Initialize only the byte range we're going to pass to | 
|---|
| 442 | // `try_cast_from`. | 
|---|
| 443 | bytes.copy_from_slice(&initialized[start..end]); | 
|---|
| 444 |  | 
|---|
| 445 | let bytes = { | 
|---|
| 446 | let bytes: *const [MaybeUninit<u8>] = bytes; | 
|---|
| 447 | #[ allow(clippy::as_conversions)] | 
|---|
| 448 | let bytes = bytes as *const [u8]; | 
|---|
| 449 | // SAFETY: We just initialized these bytes to valid | 
|---|
| 450 | // `u8`s. | 
|---|
| 451 | unsafe { &*bytes } | 
|---|
| 452 | }; | 
|---|
| 453 |  | 
|---|
| 454 | /// # Safety | 
|---|
| 455 | /// | 
|---|
| 456 | /// - `slf` must reference a byte range which is | 
|---|
| 457 | ///   entirely initialized. | 
|---|
| 458 | /// - `slf` must reference a byte range which is only | 
|---|
| 459 | ///   referenced by shared references which do not | 
|---|
| 460 | ///   contain `UnsafeCell`s during its lifetime. | 
|---|
| 461 | unsafe fn validate_and_get_len<T: ?Sized + KnownLayout + FromBytes>( | 
|---|
| 462 | slf: Ptr<'_, T>, | 
|---|
| 463 | ) -> usize { | 
|---|
| 464 | // SAFETY: | 
|---|
| 465 | // - Since all bytes in `slf` are initialized and | 
|---|
| 466 | //   `T: FromBytes`, `slf` contains a valid `T`. | 
|---|
| 467 | // - The caller promises that the referenced memory | 
|---|
| 468 | //   is not also referenced by any mutable | 
|---|
| 469 | //   references. | 
|---|
| 470 | // - The caller promises that the referenced memory | 
|---|
| 471 | //   is not also referenced as a type which contains | 
|---|
| 472 | //   `UnsafeCell`s. | 
|---|
| 473 | let t = unsafe { slf.as_ref() }; | 
|---|
| 474 |  | 
|---|
| 475 | let bytes = { | 
|---|
| 476 | let len = mem::size_of_val(t); | 
|---|
| 477 | let t: *const T = t; | 
|---|
| 478 | // SAFETY: | 
|---|
| 479 | // - We know `t`'s bytes are all initialized | 
|---|
| 480 | //   because we just read it from `slf`, which | 
|---|
| 481 | //   points to an initialized range of bytes. If | 
|---|
| 482 | //   there's a bug and this doesn't hold, then | 
|---|
| 483 | //   that's exactly what we're hoping Miri will | 
|---|
| 484 | //   catch! | 
|---|
| 485 | // - Since `T: FromBytes`, `T` doesn't contain | 
|---|
| 486 | //   any `UnsafeCell`s, so it's okay for `t: T` | 
|---|
| 487 | //   and a `&[u8]` to the same memory to be | 
|---|
| 488 | //   alive concurrently. | 
|---|
| 489 | unsafe { core::slice::from_raw_parts(t.cast::<u8>(), len) } | 
|---|
| 490 | }; | 
|---|
| 491 |  | 
|---|
| 492 | // This assertion ensures that `t`'s bytes are read | 
|---|
| 493 | // and compared to another value, which in turn | 
|---|
| 494 | // ensures that Miri gets a chance to notice if any | 
|---|
| 495 | // of `t`'s bytes are uninitialized, which they | 
|---|
| 496 | // shouldn't be (see the comment above). | 
|---|
| 497 | assert_eq!(bytes, vec![0u8; bytes.len()]); | 
|---|
| 498 |  | 
|---|
| 499 | mem::size_of_val(t) | 
|---|
| 500 | } | 
|---|
| 501 |  | 
|---|
| 502 | for cast_type in [_CastType::_Prefix, _CastType::_Suffix] { | 
|---|
| 503 | if let Some((slf, split_at)) = | 
|---|
| 504 | Ptr::from(bytes).try_cast_into::<T>(cast_type) | 
|---|
| 505 | { | 
|---|
| 506 | // SAFETY: All bytes in `bytes` have been | 
|---|
| 507 | // initialized. | 
|---|
| 508 | let len = unsafe { validate_and_get_len(slf) }; | 
|---|
| 509 | match cast_type { | 
|---|
| 510 | _CastType::_Prefix => assert_eq!(split_at, len), | 
|---|
| 511 | _CastType::_Suffix => assert_eq!(split_at, bytes.len() - len), | 
|---|
| 512 | } | 
|---|
| 513 | } | 
|---|
| 514 | } | 
|---|
| 515 |  | 
|---|
| 516 | if let Some(slf) = Ptr::from(bytes).try_cast_into_no_leftover::<T>() { | 
|---|
| 517 | // SAFETY: All bytes in `bytes` have been | 
|---|
| 518 | // initialized. | 
|---|
| 519 | let len = unsafe { validate_and_get_len(slf) }; | 
|---|
| 520 | assert_eq!(len, bytes.len()); | 
|---|
| 521 | } | 
|---|
| 522 | } | 
|---|
| 523 | } | 
|---|
| 524 | } | 
|---|
| 525 |  | 
|---|
| 526 | macro_rules! test { | 
|---|
| 527 | ($($ty:ty),*) => { | 
|---|
| 528 | $({ | 
|---|
| 529 | const S: usize = core::mem::size_of::<$ty>(); | 
|---|
| 530 | const N: usize = if S == 0 { 4 } else { S * 4 }; | 
|---|
| 531 | test::<N, $ty>(); | 
|---|
| 532 | // We don't support casting into DSTs whose trailing slice | 
|---|
| 533 | // element is a ZST. | 
|---|
| 534 | if S > 0 { | 
|---|
| 535 | test::<N, [$ty]>(); | 
|---|
| 536 | } | 
|---|
| 537 | // TODO: Test with a slice DST once we have any that | 
|---|
| 538 | // implement `KnownLayout + FromBytes`. | 
|---|
| 539 | })* | 
|---|
| 540 | }; | 
|---|
| 541 | } | 
|---|
| 542 |  | 
|---|
| 543 | test!(()); | 
|---|
| 544 | test!(u8, u16, u32, u64, u128, usize, AU64); | 
|---|
| 545 | test!(i8, i16, i32, i64, i128, isize); | 
|---|
| 546 | test!(f32, f64); | 
|---|
| 547 | } | 
|---|
| 548 | } | 
|---|
| 549 | } | 
|---|
| 550 |  | 
|---|
| 551 | pub(crate) trait AsAddress { | 
|---|
| 552 | fn addr(self) -> usize; | 
|---|
| 553 | } | 
|---|
| 554 |  | 
|---|
| 555 | impl<'a, T: ?Sized> AsAddress for &'a T { | 
|---|
| 556 | #[ inline(always)] | 
|---|
| 557 | fn addr(self) -> usize { | 
|---|
| 558 | let ptr: *const T = self; | 
|---|
| 559 | AsAddress::addr(self:ptr) | 
|---|
| 560 | } | 
|---|
| 561 | } | 
|---|
| 562 |  | 
|---|
| 563 | impl<'a, T: ?Sized> AsAddress for &'a mut T { | 
|---|
| 564 | #[ inline(always)] | 
|---|
| 565 | fn addr(self) -> usize { | 
|---|
| 566 | let ptr: *const T = self; | 
|---|
| 567 | AsAddress::addr(self:ptr) | 
|---|
| 568 | } | 
|---|
| 569 | } | 
|---|
| 570 |  | 
|---|
| 571 | impl<T: ?Sized> AsAddress for *const T { | 
|---|
| 572 | #[ inline(always)] | 
|---|
| 573 | fn addr(self) -> usize { | 
|---|
| 574 | // TODO(#181), TODO(https://github.com/rust-lang/rust/issues/95228): Use | 
|---|
| 575 | // `.addr()` instead of `as usize` once it's stable, and get rid of this | 
|---|
| 576 | // `allow`. Currently, `as usize` is the only way to accomplish this. | 
|---|
| 577 | #[ allow(clippy::as_conversions)] | 
|---|
| 578 | #[ cfg_attr(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS, allow(lossy_provenance_casts))] | 
|---|
| 579 | return self.cast::<()>() as usize; | 
|---|
| 580 | } | 
|---|
| 581 | } | 
|---|
| 582 |  | 
|---|
| 583 | impl<T: ?Sized> AsAddress for *mut T { | 
|---|
| 584 | #[ inline(always)] | 
|---|
| 585 | fn addr(self) -> usize { | 
|---|
| 586 | let ptr: *const T = self; | 
|---|
| 587 | AsAddress::addr(self:ptr) | 
|---|
| 588 | } | 
|---|
| 589 | } | 
|---|
| 590 |  | 
|---|
| 591 | /// Is `t` aligned to `mem::align_of::<U>()`? | 
|---|
| 592 | #[ inline(always)] | 
|---|
| 593 | pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool { | 
|---|
| 594 | // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in | 
|---|
| 595 | // turn guarantees that this mod operation will not panic. | 
|---|
| 596 | #[ allow(clippy::arithmetic_side_effects)] | 
|---|
| 597 | let remainder: usize = t.addr() % mem::align_of::<U>(); | 
|---|
| 598 | remainder == 0 | 
|---|
| 599 | } | 
|---|
| 600 |  | 
|---|
| 601 | /// Round `n` down to the largest value `m` such that `m <= n` and `m % align == | 
|---|
| 602 | /// 0`. | 
|---|
| 603 | /// | 
|---|
| 604 | /// # Panics | 
|---|
| 605 | /// | 
|---|
| 606 | /// May panic if `align` is not a power of two. Even if it doesn't panic in this | 
|---|
| 607 | /// case, it will produce nonsense results. | 
|---|
| 608 | #[ inline(always)] | 
|---|
| 609 | pub(crate) const fn round_down_to_next_multiple_of_alignment( | 
|---|
| 610 | n: usize, | 
|---|
| 611 | align: NonZeroUsize, | 
|---|
| 612 | ) -> usize { | 
|---|
| 613 | let align: usize = align.get(); | 
|---|
| 614 | debug_assert!(align.is_power_of_two()); | 
|---|
| 615 |  | 
|---|
| 616 | // Subtraction can't underflow because `align.get() >= 1`. | 
|---|
| 617 | #[ allow(clippy::arithmetic_side_effects)] | 
|---|
| 618 | let mask: usize = !(align - 1); | 
|---|
| 619 | n & mask | 
|---|
| 620 | } | 
|---|
| 621 |  | 
|---|
| 622 | pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize { | 
|---|
| 623 | if a.get() < b.get() { | 
|---|
| 624 | b | 
|---|
| 625 | } else { | 
|---|
| 626 | a | 
|---|
| 627 | } | 
|---|
| 628 | } | 
|---|
| 629 |  | 
|---|
| 630 | pub(crate) const fn min(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize { | 
|---|
| 631 | if a.get() > b.get() { | 
|---|
| 632 | b | 
|---|
| 633 | } else { | 
|---|
| 634 | a | 
|---|
| 635 | } | 
|---|
| 636 | } | 
|---|
| 637 |  | 
|---|
| 638 | /// Since we support multiple versions of Rust, there are often features which | 
|---|
| 639 | /// have been stabilized in the most recent stable release which do not yet | 
|---|
| 640 | /// exist (stably) on our MSRV. This module provides polyfills for those | 
|---|
| 641 | /// features so that we can write more "modern" code, and just remove the | 
|---|
| 642 | /// polyfill once our MSRV supports the corresponding feature. Without this, | 
|---|
| 643 | /// we'd have to write worse/more verbose code and leave TODO comments sprinkled | 
|---|
| 644 | /// throughout the codebase to update to the new pattern once it's stabilized. | 
|---|
| 645 | /// | 
|---|
| 646 | /// Each trait is imported as `_` at the crate root; each polyfill should "just | 
|---|
| 647 | /// work" at usage sites. | 
|---|
| 648 | pub(crate) mod polyfills { | 
|---|
| 649 | use core::ptr::{self, NonNull}; | 
|---|
| 650 |  | 
|---|
| 651 | // A polyfill for `NonNull::slice_from_raw_parts` that we can use before our | 
|---|
| 652 | // MSRV is 1.70, when that function was stabilized. | 
|---|
| 653 | // | 
|---|
| 654 | // TODO(#67): Once our MSRV is 1.70, remove this. | 
|---|
| 655 | #[ allow(unused)] | 
|---|
| 656 | pub(crate) trait NonNullExt<T> { | 
|---|
| 657 | fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]>; | 
|---|
| 658 | } | 
|---|
| 659 |  | 
|---|
| 660 | #[ allow(unused)] | 
|---|
| 661 | impl<T> NonNullExt<T> for NonNull<T> { | 
|---|
| 662 | #[ inline(always)] | 
|---|
| 663 | fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]> { | 
|---|
| 664 | let ptr: *mut [T] = ptr::slice_from_raw_parts_mut(data.as_ptr(), len); | 
|---|
| 665 | // SAFETY: `ptr` is converted from `data`, which is non-null. | 
|---|
| 666 | unsafe { NonNull::new_unchecked(ptr) } | 
|---|
| 667 | } | 
|---|
| 668 | } | 
|---|
| 669 | } | 
|---|
| 670 |  | 
|---|
| 671 | #[ cfg(test)] | 
|---|
| 672 | pub(crate) mod testutil { | 
|---|
| 673 | use core::fmt::{self, Display, Formatter}; | 
|---|
| 674 |  | 
|---|
| 675 | use crate::*; | 
|---|
| 676 |  | 
|---|
| 677 | /// A `T` which is aligned to at least `align_of::<A>()`. | 
|---|
| 678 | #[ derive(Default)] | 
|---|
| 679 | pub(crate) struct Align<T, A> { | 
|---|
| 680 | pub(crate) t: T, | 
|---|
| 681 | _a: [A; 0], | 
|---|
| 682 | } | 
|---|
| 683 |  | 
|---|
| 684 | impl<T: Default, A> Align<T, A> { | 
|---|
| 685 | pub(crate) fn set_default(&mut self) { | 
|---|
| 686 | self.t = T::default(); | 
|---|
| 687 | } | 
|---|
| 688 | } | 
|---|
| 689 |  | 
|---|
| 690 | impl<T, A> Align<T, A> { | 
|---|
| 691 | pub(crate) const fn new(t: T) -> Align<T, A> { | 
|---|
| 692 | Align { t, _a: [] } | 
|---|
| 693 | } | 
|---|
| 694 | } | 
|---|
| 695 |  | 
|---|
| 696 | // A `u64` with alignment 8. | 
|---|
| 697 | // | 
|---|
| 698 | // Though `u64` has alignment 8 on some platforms, it's not guaranteed. | 
|---|
| 699 | // By contrast, `AU64` is guaranteed to have alignment 8. | 
|---|
| 700 | #[ derive( | 
|---|
| 701 | KnownLayout, | 
|---|
| 702 | FromZeroes, | 
|---|
| 703 | FromBytes, | 
|---|
| 704 | AsBytes, | 
|---|
| 705 | Eq, | 
|---|
| 706 | PartialEq, | 
|---|
| 707 | Ord, | 
|---|
| 708 | PartialOrd, | 
|---|
| 709 | Default, | 
|---|
| 710 | Debug, | 
|---|
| 711 | Copy, | 
|---|
| 712 | Clone, | 
|---|
| 713 | )] | 
|---|
| 714 | #[ repr(C, align(8))] | 
|---|
| 715 | pub(crate) struct AU64(pub(crate) u64); | 
|---|
| 716 |  | 
|---|
| 717 | impl AU64 { | 
|---|
| 718 | // Converts this `AU64` to bytes using this platform's endianness. | 
|---|
| 719 | pub(crate) fn to_bytes(self) -> [u8; 8] { | 
|---|
| 720 | crate::transmute!(self) | 
|---|
| 721 | } | 
|---|
| 722 | } | 
|---|
| 723 |  | 
|---|
| 724 | impl Display for AU64 { | 
|---|
| 725 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { | 
|---|
| 726 | Display::fmt(&self.0, f) | 
|---|
| 727 | } | 
|---|
| 728 | } | 
|---|
| 729 |  | 
|---|
| 730 | #[ derive( | 
|---|
| 731 | FromZeroes, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone, | 
|---|
| 732 | )] | 
|---|
| 733 | #[ repr(C)] | 
|---|
| 734 | pub(crate) struct Nested<T, U: ?Sized> { | 
|---|
| 735 | _t: T, | 
|---|
| 736 | _u: U, | 
|---|
| 737 | } | 
|---|
| 738 | } | 
|---|
| 739 |  | 
|---|
| 740 | #[ cfg(test)] | 
|---|
| 741 | mod tests { | 
|---|
| 742 | use super::*; | 
|---|
| 743 |  | 
|---|
| 744 | #[ test] | 
|---|
| 745 | fn test_round_down_to_next_multiple_of_alignment() { | 
|---|
| 746 | fn alt_impl(n: usize, align: NonZeroUsize) -> usize { | 
|---|
| 747 | let mul = n / align.get(); | 
|---|
| 748 | mul * align.get() | 
|---|
| 749 | } | 
|---|
| 750 |  | 
|---|
| 751 | for align in [1, 2, 4, 8, 16] { | 
|---|
| 752 | for n in 0..256 { | 
|---|
| 753 | let align = NonZeroUsize::new(align).unwrap(); | 
|---|
| 754 | let want = alt_impl(n, align); | 
|---|
| 755 | let got = round_down_to_next_multiple_of_alignment(n, align); | 
|---|
| 756 | assert_eq!(got, want, "round_down_to_next_multiple_of_alignment({n}, {align})"); | 
|---|
| 757 | } | 
|---|
| 758 | } | 
|---|
| 759 | } | 
|---|
| 760 | } | 
|---|
| 761 |  | 
|---|
| 762 | #[ cfg(kani)] | 
|---|
| 763 | mod proofs { | 
|---|
| 764 | use super::*; | 
|---|
| 765 |  | 
|---|
| 766 | #[kani::proof] | 
|---|
| 767 | fn prove_round_down_to_next_multiple_of_alignment() { | 
|---|
| 768 | fn model_impl(n: usize, align: NonZeroUsize) -> usize { | 
|---|
| 769 | assert!(align.get().is_power_of_two()); | 
|---|
| 770 | let mul = n / align.get(); | 
|---|
| 771 | mul * align.get() | 
|---|
| 772 | } | 
|---|
| 773 |  | 
|---|
| 774 | let align: NonZeroUsize = kani::any(); | 
|---|
| 775 | kani::assume(align.get().is_power_of_two()); | 
|---|
| 776 | let n: usize = kani::any(); | 
|---|
| 777 |  | 
|---|
| 778 | let expected = model_impl(n, align); | 
|---|
| 779 | let actual = round_down_to_next_multiple_of_alignment(n, align); | 
|---|
| 780 | assert_eq!(expected, actual, "round_down_to_next_multiple_of_alignment({n}, {align})"); | 
|---|
| 781 | } | 
|---|
| 782 |  | 
|---|
| 783 | // Restricted to nightly since we use the unstable `usize::next_multiple_of` | 
|---|
| 784 | // in our model implementation. | 
|---|
| 785 | #[ cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)] | 
|---|
| 786 | #[kani::proof] | 
|---|
| 787 | fn prove_padding_needed_for() { | 
|---|
| 788 | fn model_impl(len: usize, align: NonZeroUsize) -> usize { | 
|---|
| 789 | let padded = len.next_multiple_of(align.get()); | 
|---|
| 790 | let padding = padded - len; | 
|---|
| 791 | padding | 
|---|
| 792 | } | 
|---|
| 793 |  | 
|---|
| 794 | let align: NonZeroUsize = kani::any(); | 
|---|
| 795 | kani::assume(align.get().is_power_of_two()); | 
|---|
| 796 | let len: usize = kani::any(); | 
|---|
| 797 | // Constrain `len` to valid Rust lengths, since our model implementation | 
|---|
| 798 | // isn't robust to overflow. | 
|---|
| 799 | kani::assume(len <= isize::MAX as usize); | 
|---|
| 800 | kani::assume(align.get() < 1 << 29); | 
|---|
| 801 |  | 
|---|
| 802 | let expected = model_impl(len, align); | 
|---|
| 803 | let actual = core_layout::padding_needed_for(len, align); | 
|---|
| 804 | assert_eq!(expected, actual, "padding_needed_for({len}, {align})"); | 
|---|
| 805 |  | 
|---|
| 806 | let padded_len = actual + len; | 
|---|
| 807 | assert_eq!(padded_len % align, 0); | 
|---|
| 808 | assert!(padded_len / align >= len / align); | 
|---|
| 809 | } | 
|---|
| 810 | } | 
|---|
| 811 |  | 
|---|