zerocopy/util/mod.rs
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#[macro_use]
10mod macros;
11
12#[doc(hidden)]
13pub mod macro_util;
14
15use core::{
16 marker::PhantomData,
17 mem::{self, ManuallyDrop},
18 num::NonZeroUsize,
19 ptr::NonNull,
20};
21
22use super::*;
23
24/// Like [`PhantomData`], but [`Send`] and [`Sync`] regardless of whether the
25/// wrapped `T` is.
26pub(crate) struct SendSyncPhantomData<T: ?Sized>(PhantomData<T>);
27
28// SAFETY: `SendSyncPhantomData` does not enable any behavior which isn't sound
29// to be called from multiple threads.
30unsafe impl<T: ?Sized> Send for SendSyncPhantomData<T> {}
31// SAFETY: `SendSyncPhantomData` does not enable any behavior which isn't sound
32// to be called from multiple threads.
33unsafe impl<T: ?Sized> Sync for SendSyncPhantomData<T> {}
34
35impl<T: ?Sized> Default for SendSyncPhantomData<T> {
36 fn default() -> SendSyncPhantomData<T> {
37 SendSyncPhantomData(PhantomData)
38 }
39}
40
41impl<T: ?Sized> PartialEq for SendSyncPhantomData<T> {
42 fn eq(&self, other: &Self) -> bool {
43 self.0.eq(&other.0)
44 }
45}
46
47impl<T: ?Sized> Eq for SendSyncPhantomData<T> {}
48
49pub(crate) trait AsAddress {
50 fn addr(self) -> usize;
51}
52
53impl<T: ?Sized> AsAddress for &T {
54 #[inline(always)]
55 fn addr(self) -> usize {
56 let ptr: *const T = self;
57 AsAddress::addr(ptr)
58 }
59}
60
61impl<T: ?Sized> AsAddress for &mut T {
62 #[inline(always)]
63 fn addr(self) -> usize {
64 let ptr: *const T = self;
65 AsAddress::addr(ptr)
66 }
67}
68
69impl<T: ?Sized> AsAddress for NonNull<T> {
70 #[inline(always)]
71 fn addr(self) -> usize {
72 AsAddress::addr(self.as_ptr())
73 }
74}
75
76impl<T: ?Sized> AsAddress for *const T {
77 #[inline(always)]
78 fn addr(self) -> usize {
79 // TODO(#181), TODO(https://github.com/rust-lang/rust/issues/95228): Use
80 // `.addr()` instead of `as usize` once it's stable, and get rid of this
81 // `allow`. Currently, `as usize` is the only way to accomplish this.
82 #[allow(clippy::as_conversions)]
83 #[cfg_attr(
84 __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS,
85 allow(lossy_provenance_casts)
86 )]
87 return self.cast::<()>() as usize;
88 }
89}
90
91impl<T: ?Sized> AsAddress for *mut T {
92 #[inline(always)]
93 fn addr(self) -> usize {
94 let ptr: *const T = self;
95 AsAddress::addr(ptr)
96 }
97}
98
99/// Validates that `t` is aligned to `align_of::<U>()`.
100#[inline(always)]
101pub(crate) fn validate_aligned_to<T: AsAddress, U>(t: T) -> Result<(), AlignmentError<(), U>> {
102 // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
103 // turn guarantees that this mod operation will not panic.
104 #[allow(clippy::arithmetic_side_effects)]
105 let remainder = t.addr() % mem::align_of::<U>();
106 if remainder == 0 {
107 Ok(())
108 } else {
109 // SAFETY: We just confirmed that `t.addr() % align_of::<U>() != 0`.
110 // That's only possible if `align_of::<U>() > 1`.
111 Err(unsafe { AlignmentError::new_unchecked(()) })
112 }
113}
114
115/// Returns the bytes needed to pad `len` to the next multiple of `align`.
116///
117/// This function assumes that align is a power of two; there are no guarantees
118/// on the answer it gives if this is not the case.
119#[cfg_attr(
120 kani,
121 kani::requires(len <= isize::MAX as usize),
122 kani::requires(align.is_power_of_two()),
123 kani::ensures(|&p| (len + p) % align.get() == 0),
124 // Ensures that we add the minimum required padding.
125 kani::ensures(|&p| p < align.get()),
126)]
127pub(crate) const fn padding_needed_for(len: usize, align: NonZeroUsize) -> usize {
128 #[cfg(kani)]
129 #[kani::proof_for_contract(padding_needed_for)]
130 fn proof() {
131 padding_needed_for(kani::any(), kani::any());
132 }
133
134 // Abstractly, we want to compute:
135 // align - (len % align).
136 // Handling the case where len%align is 0.
137 // Because align is a power of two, len % align = len & (align-1).
138 // Guaranteed not to underflow as align is nonzero.
139 #[allow(clippy::arithmetic_side_effects)]
140 let mask = align.get() - 1;
141
142 // To efficiently subtract this value from align, we can use the bitwise complement.
143 // Note that ((!len) & (align-1)) gives us a number that with (len &
144 // (align-1)) sums to align-1. So subtracting 1 from x before taking the
145 // complement subtracts `len` from `align`. Some quick inspection of
146 // cases shows that this also handles the case where `len % align = 0`
147 // correctly too: len-1 % align then equals align-1, so the complement mod
148 // align will be 0, as desired.
149 //
150 // The following reasoning can be verified quickly by an SMT solver
151 // supporting the theory of bitvectors:
152 // ```smtlib
153 // ; Naive implementation of padding
154 // (define-fun padding1 (
155 // (len (_ BitVec 32))
156 // (align (_ BitVec 32))) (_ BitVec 32)
157 // (ite
158 // (= (_ bv0 32) (bvand len (bvsub align (_ bv1 32))))
159 // (_ bv0 32)
160 // (bvsub align (bvand len (bvsub align (_ bv1 32))))))
161 //
162 // ; The implementation below
163 // (define-fun padding2 (
164 // (len (_ BitVec 32))
165 // (align (_ BitVec 32))) (_ BitVec 32)
166 // (bvand (bvnot (bvsub len (_ bv1 32))) (bvsub align (_ bv1 32))))
167 //
168 // (define-fun is-power-of-two ((x (_ BitVec 32))) Bool
169 // (= (_ bv0 32) (bvand x (bvsub x (_ bv1 32)))))
170 //
171 // (declare-const len (_ BitVec 32))
172 // (declare-const align (_ BitVec 32))
173 // ; Search for a case where align is a power of two and padding2 disagrees with padding1
174 // (assert (and (is-power-of-two align)
175 // (not (= (padding1 len align) (padding2 len align)))))
176 // (simplify (padding1 (_ bv300 32) (_ bv32 32))) ; 20
177 // (simplify (padding2 (_ bv300 32) (_ bv32 32))) ; 20
178 // (simplify (padding1 (_ bv322 32) (_ bv32 32))) ; 30
179 // (simplify (padding2 (_ bv322 32) (_ bv32 32))) ; 30
180 // (simplify (padding1 (_ bv8 32) (_ bv8 32))) ; 0
181 // (simplify (padding2 (_ bv8 32) (_ bv8 32))) ; 0
182 // (check-sat) ; unsat, also works for 64-bit bitvectors
183 // ```
184 !(len.wrapping_sub(1)) & mask
185}
186
187/// Rounds `n` down to the largest value `m` such that `m <= n` and `m % align
188/// == 0`.
189///
190/// # Panics
191///
192/// May panic if `align` is not a power of two. Even if it doesn't panic in this
193/// case, it will produce nonsense results.
194#[inline(always)]
195#[cfg_attr(
196 kani,
197 kani::requires(align.is_power_of_two()),
198 kani::ensures(|&m| m <= n && m % align.get() == 0),
199 // Guarantees that `m` is the *largest* value such that `m % align == 0`.
200 kani::ensures(|&m| {
201 // If this `checked_add` fails, then the next multiple would wrap
202 // around, which trivially satisfies the "largest value" requirement.
203 m.checked_add(align.get()).map(|next_mul| next_mul > n).unwrap_or(true)
204 })
205)]
206pub(crate) const fn round_down_to_next_multiple_of_alignment(
207 n: usize,
208 align: NonZeroUsize,
209) -> usize {
210 #[cfg(kani)]
211 #[kani::proof_for_contract(round_down_to_next_multiple_of_alignment)]
212 fn proof() {
213 round_down_to_next_multiple_of_alignment(kani::any(), kani::any());
214 }
215
216 let align = align.get();
217 #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
218 debug_assert!(align.is_power_of_two());
219
220 // Subtraction can't underflow because `align.get() >= 1`.
221 #[allow(clippy::arithmetic_side_effects)]
222 let mask = !(align - 1);
223 n & mask
224}
225
226pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
227 if a.get() < b.get() {
228 b
229 } else {
230 a
231 }
232}
233
234pub(crate) const fn min(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
235 if a.get() > b.get() {
236 b
237 } else {
238 a
239 }
240}
241
242/// Copies `src` into the prefix of `dst`.
243///
244/// # Safety
245///
246/// The caller guarantees that `src.len() <= dst.len()`.
247#[inline(always)]
248pub(crate) unsafe fn copy_unchecked(src: &[u8], dst: &mut [u8]) {
249 debug_assert!(src.len() <= dst.len());
250 // SAFETY: This invocation satisfies the safety contract of
251 // copy_nonoverlapping [1]:
252 // - `src.as_ptr()` is trivially valid for reads of `src.len()` bytes
253 // - `dst.as_ptr()` is valid for writes of `src.len()` bytes, because the
254 // caller has promised that `src.len() <= dst.len()`
255 // - `src` and `dst` are, trivially, properly aligned
256 // - the region of memory beginning at `src` with a size of `src.len()`
257 // bytes does not overlap with the region of memory beginning at `dst`
258 // with the same size, because `dst` is derived from an exclusive
259 // reference.
260 unsafe {
261 core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), src.len());
262 };
263}
264
265/// Unsafely transmutes the given `src` into a type `Dst`.
266///
267/// # Safety
268///
269/// The value `src` must be a valid instance of `Dst`.
270#[inline(always)]
271pub(crate) const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst {
272 static_assert!(Src, Dst => core::mem::size_of::<Src>() == core::mem::size_of::<Dst>());
273
274 #[repr(C)]
275 union Transmute<Src, Dst> {
276 src: ManuallyDrop<Src>,
277 dst: ManuallyDrop<Dst>,
278 }
279
280 // SAFETY: Since `Transmute<Src, Dst>` is `#[repr(C)]`, its `src` and `dst`
281 // fields both start at the same offset and the types of those fields are
282 // transparent wrappers around `Src` and `Dst` [1]. Consequently,
283 // initializng `Transmute` with with `src` and then reading out `dst` is
284 // equivalent to transmuting from `Src` to `Dst` [2]. Transmuting from `src`
285 // to `Dst` is valid because — by contract on the caller — `src` is a valid
286 // instance of `Dst`.
287 //
288 // [1] Per https://doc.rust-lang.org/1.82.0/std/mem/struct.ManuallyDrop.html:
289 //
290 // `ManuallyDrop<T>` is guaranteed to have the same layout and bit
291 // validity as `T`, and is subject to the same layout optimizations as
292 // `T`.
293 //
294 // [2] Per https://doc.rust-lang.org/1.82.0/reference/items/unions.html#reading-and-writing-union-fields:
295 //
296 // Effectively, writing to and then reading from a union with the C
297 // representation is analogous to a transmute from the type used for
298 // writing to the type used for reading.
299 unsafe { ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst) }
300}
301
302/// Uses `allocate` to create a `Box<T>`.
303///
304/// # Errors
305///
306/// Returns an error on allocation failure. Allocation failure is guaranteed
307/// never to cause a panic or an abort.
308///
309/// # Safety
310///
311/// `allocate` must be either `alloc::alloc::alloc` or
312/// `alloc::alloc::alloc_zeroed`. The referent of the box returned by `new_box`
313/// has the same bit-validity as the referent of the pointer returned by the
314/// given `allocate` and sufficient size to store `T` with `meta`.
315#[must_use = "has no side effects (other than allocation)"]
316#[cfg(feature = "alloc")]
317#[inline]
318pub(crate) unsafe fn new_box<T>(
319 meta: T::PointerMetadata,
320 allocate: unsafe fn(core::alloc::Layout) -> *mut u8,
321) -> Result<alloc::boxed::Box<T>, AllocError>
322where
323 T: ?Sized + crate::KnownLayout,
324{
325 let size = match meta.size_for_metadata(T::LAYOUT) {
326 Some(size) => size,
327 None => return Err(AllocError),
328 };
329
330 let align = T::LAYOUT.align.get();
331 // On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a bug in
332 // which sufficiently-large allocations (those which, when rounded up to the
333 // alignment, overflow `isize`) are not rejected, which can cause undefined
334 // behavior. See #64 for details.
335 //
336 // TODO(#67): Once our MSRV is > 1.64.0, remove this assertion.
337 #[allow(clippy::as_conversions)]
338 let max_alloc = (isize::MAX as usize).saturating_sub(align);
339 if size > max_alloc {
340 return Err(AllocError);
341 }
342
343 // TODO(https://github.com/rust-lang/rust/issues/55724): Use
344 // `Layout::repeat` once it's stabilized.
345 let layout = Layout::from_size_align(size, align).or(Err(AllocError))?;
346
347 let ptr = if layout.size() != 0 {
348 // SAFETY: By contract on the caller, `allocate` is either
349 // `alloc::alloc::alloc` or `alloc::alloc::alloc_zeroed`. The above
350 // check ensures their shared safety precondition: that the supplied
351 // layout is not zero-sized type [1].
352 //
353 // [1] Per https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html#tymethod.alloc:
354 //
355 // This function is unsafe because undefined behavior can result if
356 // the caller does not ensure that layout has non-zero size.
357 let ptr = unsafe { allocate(layout) };
358 match NonNull::new(ptr) {
359 Some(ptr) => ptr,
360 None => return Err(AllocError),
361 }
362 } else {
363 let align = T::LAYOUT.align.get();
364 // We use `transmute` instead of an `as` cast since Miri (with strict
365 // provenance enabled) notices and complains that an `as` cast creates a
366 // pointer with no provenance. Miri isn't smart enough to realize that
367 // we're only executing this branch when we're constructing a zero-sized
368 // `Box`, which doesn't require provenance.
369 //
370 // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`. All
371 // bits of a `usize` are initialized.
372 #[allow(clippy::useless_transmute)]
373 let dangling = unsafe { mem::transmute::<usize, *mut u8>(align) };
374 // SAFETY: `dangling` is constructed from `T::LAYOUT.align`, which is a
375 // `NonZeroUsize`, which is guaranteed to be non-zero.
376 //
377 // `Box<[T]>` does not allocate when `T` is zero-sized or when `len` is
378 // zero, but it does require a non-null dangling pointer for its
379 // allocation.
380 //
381 // TODO(https://github.com/rust-lang/rust/issues/95228): Use
382 // `std::ptr::without_provenance` once it's stable. That may optimize
383 // better. As written, Rust may assume that this consumes "exposed"
384 // provenance, and thus Rust may have to assume that this may consume
385 // provenance from any pointer whose provenance has been exposed.
386 unsafe { NonNull::new_unchecked(dangling) }
387 };
388
389 let ptr = T::raw_from_ptr_len(ptr, meta);
390
391 // TODO(#429): Add a "SAFETY" comment and remove this `allow`. Make sure to
392 // include a justification that `ptr.as_ptr()` is validly-aligned in the ZST
393 // case (in which we manually construct a dangling pointer) and to justify
394 // why `Box` is safe to drop (it's because `allocate` uses the system
395 // allocator).
396 #[allow(clippy::undocumented_unsafe_blocks)]
397 Ok(unsafe { alloc::boxed::Box::from_raw(ptr.as_ptr()) })
398}
399
400/// Since we support multiple versions of Rust, there are often features which
401/// have been stabilized in the most recent stable release which do not yet
402/// exist (stably) on our MSRV. This module provides polyfills for those
403/// features so that we can write more "modern" code, and just remove the
404/// polyfill once our MSRV supports the corresponding feature. Without this,
405/// we'd have to write worse/more verbose code and leave TODO comments sprinkled
406/// throughout the codebase to update to the new pattern once it's stabilized.
407///
408/// Each trait is imported as `_` at the crate root; each polyfill should "just
409/// work" at usage sites.
410pub(crate) mod polyfills {
411 use core::ptr::{self, NonNull};
412
413 // A polyfill for `NonNull::slice_from_raw_parts` that we can use before our
414 // MSRV is 1.70, when that function was stabilized.
415 //
416 // The `#[allow(unused)]` is necessary because, on sufficiently recent
417 // toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent
418 // method rather than to this trait, and so this trait is considered unused.
419 //
420 // TODO(#67): Once our MSRV is 1.70, remove this.
421 #[allow(unused)]
422 pub(crate) trait NonNullExt<T> {
423 fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]>;
424 }
425
426 impl<T> NonNullExt<T> for NonNull<T> {
427 // NOTE on coverage: this will never be tested in nightly since it's a
428 // polyfill for a feature which has been stabilized on our nightly
429 // toolchain.
430 #[cfg_attr(
431 all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
432 coverage(off)
433 )]
434 #[inline(always)]
435 fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]> {
436 let ptr = ptr::slice_from_raw_parts_mut(data.as_ptr(), len);
437 // SAFETY: `ptr` is converted from `data`, which is non-null.
438 unsafe { NonNull::new_unchecked(ptr) }
439 }
440 }
441
442 // A polyfill for `Self::unchecked_sub` that we can use until methods like
443 // `usize::unchecked_sub` is stabilized.
444 //
445 // The `#[allow(unused)]` is necessary because, on sufficiently recent
446 // toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent
447 // method rather than to this trait, and so this trait is considered unused.
448 //
449 // TODO(#67): Once our MSRV is high enough, remove this.
450 #[allow(unused)]
451 pub(crate) trait NumExt {
452 /// Subtract without checking for underflow.
453 ///
454 /// # Safety
455 ///
456 /// The caller promises that the subtraction will not underflow.
457 unsafe fn unchecked_sub(self, rhs: Self) -> Self;
458 }
459
460 impl NumExt for usize {
461 // NOTE on coverage: this will never be tested in nightly since it's a
462 // polyfill for a feature which has been stabilized on our nightly
463 // toolchain.
464 #[cfg_attr(
465 all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
466 coverage(off)
467 )]
468 #[inline(always)]
469 unsafe fn unchecked_sub(self, rhs: usize) -> usize {
470 match self.checked_sub(rhs) {
471 Some(x) => x,
472 None => {
473 // SAFETY: The caller promises that the subtraction will not
474 // underflow.
475 unsafe { core::hint::unreachable_unchecked() }
476 }
477 }
478 }
479 }
480}
481
482#[cfg(test)]
483pub(crate) mod testutil {
484 use crate::*;
485
486 /// A `T` which is aligned to at least `align_of::<A>()`.
487 #[derive(Default)]
488 pub(crate) struct Align<T, A> {
489 pub(crate) t: T,
490 _a: [A; 0],
491 }
492
493 impl<T: Default, A> Align<T, A> {
494 pub(crate) fn set_default(&mut self) {
495 self.t = T::default();
496 }
497 }
498
499 impl<T, A> Align<T, A> {
500 pub(crate) const fn new(t: T) -> Align<T, A> {
501 Align { t, _a: [] }
502 }
503 }
504
505 /// A `T` which is guaranteed not to satisfy `align_of::<A>()`.
506 ///
507 /// It must be the case that `align_of::<T>() < align_of::<A>()` in order
508 /// fot this type to work properly.
509 #[repr(C)]
510 pub(crate) struct ForceUnalign<T: Unaligned, A> {
511 // The outer struct is aligned to `A`, and, thanks to `repr(C)`, `t` is
512 // placed at the minimum offset that guarantees its alignment. If
513 // `align_of::<T>() < align_of::<A>()`, then that offset will be
514 // guaranteed *not* to satisfy `align_of::<A>()`.
515 //
516 // Note that we need `T: Unaligned` in order to guarantee that there is
517 // no padding between `_u` and `t`.
518 _u: u8,
519 pub(crate) t: T,
520 _a: [A; 0],
521 }
522
523 impl<T: Unaligned, A> ForceUnalign<T, A> {
524 pub(crate) fn new(t: T) -> ForceUnalign<T, A> {
525 ForceUnalign { _u: 0, t, _a: [] }
526 }
527 }
528 // A `u64` with alignment 8.
529 //
530 // Though `u64` has alignment 8 on some platforms, it's not guaranteed. By
531 // contrast, `AU64` is guaranteed to have alignment 8 on all platforms.
532 #[derive(
533 KnownLayout,
534 Immutable,
535 FromBytes,
536 IntoBytes,
537 Eq,
538 PartialEq,
539 Ord,
540 PartialOrd,
541 Default,
542 Debug,
543 Copy,
544 Clone,
545 )]
546 #[repr(C, align(8))]
547 pub(crate) struct AU64(pub(crate) u64);
548
549 impl AU64 {
550 // Converts this `AU64` to bytes using this platform's endianness.
551 pub(crate) fn to_bytes(self) -> [u8; 8] {
552 crate::transmute!(self)
553 }
554 }
555
556 impl Display for AU64 {
557 #[cfg_attr(
558 all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
559 coverage(off)
560 )]
561 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
562 Display::fmt(&self.0, f)
563 }
564 }
565
566 #[derive(Immutable, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone)]
567 #[repr(C)]
568 pub(crate) struct Nested<T, U: ?Sized> {
569 _t: T,
570 _u: U,
571 }
572}
573
574#[cfg(test)]
575mod tests {
576 use super::*;
577
578 #[test]
579 fn test_round_down_to_next_multiple_of_alignment() {
580 fn alt_impl(n: usize, align: NonZeroUsize) -> usize {
581 let mul = n / align.get();
582 mul * align.get()
583 }
584
585 for align in [1, 2, 4, 8, 16] {
586 for n in 0..256 {
587 let align = NonZeroUsize::new(align).unwrap();
588 let want = alt_impl(n, align);
589 let got = round_down_to_next_multiple_of_alignment(n, align);
590 assert_eq!(got, want, "round_down_to_next_multiple_of_alignment({}, {})", n, align);
591 }
592 }
593 }
594
595 #[rustversion::since(1.57.0)]
596 #[test]
597 #[should_panic]
598 fn test_round_down_to_next_multiple_of_alignment_zerocopy_panic_in_const_and_vec_try_reserve() {
599 round_down_to_next_multiple_of_alignment(0, NonZeroUsize::new(3).unwrap());
600 }
601}