1 // SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT 2 // 3 // Copyright 2023 The Fuchsia Authors 4 // 5 // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0 6 // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT 7 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. 8 // This file may not be copied, modified, or distributed except according to 9 // those terms. 10 11 #[macro_use] 12 pub(crate) mod macros; 13 14 #[doc(hidden)] 15 pub mod macro_util; 16 17 use core::{ 18 marker::PhantomData, 19 mem::{self, ManuallyDrop}, 20 num::NonZeroUsize, 21 ptr::NonNull, 22 }; 23 24 use super::*; 25 use crate::pointer::{ 26 invariant::{Exclusive, Safe, Shared}, 27 SizeEq, TransmuteFromPtr, 28 }; 29 30 /// Like [`PhantomData`], but [`Send`] and [`Sync`] regardless of whether the 31 /// wrapped `T` is. 32 pub(crate) struct SendSyncPhantomData<T: ?Sized>(PhantomData<T>); 33 34 // SAFETY: `SendSyncPhantomData` does not enable any behavior which isn't sound 35 // to be called from multiple threads. 36 unsafe impl<T: ?Sized> Send for SendSyncPhantomData<T> {} 37 // SAFETY: `SendSyncPhantomData` does not enable any behavior which isn't sound 38 // to be called from multiple threads. 39 unsafe impl<T: ?Sized> Sync for SendSyncPhantomData<T> {} 40 41 impl<T: ?Sized> Default for SendSyncPhantomData<T> { 42 fn default() -> SendSyncPhantomData<T> { 43 SendSyncPhantomData(PhantomData) 44 } 45 } 46 47 impl<T: ?Sized> PartialEq for SendSyncPhantomData<T> { 48 fn eq(&self, _other: &Self) -> bool { 49 true 50 } 51 } 52 53 impl<T: ?Sized> Eq for SendSyncPhantomData<T> {} 54 55 impl<T: ?Sized> Clone for SendSyncPhantomData<T> { 56 fn clone(&self) -> Self { 57 SendSyncPhantomData(PhantomData) 58 } 59 } 60 61 #[cfg(miri)] 62 extern "Rust" { 63 /// Miri-provided intrinsic that marks the pointer `ptr` as aligned to 64 /// `align`. 65 /// 66 /// This intrinsic is used to inform Miri's symbolic alignment checker that 67 /// a pointer is aligned, even if Miri cannot statically deduce that fact. 68 /// This is often required when performing raw pointer arithmetic or casts 69 /// where the alignment is guaranteed by runtime checks or invariants that 70 /// Miri is not aware of. 71 pub(crate) fn miri_promise_symbolic_alignment(ptr: *const (), align: usize); 72 } 73 74 pub(crate) trait AsAddress { 75 fn addr(self) -> usize; 76 } 77 78 impl<T: ?Sized> AsAddress for &T { 79 #[inline(always)] 80 fn addr(self) -> usize { 81 let ptr: *const T = self; 82 AsAddress::addr(ptr) 83 } 84 } 85 86 impl<T: ?Sized> AsAddress for &mut T { 87 #[inline(always)] 88 fn addr(self) -> usize { 89 let ptr: *const T = self; 90 AsAddress::addr(ptr) 91 } 92 } 93 94 impl<T: ?Sized> AsAddress for NonNull<T> { 95 #[inline(always)] 96 fn addr(self) -> usize { 97 AsAddress::addr(self.as_ptr()) 98 } 99 } 100 101 impl<T: ?Sized> AsAddress for *const T { 102 #[inline(always)] 103 fn addr(self) -> usize { 104 // FIXME(#181), FIXME(https://github.com/rust-lang/rust/issues/95228): 105 // Use `.addr()` instead of `as usize` once it's stable, and get rid of 106 // this `allow`. Currently, `as usize` is the only way to accomplish 107 // this. 108 #[allow(clippy::as_conversions)] 109 #[cfg_attr( 110 __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, 111 allow(implicit_provenance_casts) 112 )] 113 return self.cast::<()>() as usize; 114 } 115 } 116 117 impl<T: ?Sized> AsAddress for *mut T { 118 #[inline(always)] 119 fn addr(self) -> usize { 120 let ptr: *const T = self; 121 AsAddress::addr(ptr) 122 } 123 } 124 125 /// Validates that `t` is aligned to `align_of::<U>()`. 126 #[inline(always)] 127 pub(crate) fn validate_aligned_to<T: AsAddress, U>(t: T) -> Result<(), AlignmentError<(), U>> { 128 // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in 129 // turn guarantees that this mod operation will not panic. 130 #[allow(clippy::arithmetic_side_effects)] 131 let remainder = t.addr() % mem::align_of::<U>(); 132 if remainder == 0 { 133 Ok(()) 134 } else { 135 // SAFETY: We just confirmed that `t.addr() % align_of::<U>() != 0`. 136 // That's only possible if `align_of::<U>() > 1`. 137 Err(unsafe { AlignmentError::new_unchecked(()) }) 138 } 139 } 140 141 /// Returns the bytes needed to pad `len` to the next multiple of `align`. 142 /// 143 /// This function assumes that align is a power of two; there are no guarantees 144 /// on the answer it gives if this is not the case. 145 #[cfg_attr( 146 kani, 147 kani::requires(align.is_power_of_two()), 148 // A power-of-two alignment divides the `usize` modulus, so wrapping 149 // preserves congruence even when the next aligned value exceeds `usize`. 150 kani::ensures(|&p| len.wrapping_add(p) % align.get() == 0), 151 // Ensures that we add the minimum required padding. 152 kani::ensures(|&p| p < align.get()), 153 )] 154 #[cfg_attr(not(zerocopy_inline_always), inline)] 155 #[cfg_attr(zerocopy_inline_always, inline(always))] 156 pub(crate) const fn padding_needed_for(len: usize, align: NonZeroUsize) -> usize { 157 #[cfg(kani)] 158 #[kani::proof_for_contract(padding_needed_for)] 159 fn proof() { 160 padding_needed_for(kani::any(), kani::any()); 161 } 162 163 // Abstractly, we want to compute: 164 // align - (len % align). 165 // Handling the case where len%align is 0. 166 // Because align is a power of two, len % align = len & (align-1). 167 // Guaranteed not to underflow as align is nonzero. 168 #[allow(clippy::arithmetic_side_effects)] 169 let mask = align.get() - 1; 170 171 // To efficiently subtract this value from align, we can use the bitwise 172 // complement. 173 // Note that ((!len) & (align-1)) gives us a number that with (len & 174 // (align-1)) sums to align-1. So subtracting 1 from x before taking the 175 // complement subtracts `len` from `align`. Some quick inspection of 176 // cases shows that this also handles the case where `len % align = 0` 177 // correctly too: len-1 % align then equals align-1, so the complement mod 178 // align will be 0, as desired. 179 // 180 // The following reasoning can be verified quickly by an SMT solver 181 // supporting the theory of bitvectors: 182 // ```smtlib 183 // ; Naive implementation of padding 184 // (define-fun padding1 ( 185 // (len (_ BitVec 32)) 186 // (align (_ BitVec 32))) (_ BitVec 32) 187 // (ite 188 // (= (_ bv0 32) (bvand len (bvsub align (_ bv1 32)))) 189 // (_ bv0 32) 190 // (bvsub align (bvand len (bvsub align (_ bv1 32)))))) 191 // 192 // ; The implementation below 193 // (define-fun padding2 ( 194 // (len (_ BitVec 32)) 195 // (align (_ BitVec 32))) (_ BitVec 32) 196 // (bvand (bvnot (bvsub len (_ bv1 32))) (bvsub align (_ bv1 32)))) 197 // 198 // (define-fun is-power-of-two ((x (_ BitVec 32))) Bool 199 // (= (_ bv0 32) (bvand x (bvsub x (_ bv1 32))))) 200 // 201 // (declare-const len (_ BitVec 32)) 202 // (declare-const align (_ BitVec 32)) 203 // ; Search for a case where align is a power of two and padding2 disagrees 204 // ; with padding1 205 // (assert (and (is-power-of-two align) 206 // (not (= (padding1 len align) (padding2 len align))))) 207 // (simplify (padding1 (_ bv300 32) (_ bv32 32))) ; 20 208 // (simplify (padding2 (_ bv300 32) (_ bv32 32))) ; 20 209 // (simplify (padding1 (_ bv322 32) (_ bv32 32))) ; 30 210 // (simplify (padding2 (_ bv322 32) (_ bv32 32))) ; 30 211 // (simplify (padding1 (_ bv8 32) (_ bv8 32))) ; 0 212 // (simplify (padding2 (_ bv8 32) (_ bv8 32))) ; 0 213 // (check-sat) ; unsat, also works for 64-bit bitvectors 214 // ``` 215 !(len.wrapping_sub(1)) & mask 216 } 217 218 /// Rounds `n` down to the largest value `m` such that `m <= n` and `m % align 219 /// == 0`. 220 /// 221 /// # Panics 222 /// 223 /// May panic if `align` is not a power of two. Even if it doesn't panic in this 224 /// case, it will produce nonsense results. 225 #[inline(always)] 226 #[cfg_attr( 227 kani, 228 kani::requires(align.is_power_of_two()), 229 kani::ensures(|&m| m <= n && m % align.get() == 0), 230 // Guarantees that `m` is the *largest* value such that `m % align == 0`. 231 kani::ensures(|&m| { 232 // If this `checked_add` fails, then the next multiple would wrap 233 // around, which trivially satisfies the "largest value" requirement. 234 m.checked_add(align.get()).map(|next_mul| next_mul > n).unwrap_or(true) 235 }) 236 )] 237 pub(crate) const fn round_down_to_next_multiple_of_alignment( 238 n: usize, 239 align: NonZeroUsize, 240 ) -> usize { 241 #[cfg(kani)] 242 #[kani::proof_for_contract(round_down_to_next_multiple_of_alignment)] 243 fn proof() { 244 round_down_to_next_multiple_of_alignment(kani::any(), kani::any()); 245 } 246 247 let align = align.get(); 248 #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 249 debug_assert!(align.is_power_of_two()); 250 251 // Subtraction can't underflow because `align.get() >= 1`. 252 #[allow(clippy::arithmetic_side_effects)] 253 let mask = !(align - 1); 254 n & mask 255 } 256 257 #[cfg_attr(not(zerocopy_inline_always), inline)] 258 #[cfg_attr(zerocopy_inline_always, inline(always))] 259 pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize { 260 if a.get() < b.get() { 261 b 262 } else { 263 a 264 } 265 } 266 267 #[cfg_attr(not(zerocopy_inline_always), inline)] 268 #[cfg_attr(zerocopy_inline_always, inline(always))] 269 pub(crate) const fn min(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize { 270 if a.get() > b.get() { 271 b 272 } else { 273 a 274 } 275 } 276 277 /// Copies `src` into the prefix of `dst`. 278 /// 279 /// # Safety 280 /// 281 /// The caller guarantees that `src.len() <= dst.len()`. 282 #[inline(always)] 283 pub(crate) unsafe fn copy_unchecked(src: &[u8], dst: &mut [u8]) { 284 debug_assert!(src.len() <= dst.len()); 285 // SAFETY: This invocation satisfies the safety contract of 286 // copy_nonoverlapping [1]: 287 // - `src.as_ptr()` is trivially valid for reads of `src.len()` bytes 288 // - `dst.as_ptr()` is valid for writes of `src.len()` bytes, because the 289 // caller has promised that `src.len() <= dst.len()` 290 // - `src` and `dst` are, trivially, properly aligned 291 // - the region of memory beginning at `src` with a size of `src.len()` 292 // bytes does not overlap with the region of memory beginning at `dst` 293 // with the same size, because `dst` is derived from an exclusive 294 // reference. 295 unsafe { 296 core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), src.len()); 297 }; 298 } 299 300 /// Unsafely transmutes the given `src` into a type `Dst`. 301 /// 302 /// # Safety 303 /// 304 /// The value `src` must be a valid instance of `Dst`. 305 #[inline(always)] 306 pub(crate) const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst { 307 static_assert!(Src, Dst => core::mem::size_of::<Src>() == core::mem::size_of::<Dst>()); 308 309 #[repr(C)] 310 union Transmute<Src, Dst> { 311 src: ManuallyDrop<Src>, 312 dst: ManuallyDrop<Dst>, 313 } 314 315 // SAFETY: Since `Transmute<Src, Dst>` is `#[repr(C)]`, its `src` and `dst` 316 // fields both start at the same offset and the types of those fields are 317 // transparent wrappers around `Src` and `Dst` [1]. Consequently, 318 // initializing `Transmute` with with `src` and then reading out `dst` is 319 // equivalent to transmuting from `Src` to `Dst` [2]. Transmuting from `src` 320 // to `Dst` is valid because — by contract on the caller — `src` is a valid 321 // instance of `Dst`. 322 // 323 // [1] Per https://doc.rust-lang.org/1.82.0/std/mem/struct.ManuallyDrop.html: 324 // 325 // `ManuallyDrop<T>` is guaranteed to have the same layout and bit 326 // validity as `T`, and is subject to the same layout optimizations as 327 // `T`. 328 // 329 // [2] Per https://doc.rust-lang.org/1.82.0/reference/items/unions.html#reading-and-writing-union-fields: 330 // 331 // Effectively, writing to and then reading from a union with the C 332 // representation is analogous to a transmute from the type used for 333 // writing to the type used for reading. 334 unsafe { ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst) } 335 } 336 337 /// # Safety 338 /// 339 /// `Src` must have a greater or equal alignment to `Dst`. 340 pub(crate) unsafe fn transmute_ref<Src, Dst, R>(src: &Src) -> &Dst 341 where 342 Src: ?Sized, 343 Dst: SizeEq<Src> 344 + TransmuteFromPtr<Src, Shared, Safe, Safe, <Dst as SizeEq<Src>>::CastFrom, R> 345 + ?Sized, 346 { 347 let dst = Ptr::from_ref(src).transmute(); 348 // SAFETY: The caller promises that `Src`'s alignment is at least as large 349 // as `Dst`'s alignment. 350 let dst = unsafe { dst.assume_alignment() }; 351 dst.as_ref() 352 } 353 354 /// # Safety 355 /// 356 /// `Src` must have a greater or equal alignment to `Dst`. 357 pub(crate) unsafe fn transmute_mut<Src, Dst, R>(src: &mut Src) -> &mut Dst 358 where 359 Src: ?Sized, 360 Dst: SizeEq<Src> 361 + TransmuteFromPtr<Src, Exclusive, Safe, Safe, <Dst as SizeEq<Src>>::CastFrom, R> 362 + ?Sized, 363 { 364 let dst = Ptr::from_mut(src).transmute(); 365 // SAFETY: The caller promises that `Src`'s alignment is at least as large 366 // as `Dst`'s alignment. 367 let dst = unsafe { dst.assume_alignment() }; 368 dst.as_mut() 369 } 370 371 /// Uses `allocate` to create a `Box<T>`. 372 /// 373 /// # Errors 374 /// 375 /// Returns an error on allocation failure. Allocation failure is guaranteed 376 /// never to cause a panic or an abort. 377 /// 378 /// # Safety 379 /// 380 /// `allocate` must be either `alloc::alloc::alloc` or 381 /// `alloc::alloc::alloc_zeroed`. The referent of the box returned by `new_box` 382 /// has the same bit-validity as the referent of the pointer returned by the 383 /// given `allocate` and sufficient size to store `T` with `meta`. 384 #[must_use = "has no side effects (other than allocation)"] 385 #[cfg(feature = "alloc")] 386 #[inline] 387 pub(crate) unsafe fn new_box<T>( 388 meta: T::PointerMetadata, 389 allocate: unsafe fn(core::alloc::Layout) -> *mut u8, 390 ) -> Result<alloc::boxed::Box<T>, AllocError> 391 where 392 T: ?Sized + crate::KnownLayout, 393 { 394 let align = T::LAYOUT.align.get(); 395 if !T::is_valid_metadata(meta) { 396 return Err(AllocError); 397 } 398 let size = match T::size_for_metadata(meta) { 399 Some(size) => size, 400 // Thanks to the `!T::is_valid_metadata(meta)` check 401 // above, this branch is unreachable. Fortunately, the 402 // optimizer recognizes this, so replacing this branch 403 // with `unreachable_unchecked` produces no codegen 404 // improvements. 405 None => return Err(AllocError), 406 }; 407 let ptr = if size != 0 { 408 // SAFETY: 409 // - `align` is derived from a `NonZeroUsize` and is thus non-zero. 410 // - `align` is a power of two because, by invariant on 411 // `KnownLayout::LAYOUT` `<T as KnownLayout>::LAYOUT` accurately 412 // reflects the layout of `T`. 413 // - `size`, by invariant on `size_for_metadata` is well-aligned for 414 // `align` and, by the check on `T::is_valid_metadata(meta)`, is less 415 // than `isize::MAX`. 416 let layout: Layout = unsafe { Layout::from_size_align_unchecked(size, align) }; 417 // SAFETY: By contract on the caller, `allocate` is either 418 // `alloc::alloc::alloc` or `alloc::alloc::alloc_zeroed`. The above 419 // check ensures their shared safety precondition: that the supplied 420 // layout is not zero-sized type [1]. 421 // 422 // [1] Per https://doc.rust-lang.org/1.81.0/std/alloc/trait.GlobalAlloc.html#tymethod.alloc: 423 // 424 // This function is unsafe because undefined behavior can result if 425 // the caller does not ensure that layout has non-zero size. 426 let ptr = unsafe { allocate(layout) }; 427 match NonNull::new(ptr) { 428 Some(ptr) => ptr, 429 None => return Err(AllocError), 430 } 431 } else { 432 // We use `transmute` instead of an `as` cast since Miri (with strict 433 // provenance enabled) notices and complains that an `as` cast creates a 434 // pointer with no provenance. Miri isn't smart enough to realize that 435 // we're only executing this branch when we're constructing a zero-sized 436 // `Box`, which doesn't require provenance. 437 // 438 // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`. All 439 // bits of a `usize` are initialized. 440 // 441 // `#[allow(unknown_lints)]` is for `integer_to_ptr_transmutes` 442 #[allow(unknown_lints)] 443 #[allow(clippy::useless_transmute, integer_to_ptr_transmutes)] 444 let dangling = unsafe { mem::transmute::<usize, *mut u8>(align) }; 445 // SAFETY: `dangling` is constructed from `align`, which is derived from 446 // a `NonZeroUsize`, which is guaranteed to be non-zero. 447 // 448 // `Box<[T]>` does not allocate when `T` is zero-sized or when `len` is 449 // zero, but it does require a non-null dangling pointer for its 450 // allocation. 451 // 452 // FIXME(https://github.com/rust-lang/rust/issues/95228): Use 453 // `std::ptr::without_provenance` once it's stable. That may optimize 454 // better. As written, Rust may assume that this consumes "exposed" 455 // provenance, and thus Rust may have to assume that this may consume 456 // provenance from any pointer whose provenance has been exposed. 457 unsafe { NonNull::new_unchecked(dangling) } 458 }; 459 460 let ptr = T::raw_from_ptr_len(ptr, meta); 461 462 // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. Make sure to 463 // include a justification that `ptr.as_ptr()` is validly-aligned in the ZST 464 // case (in which we manually construct a dangling pointer) and to justify 465 // why `Box` is safe to drop (it's because `allocate` uses the system 466 // allocator). 467 #[allow(clippy::undocumented_unsafe_blocks)] 468 Ok(unsafe { alloc::boxed::Box::from_raw(ptr.as_ptr()) }) 469 } 470 471 mod len_of { 472 use super::*; 473 474 /// A witness type for metadata of a valid instance of `&T`. 475 pub struct MetadataOf<T: ?Sized + KnownLayout> { 476 /// # Safety 477 /// 478 /// The size of an instance of `&T` with the given metadata is not 479 /// larger than `isize::MAX`. 480 meta: T::PointerMetadata, 481 _p: PhantomData<T>, 482 } 483 484 impl<T: ?Sized + KnownLayout> Copy for MetadataOf<T> {} 485 impl<T: ?Sized + KnownLayout> Clone for MetadataOf<T> { 486 #[inline] 487 fn clone(&self) -> Self { 488 *self 489 } 490 } 491 492 impl<T: ?Sized + KnownLayout> core::fmt::Debug for MetadataOf<T> 493 where 494 T::PointerMetadata: core::fmt::Debug, 495 { 496 #[inline] 497 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 498 f.debug_struct("MetadataOf").field("meta", &self.meta).finish() 499 } 500 } 501 502 impl<T: ?Sized> MetadataOf<T> 503 where 504 T: KnownLayout, 505 { 506 /// Returns `None` if `meta` is greater than `t`'s metadata. 507 #[inline(always)] 508 pub(crate) fn new_in_bounds(t: &T, meta: usize) -> Option<Self> 509 where 510 T: KnownLayout<PointerMetadata = usize>, 511 { 512 if meta <= Ptr::from_ref(t).len() { 513 // SAFETY: We have checked that `meta` is not greater than `t`'s 514 // metadata, which, by invariant on `&T`, addresses no more than 515 // `isize::MAX` bytes [1][2]. 516 // 517 // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety: 518 // 519 // For all types, `T: ?Sized`, and for all `t: &T` or `t: 520 // &mut T`, when such values cross an API boundary, the 521 // following invariants must generally be upheld: 522 // 523 // * `t` is non-null 524 // * `t` is aligned to `align_of_val(t)` 525 // * if `size_of_val(t) > 0`, then `t` is dereferenceable for 526 // `size_of_val(t)` many bytes 527 // 528 // If `t` points at address `a`, being "dereferenceable" for 529 // N bytes means that the memory range `[a, a + N)` is all 530 // contained within a single allocated object. 531 // 532 // [2] Per https://doc.rust-lang.org/1.85.0/std/ptr/index.html#allocated-object: 533 // 534 // For any allocated object with `base` address, `size`, and 535 // a set of `addresses`, the following are guaranteed: 536 // - For all addresses `a` in `addresses`, `a` is in the 537 // range `base .. (base + size)` (note that this requires 538 // `a < base + size`, not `a <= base + size`) 539 // - `base` is not equal to [`null()`] (i.e., the address 540 // with the numerical value 0) 541 // - `base + size <= usize::MAX` 542 // - `size <= isize::MAX` 543 Some(unsafe { Self::new_unchecked(meta) }) 544 } else { 545 None 546 } 547 } 548 549 /// # Safety 550 /// 551 /// The size of an instance of `&T` with the given metadata is not 552 /// larger than `isize::MAX`. 553 pub(crate) unsafe fn new_unchecked(meta: T::PointerMetadata) -> Self { 554 // SAFETY: The caller has promised that the size of an instance of 555 // `&T` with the given metadata is not larger than `isize::MAX`. 556 Self { meta, _p: PhantomData } 557 } 558 559 pub(crate) fn get(&self) -> T::PointerMetadata 560 where 561 T::PointerMetadata: Copy, 562 { 563 self.meta 564 } 565 566 #[inline(always)] 567 pub(crate) fn validate_cast_and_convert_metadata( 568 addr: usize, 569 bytes_len: MetadataOf<[u8]>, 570 cast_type: CastType, 571 meta: Option<T::PointerMetadata>, 572 ) -> Result<(MetadataOf<T>, MetadataOf<[u8]>), MetadataCastError> { 573 let layout = match meta { 574 None => T::LAYOUT, 575 // This can return `Err(MetadataCastError::Size)` if the 576 // metadata describes an object which can't fit in an `isize`. 577 Some(meta) => { 578 if !T::is_valid_metadata(meta) { 579 return Err(MetadataCastError::Size); 580 } 581 let size = match T::size_for_metadata(meta) { 582 Some(size) => size, 583 // Thanks to the `!T::is_valid_metadata(meta)` check 584 // above, this branch is unreachable. Fortunately, the 585 // optimizer recognizes this, so replacing this branch 586 // with `unreachable_unchecked` produces no codegen 587 // improvements. 588 None => return Err(MetadataCastError::Size), 589 }; 590 DstLayout { 591 align: T::LAYOUT.align, 592 size_info: crate::SizeInfo::Sized { size }, 593 statically_shallow_unpadded: false, 594 } 595 } 596 }; 597 // Lemma 0: By contract on `validate_cast_and_convert_metadata`, if 598 // the result is `Ok(..)`, then a `&T` with `elems` trailing slice 599 // elements is no larger in size than `bytes_len.get()`. 600 let (elems, split_at) = 601 layout.validate_cast_and_convert_metadata(addr, bytes_len.get(), cast_type)?; 602 let elems = T::PointerMetadata::from_elem_count(elems); 603 604 // For a slice DST type, if `meta` is `Some(elems)`, then we 605 // synthesize `layout` to describe a sized type whose size is equal 606 // to the size of the instance that we are asked to cast. For sized 607 // types, `validate_cast_and_convert_metadata` returns `elems == 0`. 608 // Thus, in this case, we need to use the `elems` passed by the 609 // caller, not the one returned by 610 // `validate_cast_and_convert_metadata`. 611 // 612 // Lemma 1: A `&T` with `elems` trailing slice elements is no larger 613 // in size than `bytes_len.get()`. Proof: 614 // - If `meta` is `None`, then `elems` satisfies this condition by 615 // Lemma 0. 616 // - If `meta` is `Some(meta)`, then `layout` describes an object 617 // whose size is equal to the size of an `&T` with `meta` 618 // metadata. By Lemma 0, that size is not larger than 619 // `bytes_len.get()`. 620 // 621 // Lemma 2: A `&T` with `elems` trailing slice elements is no larger 622 // than `isize::MAX` bytes. Proof: By Lemma 1, a `&T` with metadata 623 // `elems` is not larger in size than `bytes_len.get()`. By 624 // invariant on `MetadataOf<[u8]>`, a `&[u8]` with metadata 625 // `bytes_len` is not larger than `isize::MAX`. Because 626 // `size_of::<u8>()` is `1`, a `&[u8]` with metadata `bytes_len` has 627 // size `bytes_len.get()` bytes. Therefore, a `&T` with metadata 628 // `elems` has size not larger than `isize::MAX`. 629 let elems = meta.unwrap_or(elems); 630 631 // SAFETY: See Lemma 2. 632 let elems = unsafe { MetadataOf::new_unchecked(elems) }; 633 634 // SAFETY: Let `size` be the size of a `&T` with metadata `elems`. 635 // By post-condition on `validate_cast_and_convert_metadata`, one of 636 // the following conditions holds: 637 // - `split_at == size`, in which case, by Lemma 2, `split_at <= 638 // isize::MAX`. Since `size_of::<u8>() == 1`, a `[u8]` with 639 // `split_at` elems has size not larger than `isize::MAX`. 640 // - `split_at == bytes_len - size`. Since `bytes_len: 641 // MetadataOf<u8>`, and since `size` is non-negative, `split_at` 642 // addresses no more bytes than `bytes_len` does. Since 643 // `bytes_len: MetadataOf<u8>`, `bytes_len` describes a `[u8]` 644 // which has no more than `isize::MAX` bytes, and thus so does 645 // `split_at`. 646 let split_at = unsafe { MetadataOf::<[u8]>::new_unchecked(split_at) }; 647 Ok((elems, split_at)) 648 } 649 } 650 } 651 652 pub use len_of::MetadataOf; 653 654 /// Since we support multiple versions of Rust, there are often features which 655 /// have been stabilized in the most recent stable release which do not yet 656 /// exist (stably) on our MSRV. This module provides polyfills for those 657 /// features so that we can write more "modern" code, and just remove the 658 /// polyfill once our MSRV supports the corresponding feature. Without this, 659 /// we'd have to write worse/more verbose code and leave FIXME comments 660 /// sprinkled throughout the codebase to update to the new pattern once it's 661 /// stabilized. 662 /// 663 /// Each trait is imported as `_` at the crate root; each polyfill should "just 664 /// work" at usage sites. 665 pub(crate) mod polyfills { 666 use core::ptr::{self, NonNull}; 667 668 // A polyfill for `NonNull::slice_from_raw_parts` that we can use before our 669 // MSRV is 1.70, when that function was stabilized. 670 // 671 // The `#[allow(unused)]` is necessary because, on sufficiently recent 672 // toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent 673 // method rather than to this trait, and so this trait is considered unused. 674 // 675 // FIXME(#67): Once our MSRV is 1.70, remove this. 676 #[allow(unused)] 677 pub(crate) trait NonNullExt<T> { 678 fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]>; 679 } 680 681 impl<T> NonNullExt<T> for NonNull<T> { 682 // NOTE on coverage: this will never be tested in nightly since it's a 683 // polyfill for a feature which has been stabilized on our nightly 684 // toolchain. 685 #[cfg_attr( 686 all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), 687 coverage(off) 688 )] 689 #[inline(always)] 690 fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]> { 691 let ptr = ptr::slice_from_raw_parts_mut(data.as_ptr(), len); 692 // SAFETY: `ptr` is converted from `data`, which is non-null. 693 unsafe { NonNull::new_unchecked(ptr) } 694 } 695 } 696 697 // A polyfill for `Self::unchecked_sub` that we can use until methods like 698 // `usize::unchecked_sub` is stabilized. 699 // 700 // The `#[allow(unused)]` is necessary because, on sufficiently recent 701 // toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent 702 // method rather than to this trait, and so this trait is considered unused. 703 // 704 // FIXME(#67): Once our MSRV is high enough, remove this. 705 #[allow(unused)] 706 pub(crate) trait NumExt { 707 /// Add without checking for overflow. 708 /// 709 /// # Safety 710 /// 711 /// The caller promises that the addition will not overflow. 712 unsafe fn unchecked_add(self, rhs: Self) -> Self; 713 714 /// Subtract without checking for underflow. 715 /// 716 /// # Safety 717 /// 718 /// The caller promises that the subtraction will not underflow. 719 unsafe fn unchecked_sub(self, rhs: Self) -> Self; 720 721 /// Multiply without checking for overflow. 722 /// 723 /// # Safety 724 /// 725 /// The caller promises that the multiplication will not overflow. 726 unsafe fn unchecked_mul(self, rhs: Self) -> Self; 727 } 728 729 // NOTE on coverage: these will never be tested in nightly since they're 730 // polyfills for a feature which has been stabilized on our nightly 731 // toolchain. 732 impl NumExt for usize { 733 #[cfg_attr( 734 all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), 735 coverage(off) 736 )] 737 #[inline(always)] 738 unsafe fn unchecked_add(self, rhs: usize) -> usize { 739 match self.checked_add(rhs) { 740 Some(x) => x, 741 None => { 742 // SAFETY: The caller promises that the addition will not 743 // underflow. 744 unsafe { core::hint::unreachable_unchecked() } 745 } 746 } 747 } 748 749 #[cfg_attr( 750 all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), 751 coverage(off) 752 )] 753 #[inline(always)] 754 unsafe fn unchecked_sub(self, rhs: usize) -> usize { 755 match self.checked_sub(rhs) { 756 Some(x) => x, 757 None => { 758 // SAFETY: The caller promises that the subtraction will not 759 // underflow. 760 unsafe { core::hint::unreachable_unchecked() } 761 } 762 } 763 } 764 765 #[cfg_attr( 766 all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), 767 coverage(off) 768 )] 769 #[inline(always)] 770 unsafe fn unchecked_mul(self, rhs: usize) -> usize { 771 match self.checked_mul(rhs) { 772 Some(x) => x, 773 None => { 774 // SAFETY: The caller promises that the multiplication will 775 // not overflow. 776 unsafe { core::hint::unreachable_unchecked() } 777 } 778 } 779 } 780 } 781 } 782 783 #[cfg(test)] 784 pub(crate) mod testutil { 785 use crate::*; 786 787 /// A `T` which is aligned to at least `align_of::<A>()`. 788 #[derive(Default)] 789 pub(crate) struct Align<T, A> { 790 pub(crate) t: T, 791 _a: [A; 0], 792 } 793 794 impl<T: Default, A> Align<T, A> { 795 pub(crate) fn set_default(&mut self) { 796 self.t = T::default(); 797 } 798 } 799 800 impl<T, A> Align<T, A> { 801 pub(crate) const fn new(t: T) -> Align<T, A> { 802 Align { t, _a: [] } 803 } 804 } 805 806 /// A `T` which is guaranteed not to satisfy `align_of::<A>()`. 807 /// 808 /// It must be the case that `align_of::<T>() < align_of::<A>()` in order 809 /// for this type to work properly. 810 #[repr(C)] 811 pub(crate) struct ForceUnalign<T: Unaligned, A> { 812 // The outer struct is aligned to `A`, and, thanks to `repr(C)`, `t` is 813 // placed at the minimum offset that guarantees its alignment. If 814 // `align_of::<T>() < align_of::<A>()`, then that offset will be 815 // guaranteed *not* to satisfy `align_of::<A>()`. 816 // 817 // Note that we need `T: Unaligned` in order to guarantee that there is 818 // no padding between `_u` and `t`. 819 _u: u8, 820 pub(crate) t: T, 821 _a: [A; 0], 822 } 823 824 impl<T: Unaligned, A> ForceUnalign<T, A> { 825 pub(crate) fn new(t: T) -> ForceUnalign<T, A> { 826 ForceUnalign { _u: 0, t, _a: [] } 827 } 828 } 829 // A `u64` with alignment 8. 830 // 831 // Though `u64` has alignment 8 on some platforms, it's not guaranteed. By 832 // contrast, `AU64` is guaranteed to have alignment 8 on all platforms. 833 #[derive( 834 KnownLayout, 835 Immutable, 836 FromBytes, 837 IntoBytes, 838 Eq, 839 PartialEq, 840 Ord, 841 PartialOrd, 842 Default, 843 Debug, 844 Copy, 845 Clone, 846 )] 847 #[repr(C, align(8))] 848 pub(crate) struct AU64(pub(crate) u64); 849 850 impl AU64 { 851 // Converts this `AU64` to bytes using this platform's endianness. 852 pub(crate) fn to_bytes(self) -> [u8; 8] { 853 crate::transmute!(self) 854 } 855 } 856 857 impl Display for AU64 { 858 #[cfg_attr( 859 all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), 860 coverage(off) 861 )] 862 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 863 Display::fmt(&self.0, f) 864 } 865 } 866 } 867 868 #[cfg(test)] 869 mod tests { 870 use super::*; 871 872 #[test] 873 fn test_round_down_to_next_multiple_of_alignment() { 874 // Division by `NonZeroUsize` unsupported on our MSRV. 875 #[allow(clippy::needless_nonzero_get)] 876 fn alt_impl(n: usize, align: NonZeroUsize) -> usize { 877 let mul = n / align.get(); 878 mul * align.get() 879 } 880 881 for align in [1, 2, 4, 8, 16] { 882 for n in 0..256 { 883 let align = NonZeroUsize::new(align).unwrap(); 884 let want = alt_impl(n, align); 885 let got = round_down_to_next_multiple_of_alignment(n, align); 886 assert_eq!(got, want, "round_down_to_next_multiple_of_alignment({}, {})", n, align); 887 } 888 } 889 } 890 891 #[rustversion::since(1.57.0)] 892 #[test] 893 #[should_panic] 894 fn test_round_down_to_next_multiple_of_alignment_zerocopy_panic_in_const_and_vec_try_reserve() { 895 round_down_to_next_multiple_of_alignment(0, NonZeroUsize::new(3).unwrap()); 896 } 897 #[test] 898 fn test_send_sync_phantom_data() { 899 let x = SendSyncPhantomData::<u8>::default(); 900 let y = x.clone(); 901 assert!(x == y); 902 assert!(x == SendSyncPhantomData::<u8>::default()); 903 } 904 905 #[test] 906 #[allow(clippy::as_conversions)] 907 fn test_as_address() { 908 let x = 0u8; 909 let r = &x; 910 let mut x_mut = 0u8; 911 let rm = &mut x_mut; 912 let p = r as *const u8; 913 let pm = rm as *mut u8; 914 let nn = NonNull::new(p as *mut u8).unwrap(); 915 916 assert_eq!(AsAddress::addr(r), p as usize); 917 assert_eq!(AsAddress::addr(rm), pm as usize); 918 assert_eq!(AsAddress::addr(p), p as usize); 919 assert_eq!(AsAddress::addr(pm), pm as usize); 920 assert_eq!(AsAddress::addr(nn), p as usize); 921 } 922 } 923