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"]
10pub(crate) mod core_layout;
11
12use core::{mem, num::NonZeroUsize};
13
14pub(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
551pub(crate) trait AsAddress {
552 fn addr(self) -> usize;
553}
554
555impl<'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
563impl<'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
571impl<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
583impl<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)]
593pub(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)]
609pub(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
622pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
623 if a.get() < b.get() {
624 b
625 } else {
626 a
627 }
628}
629
630pub(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.
648pub(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 pub(crate) trait NonNullExt<T> {
656 fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]>;
657 }
658
659 impl<T> NonNullExt<T> for NonNull<T> {
660 #[inline(always)]
661 fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]> {
662 let ptr: *mut [T] = ptr::slice_from_raw_parts_mut(data:data.as_ptr(), len);
663 // SAFETY: `ptr` is converted from `data`, which is non-null.
664 unsafe { NonNull::new_unchecked(ptr) }
665 }
666 }
667}
668
669#[cfg(test)]
670pub(crate) mod testutil {
671 use core::fmt::{self, Display, Formatter};
672
673 use crate::*;
674
675 /// A `T` which is aligned to at least `align_of::<A>()`.
676 #[derive(Default)]
677 pub(crate) struct Align<T, A> {
678 pub(crate) t: T,
679 _a: [A; 0],
680 }
681
682 impl<T: Default, A> Align<T, A> {
683 pub(crate) fn set_default(&mut self) {
684 self.t = T::default();
685 }
686 }
687
688 impl<T, A> Align<T, A> {
689 pub(crate) const fn new(t: T) -> Align<T, A> {
690 Align { t, _a: [] }
691 }
692 }
693
694 // A `u64` with alignment 8.
695 //
696 // Though `u64` has alignment 8 on some platforms, it's not guaranteed.
697 // By contrast, `AU64` is guaranteed to have alignment 8.
698 #[derive(
699 KnownLayout,
700 FromZeroes,
701 FromBytes,
702 AsBytes,
703 Eq,
704 PartialEq,
705 Ord,
706 PartialOrd,
707 Default,
708 Debug,
709 Copy,
710 Clone,
711 )]
712 #[repr(C, align(8))]
713 pub(crate) struct AU64(pub(crate) u64);
714
715 impl AU64 {
716 // Converts this `AU64` to bytes using this platform's endianness.
717 pub(crate) fn to_bytes(self) -> [u8; 8] {
718 crate::transmute!(self)
719 }
720 }
721
722 impl Display for AU64 {
723 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
724 Display::fmt(&self.0, f)
725 }
726 }
727
728 #[derive(
729 FromZeroes, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone,
730 )]
731 #[repr(C)]
732 pub(crate) struct Nested<T, U: ?Sized> {
733 _t: T,
734 _u: U,
735 }
736}
737
738#[cfg(test)]
739mod tests {
740 use super::*;
741
742 #[test]
743 fn test_round_down_to_next_multiple_of_alignment() {
744 fn alt_impl(n: usize, align: NonZeroUsize) -> usize {
745 let mul = n / align.get();
746 mul * align.get()
747 }
748
749 for align in [1, 2, 4, 8, 16] {
750 for n in 0..256 {
751 let align = NonZeroUsize::new(align).unwrap();
752 let want = alt_impl(n, align);
753 let got = round_down_to_next_multiple_of_alignment(n, align);
754 assert_eq!(got, want, "round_down_to_next_multiple_of_alignment({n}, {align})");
755 }
756 }
757 }
758}
759
760#[cfg(kani)]
761mod proofs {
762 use super::*;
763
764 #[kani::proof]
765 fn prove_round_down_to_next_multiple_of_alignment() {
766 fn model_impl(n: usize, align: NonZeroUsize) -> usize {
767 assert!(align.get().is_power_of_two());
768 let mul = n / align.get();
769 mul * align.get()
770 }
771
772 let align: NonZeroUsize = kani::any();
773 kani::assume(align.get().is_power_of_two());
774 let n: usize = kani::any();
775
776 let expected = model_impl(n, align);
777 let actual = round_down_to_next_multiple_of_alignment(n, align);
778 assert_eq!(expected, actual, "round_down_to_next_multiple_of_alignment({n}, {align})");
779 }
780
781 // Restricted to nightly since we use the unstable `usize::next_multiple_of`
782 // in our model implementation.
783 #[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
784 #[kani::proof]
785 fn prove_padding_needed_for() {
786 fn model_impl(len: usize, align: NonZeroUsize) -> usize {
787 let padded = len.next_multiple_of(align.get());
788 let padding = padded - len;
789 padding
790 }
791
792 let align: NonZeroUsize = kani::any();
793 kani::assume(align.get().is_power_of_two());
794 let len: usize = kani::any();
795 // Constrain `len` to valid Rust lengths, since our model implementation
796 // isn't robust to overflow.
797 kani::assume(len <= isize::MAX as usize);
798 kani::assume(align.get() < 1 << 29);
799
800 let expected = model_impl(len, align);
801 let actual = core_layout::padding_needed_for(len, align);
802 assert_eq!(expected, actual, "padding_needed_for({len}, {align})");
803
804 let padded_len = actual + len;
805 assert_eq!(padded_len % align, 0);
806 assert!(padded_len / align >= len / align);
807 }
808}
809