1 // SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT 2 // 3 // Copyright 2024 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 use core::{marker::PhantomData, ops::Range, ptr::NonNull}; 12 13 pub use _def::PtrInner; 14 15 #[allow(unused_imports)] 16 use crate::util::polyfills::NumExt as _; 17 use crate::{ 18 layout::{CastType, MetadataCastError}, 19 pointer::cast, 20 util::AsAddress, 21 AlignmentError, CastError, KnownLayout, MetadataOf, SizeError, SplitAt, 22 }; 23 24 mod _def { 25 use super::*; 26 /// The inner pointer stored inside a [`Ptr`][crate::Ptr]. 27 /// 28 /// `PtrInner<'a, T>` is [covariant] in `'a` and invariant in `T`. 29 /// 30 /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html 31 #[allow(missing_debug_implementations)] 32 pub struct PtrInner<'a, T> 33 where 34 T: ?Sized, 35 { 36 /// # Invariants 37 /// 38 /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid 39 /// provenance for its referent, which is entirely contained in some 40 /// Rust allocation, `A`. 41 /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live 42 /// for at least `'a`. 43 /// 44 /// # Postconditions 45 /// 46 /// By virtue of these invariants, code may assume the following, which 47 /// are logical implications of the invariants: 48 /// - `ptr`'s referent is not larger than `isize::MAX` bytes \[1\] 49 /// - `ptr`'s referent does not wrap around the address space \[1\] 50 /// 51 /// \[1\] Per <https://doc.rust-lang.org/1.85.0/std/ptr/index.html#allocated-object>: 52 /// 53 /// For any allocated object with `base` address, `size`, and a set of 54 /// `addresses`, the following are guaranteed: 55 /// ... 56 /// - `size <= isize::MAX` 57 /// 58 /// As a consequence of these guarantees, given any address `a` within 59 /// the set of addresses of an allocated object: 60 /// ... 61 /// - It is guaranteed that, given `o = a - base` (i.e., the offset of 62 /// `a` within the allocated object), `base + o` will not wrap 63 /// around the address space (in other words, will not overflow 64 /// `usize`) 65 ptr: NonNull<T>, 66 // SAFETY: `&'a UnsafeCell<T>` is covariant in `'a` and invariant in `T` 67 // [1]. We use this construction rather than the equivalent `&mut T`, 68 // because our MSRV of 1.65 prohibits `&mut` types in const contexts. 69 // 70 // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance 71 _marker: PhantomData<&'a core::cell::UnsafeCell<T>>, 72 } 73 74 impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {} 75 impl<'a, T: 'a + ?Sized> Clone for PtrInner<'a, T> { 76 #[inline(always)] 77 fn clone(&self) -> PtrInner<'a, T> { 78 // SAFETY: None of the invariants on `ptr` are affected by having 79 // multiple copies of a `PtrInner`. 80 *self 81 } 82 } 83 84 impl<'a, T: 'a + ?Sized> PtrInner<'a, T> { 85 /// Constructs a `Ptr` from a [`NonNull`]. 86 /// 87 /// # Safety 88 /// 89 /// The caller promises that: 90 /// 91 /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid 92 /// provenance for its referent, which is entirely contained in some 93 /// Rust allocation, `A`. 94 /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live 95 /// for at least `'a`. 96 #[inline(always)] 97 #[must_use] 98 pub const unsafe fn new(ptr: NonNull<T>) -> PtrInner<'a, T> { 99 // SAFETY: The caller has promised to satisfy all safety invariants 100 // of `PtrInner`. 101 Self { ptr, _marker: PhantomData } 102 } 103 104 /// Converts this `PtrInner<T>` to a [`NonNull<T>`]. 105 /// 106 /// Note that this method does not consume `self`. The caller should 107 /// watch out for `unsafe` code which uses the returned `NonNull` in a 108 /// way that violates the safety invariants of `self`. 109 #[inline(always)] 110 #[must_use] 111 pub const fn as_non_null(&self) -> NonNull<T> { 112 self.ptr 113 } 114 115 /// Converts this `PtrInner<T>` to a [`*mut T`]. 116 /// 117 /// Note that this method does not consume `self`. The caller should 118 /// watch out for `unsafe` code which uses the returned `*mut T` in a 119 /// way that violates the safety invariants of `self`. 120 #[inline(always)] 121 #[must_use] 122 pub const fn as_ptr(&self) -> *mut T { 123 self.ptr.as_ptr() 124 } 125 } 126 } 127 128 impl<'a, T: ?Sized> PtrInner<'a, T> { 129 /// Constructs a `PtrInner` from a reference. 130 #[inline] 131 pub fn from_ref(ptr: &'a T) -> Self { 132 let ptr = NonNull::from(ptr); 133 // SAFETY: 134 // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on 135 // `&'a T` [1], has valid provenance for its referent, which is 136 // entirely contained in some Rust allocation, `A`. 137 // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on 138 // `&'a T`, is guaranteed to live for at least `'a`. 139 // 140 // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety: 141 // 142 // For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, 143 // when such values cross an API boundary, the following invariants 144 // must generally be upheld: 145 // ... 146 // - if `size_of_val(t) > 0`, then `t` is dereferenceable for 147 // `size_of_val(t)` many bytes 148 // 149 // If `t` points at address `a`, being “dereferenceable” for N bytes 150 // means that the memory range `[a, a + N)` is all contained within a 151 // single allocated object. 152 unsafe { Self::new(ptr) } 153 } 154 155 /// Constructs a `PtrInner` from a mutable reference. 156 #[inline] 157 pub fn from_mut(ptr: &'a mut T) -> Self { 158 let ptr = NonNull::from(ptr); 159 // SAFETY: 160 // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on 161 // `&'a mut T` [1], has valid provenance for its referent, which is 162 // entirely contained in some Rust allocation, `A`. 163 // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on 164 // `&'a mut T`, is guaranteed to live for at least `'a`. 165 // 166 // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety: 167 // 168 // For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, 169 // when such values cross an API boundary, the following invariants 170 // must generally be upheld: 171 // ... 172 // - if `size_of_val(t) > 0`, then `t` is dereferenceable for 173 // `size_of_val(t)` many bytes 174 // 175 // If `t` points at address `a`, being “dereferenceable” for N bytes 176 // means that the memory range `[a, a + N)` is all contained within a 177 // single allocated object. 178 unsafe { Self::new(ptr) } 179 } 180 181 /// # Safety 182 /// 183 /// The caller may assume that the resulting `PtrInner` addresses the subset 184 /// of the bytes of `self`'s referent addressed by `C::project(self)`. 185 #[must_use] 186 #[inline(always)] 187 pub fn project<U: ?Sized, C: cast::Project<T, U>>(self) -> PtrInner<'a, U> { 188 let projected_raw = C::project(self); 189 190 // SAFETY: `self`'s referent lives at a `NonNull` address, and is either 191 // zero-sized or lives in an allocation. In either case, it does not 192 // wrap around the address space [1], and so none of the addresses 193 // contained in it or one-past-the-end of it are null. 194 // 195 // By invariant on `C: Project`, `C::project` is a provenance-preserving 196 // projection which preserves or shrinks the set of referent bytes, so 197 // `projected_raw` references a subset of `self`'s referent, and so it 198 // cannot be null. 199 // 200 // [1] https://doc.rust-lang.org/1.92.0/std/ptr/index.html#allocation 201 let projected_non_null = unsafe { NonNull::new_unchecked(projected_raw) }; 202 203 // SAFETY: As described in the preceding safety comment, `projected_raw`, 204 // and thus `projected_non_null`, addresses a subset of `self`'s 205 // referent. Thus, `projected_non_null` either: 206 // - Addresses zero bytes or, 207 // - Addresses a subset of the referent of `self`. In this case, `self` 208 // has provenance for its referent, which lives in an allocation. 209 // Since `projected_non_null` was constructed using a sequence of 210 // provenance-preserving operations, it also has provenance for its 211 // referent and that referent lives in an allocation. By invariant on 212 // `self`, that allocation lives for `'a`. 213 unsafe { PtrInner::new(projected_non_null) } 214 } 215 } 216 217 #[allow(clippy::needless_lifetimes)] 218 impl<'a, T> PtrInner<'a, T> 219 where 220 T: ?Sized + KnownLayout, 221 { 222 /// Extracts the metadata of this `ptr`. 223 #[inline] 224 #[must_use] 225 pub fn meta(self) -> MetadataOf<T> { 226 let meta = T::pointer_to_metadata(self.as_ptr()); 227 // SAFETY: By invariant on `PtrInner`, `self.as_non_null()` addresses no 228 // more than `isize::MAX` bytes. 229 unsafe { MetadataOf::new_unchecked(meta) } 230 } 231 232 /// Produces a `PtrInner` with the same address and provenance as `self` but 233 /// the given `meta`. 234 /// 235 /// # Safety 236 /// 237 /// The caller promises that if `self`'s referent is not zero sized, then 238 /// a pointer constructed from its address with the given `meta` metadata 239 /// will address a subset of the allocation pointed to by `self`. 240 #[inline] 241 #[must_use] 242 pub unsafe fn with_meta(self, meta: T::PointerMetadata) -> Self 243 where 244 T: KnownLayout, 245 { 246 let raw = T::raw_from_ptr_len(self.as_non_null().cast(), meta); 247 248 // SAFETY: 249 // 250 // Lemma 0: `raw` either addresses zero bytes, or addresses a subset of 251 // the allocation pointed to by `self` and has the same 252 // provenance as `self`. Proof: `raw` is constructed using 253 // provenance-preserving operations, and the caller has 254 // promised that, if `self`'s referent is not zero-sized, the 255 // resulting pointer addresses a subset of the allocation 256 // pointed to by `self`. 257 // 258 // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not 259 // zero sized, then `ptr` is derived from some valid Rust allocation, 260 // `A`. 261 // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not 262 // zero sized, then `ptr` has valid provenance for `A`. 263 // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not 264 // zero sized, then `ptr` addresses a byte range which is entirely 265 // contained in `A`. 266 // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte 267 // range whose length fits in an `isize`. 268 // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte 269 // range which does not wrap around the address space. 270 // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not 271 // zero sized, then `A` is guaranteed to live for at least `'a`. 272 unsafe { PtrInner::new(raw) } 273 } 274 } 275 276 #[allow(clippy::needless_lifetimes)] 277 impl<'a, T> PtrInner<'a, T> 278 where 279 T: ?Sized + KnownLayout<PointerMetadata = usize>, 280 { 281 /// Splits `T` in two. 282 /// 283 /// # Safety 284 /// 285 /// The caller promises that: 286 /// - `l_len.get() <= self.meta()`. 287 /// 288 /// ## (Non-)Overlap 289 /// 290 /// Given `let (left, right) = ptr.split_at(l_len)`, it is guaranteed that 291 /// `left` and `right` are contiguous and non-overlapping if 292 /// the left part has no trailing padding. This is true for all `[T]`. 293 /// 294 /// Any trailing padding in the left part begins at the right part's 295 /// starting address and may overlap its referent. 296 #[inline] 297 #[must_use] 298 pub unsafe fn split_at_unchecked( 299 self, 300 l_len: crate::util::MetadataOf<T>, 301 ) -> (Self, PtrInner<'a, [T::Elem]>) 302 where 303 T: SplitAt, 304 { 305 let l_len = l_len.get(); 306 307 // SAFETY: The caller promises that `l_len.get() <= self.meta()`. 308 // Trivially, `0 <= l_len`. 309 let left = unsafe { self.with_meta(l_len) }; 310 311 let right = self.trailing_slice(); 312 // SAFETY: The caller promises that `l_len <= self.meta() = slf.meta()`. 313 // Trivially, `slf.meta() <= slf.meta()`. 314 let right = unsafe { right.slice_unchecked(l_len..self.meta().get()) }; 315 316 // SAFETY: If the left part has no trailing padding, then `left` and 317 // `right` are non-overlapping. Proof: `left` has `l_len` trailing 318 // elements, and `right` starts at element `l_len` of the original 319 // trailing slice. Without padding after `left`'s final element, no 320 // byte is referred to by both pointers. 321 // 322 // Any trailing padding in `left` begins at `right`'s starting 323 // address. If `right` is nonzero sized, the referents overlap. 324 (left, right) 325 } 326 327 /// Produces the trailing slice of `self` using `T::Elem` as its element 328 /// representation. 329 #[inline] 330 #[must_use] 331 pub fn trailing_slice(self) -> PtrInner<'a, [T::Elem]> 332 where 333 T: SplitAt, 334 { 335 let offset = crate::trailing_slice_layout::<T>().offset; 336 337 let bytes = self.as_non_null().cast::<u8>().as_ptr(); 338 339 // SAFETY: 340 // - By invariant on `T: KnownLayout`, `T::LAYOUT` describes `T`'s 341 // layout. `offset` is the offset of the trailing slice within `T`, 342 // which is by definition in-bounds or one byte past the end of any 343 // `T`, regardless of metadata. By invariant on `PtrInner`, `self` 344 // (and thus `bytes`) points to a byte range of size `<= isize::MAX`, 345 // and so `offset <= isize::MAX`. Since `size_of::<u8>() == 1`, 346 // `offset * size_of::<u8>() <= isize::MAX`. 347 // - If `offset > 0`, then by invariant on `PtrInner`, `self` (and thus 348 // `bytes`) points to a byte range entirely contained within the same 349 // allocated object as `self`. As explained above, this offset results 350 // in a pointer to or one byte past the end of this allocated object. 351 let bytes = unsafe { bytes.add(offset) }; 352 353 // SAFETY: By the preceding safety argument, `bytes` is within or one 354 // byte past the end of the same allocated object as `self`, which 355 // ensures that it is non-null. 356 let bytes = unsafe { NonNull::new_unchecked(bytes) }; 357 358 let ptr = KnownLayout::raw_from_ptr_len(bytes, self.meta().get()); 359 360 // SAFETY: 361 // 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from 362 // some valid Rust allocation, `A`, because `ptr` is derived from 363 // the same allocated object as `self`. 364 // 1. If `ptr`'s referent is not zero sized, then `ptr` has valid 365 // provenance for `A` because `raw` is derived from the same 366 // allocated object as `self` via provenance-preserving operations. 367 // 2. `T: SplitAt` guarantees that `T::Elem` has the size of the actual 368 // trailing element. The new slice has the same length and start as 369 // the original trailing slice, so it covers the same byte range. 370 // If nonzero sized, that range is entirely contained in `A`. 371 // 3. `ptr` addresses a byte range whose length fits in an `isize`, by 372 // consequence of #2. 373 // 4. `ptr` addresses a byte range which does not wrap around the 374 // address space, by consequence of #2. 375 // 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to 376 // live for at least `'a`, because `ptr` is derived from `self`. 377 unsafe { PtrInner::new(ptr) } 378 } 379 } 380 381 #[allow(clippy::needless_lifetimes)] 382 impl<'a, T> PtrInner<'a, [T]> { 383 /// Creates a pointer which addresses the given `range` of self. 384 /// 385 /// # Safety 386 /// 387 /// `range` is a valid range (`start <= end`) and `end <= self.meta()`. 388 #[inline] 389 #[must_use] 390 pub unsafe fn slice_unchecked(self, range: Range<usize>) -> Self { 391 let base = self.as_non_null().cast::<T>().as_ptr(); 392 393 // SAFETY: The caller promises that `start <= end <= self.meta()`. By 394 // invariant, if `self`'s referent is not zero-sized, then `self` refers 395 // to a byte range which is contained within a single allocation, which 396 // is no more than `isize::MAX` bytes long, and which does not wrap 397 // around the address space. Thus, this pointer arithmetic remains 398 // in-bounds of the same allocation, and does not wrap around the 399 // address space. The offset (in bytes) does not overflow `isize`. 400 // 401 // If `self`'s referent is zero-sized, then these conditions are 402 // trivially satisfied. 403 let base = unsafe { base.add(range.start) }; 404 405 // SAFETY: The caller promises that `start <= end`, and so this will not 406 // underflow. 407 #[allow(unstable_name_collisions)] 408 let len = unsafe { range.end.unchecked_sub(range.start) }; 409 410 let ptr = core::ptr::slice_from_raw_parts_mut(base, len); 411 412 // SAFETY: By invariant, `self`'s referent is either a ZST or lives 413 // entirely in an allocation. `ptr` points inside of or one byte past 414 // the end of that referent. Thus, in either case, `ptr` is non-null. 415 let ptr = unsafe { NonNull::new_unchecked(ptr) }; 416 417 // SAFETY: 418 // 419 // Lemma 0: `ptr` addresses a subset of the bytes addressed by `self`, 420 // and has the same provenance. Proof: The caller guarantees 421 // that `start <= end <= self.meta()`. Thus, `base` is 422 // in-bounds of `self`, and `base + (end - start)` is also 423 // in-bounds of self. Finally, `ptr` is constructed using 424 // provenance-preserving operations. 425 // 426 // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not 427 // zero sized, then `ptr` has valid provenance for its referent, 428 // which is entirely contained in some Rust allocation, `A`. 429 // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not 430 // zero sized, then `A` is guaranteed to live for at least `'a`. 431 unsafe { PtrInner::new(ptr) } 432 } 433 434 /// Iteratively projects the elements `PtrInner<T>` from `PtrInner<[T]>`. 435 #[inline] 436 pub fn iter(&self) -> impl Iterator<Item = PtrInner<'a, T>> { 437 // FIXME(#429): Once `NonNull::cast` documents that it preserves 438 // provenance, cite those docs. 439 let base = self.as_non_null().cast::<T>().as_ptr(); 440 (0..self.meta().get()).map(move |i| { 441 // FIXME(https://github.com/rust-lang/rust/issues/74265): Use 442 // `NonNull::get_unchecked_mut`. 443 444 // SAFETY: If the following conditions are not satisfied 445 // `pointer::cast` may induce Undefined Behavior [1]: 446 // 447 // > - The computed offset, `count * size_of::<T>()` bytes, must not 448 // > overflow `isize``. 449 // > - If the computed offset is non-zero, then `self` must be 450 // > derived from a pointer to some allocated object, and the 451 // > entire memory range between `self` and the result must be in 452 // > bounds of that allocated object. In particular, this range 453 // > must not “wrap around” the edge of the address space. 454 // 455 // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add 456 // 457 // We satisfy both of these conditions here: 458 // - By invariant on `Ptr`, `self` addresses a byte range whose 459 // length fits in an `isize`. Since `elem` is contained in `self`, 460 // the computed offset of `elem` must fit within `isize.` 461 // - If the computed offset is non-zero, then this means that the 462 // referent is not zero-sized. In this case, `base` points to an 463 // allocated object (by invariant on `self`). Thus: 464 // - By contract, `self.meta()` accurately reflects the number of 465 // elements in the slice. `i` is in bounds of `c.meta()` by 466 // construction, and so the result of this addition cannot 467 // overflow past the end of the allocation referred to by `c`. 468 // - By invariant on `Ptr`, `self` addresses a byte range which 469 // does not wrap around the address space. Since `elem` is 470 // contained in `self`, the computed offset of `elem` must wrap 471 // around the address space. 472 // 473 // FIXME(#429): Once `pointer::add` documents that it preserves 474 // provenance, cite those docs. 475 let elem = unsafe { base.add(i) }; 476 477 // SAFETY: `elem` must not be null. `base` is constructed from a 478 // `NonNull` pointer, and the addition that produces `elem` must not 479 // overflow or wrap around, so `elem >= base > 0`. 480 // 481 // FIXME(#429): Once `NonNull::new_unchecked` documents that it 482 // preserves provenance, cite those docs. 483 let elem = unsafe { NonNull::new_unchecked(elem) }; 484 485 // SAFETY: The safety invariants of `Ptr::new` (see definition) are 486 // satisfied: 487 // 0. If `elem`'s referent is not zero sized, then `elem` has valid 488 // provenance for its referent, because it derived from `self` 489 // using a series of provenance-preserving operations, and 490 // because `self` has valid provenance for its referent. By the 491 // same argument, `elem`'s referent is entirely contained within 492 // the same allocated object as `self`'s referent. 493 // 1. If `elem`'s referent is not zero sized, then the allocation of 494 // `elem` is guaranteed to live for at least `'a`, because `elem` 495 // is entirely contained in `self`, which lives for at least `'a` 496 // by invariant on `Ptr`. 497 unsafe { PtrInner::new(elem) } 498 }) 499 } 500 } 501 502 impl<'a, T, const N: usize> PtrInner<'a, [T; N]> { 503 /// Casts this pointer-to-array into a slice. 504 /// 505 /// # Safety 506 /// 507 /// Callers may assume that the returned `PtrInner` references the same 508 /// address and length as `self`. 509 #[allow(clippy::wrong_self_convention)] 510 #[inline] 511 #[must_use] 512 pub fn as_slice(self) -> PtrInner<'a, [T]> { 513 let start = self.as_non_null().cast::<T>().as_ptr(); 514 let slice = core::ptr::slice_from_raw_parts_mut(start, N); 515 // SAFETY: `slice` is not null, because it is derived from `start` 516 // which is non-null. 517 let slice = unsafe { NonNull::new_unchecked(slice) }; 518 // SAFETY: Lemma: In the following safety arguments, note that `slice` 519 // is derived from `self` in two steps: first, by casting `self: [T; N]` 520 // to `start: T`, then by constructing a pointer to a slice starting at 521 // `start` of length `N`. As a result, `slice` references exactly the 522 // same allocation as `self`, if any. 523 // 524 // 0. By the above lemma, if `slice`'s referent is not zero sized, then 525 // `slice` has the same referent as `self`. By invariant on `self`, 526 // this referent is entirely contained within some allocation, `A`. 527 // Because `slice` was constructed using provenance-preserving 528 // operations, it has provenance for its entire referent. 529 // 1. By the above lemma, if `slice`'s referent is not zero sized, then 530 // `A` is guaranteed to live for at least `'a`, because it is derived 531 // from the same allocation as `self`, which, by invariant on 532 // `PtrInner`, lives for at least `'a`. 533 unsafe { PtrInner::new(slice) } 534 } 535 } 536 537 impl<'a> PtrInner<'a, [u8]> { 538 /// Attempts to cast `self` to a `U` using the given cast type. 539 /// 540 /// If `U` is a slice DST and pointer metadata (`meta`) is provided, then 541 /// the cast will only succeed if it would produce an object with the given 542 /// metadata. 543 /// 544 /// Returns `None` if the resulting `U` would be invalidly-aligned, if no 545 /// `U` can fit in `self`, or if the provided pointer metadata describes an 546 /// invalid instance of `U`. On success, returns a pointer to the 547 /// largest-possible `U` which fits in `self`. 548 /// 549 /// # Safety 550 /// 551 /// The caller may assume that this implementation is correct, and may rely 552 /// on that assumption for the soundness of their code. In particular, the 553 /// caller may assume that, if `try_cast_into` returns `Some((ptr, 554 /// remainder))`, then `ptr` and `remainder` refer to non-overlapping byte 555 /// ranges within `self`, and that `ptr` and `remainder` entirely cover 556 /// `self`. Finally: 557 /// - If this is a prefix cast, `ptr` has the same address as `self`. 558 /// - If this is a suffix cast, `remainder` has the same address as `self`. 559 #[inline] 560 pub fn try_cast_into<U>( 561 self, 562 cast_type: CastType, 563 meta: Option<U::PointerMetadata>, 564 ) -> Result<(PtrInner<'a, U>, PtrInner<'a, [u8]>), CastError<Self, U>> 565 where 566 U: 'a + ?Sized + KnownLayout, 567 { 568 // PANICS: By invariant, the byte range addressed by 569 // `self.as_non_null()` does not wrap around the address space. This 570 // implies that the sum of the address (represented as a `usize`) and 571 // length do not overflow `usize`, as required by 572 // `validate_cast_and_convert_metadata`. Thus, this call to 573 // `validate_cast_and_convert_metadata` will only panic if `U` is a DST 574 // whose trailing slice element is zero-sized. 575 let maybe_metadata = MetadataOf::<U>::validate_cast_and_convert_metadata( 576 AsAddress::addr(self.as_ptr()), 577 self.meta(), 578 cast_type, 579 meta, 580 ); 581 582 let (elems, split_at) = match maybe_metadata { 583 Ok((elems, split_at)) => (elems, split_at), 584 Err(MetadataCastError::Alignment) => { 585 // SAFETY: Since `validate_cast_and_convert_metadata` returned 586 // an alignment error, `U` must have an alignment requirement 587 // greater than one. 588 let err = unsafe { AlignmentError::<_, U>::new_unchecked(self) }; 589 return Err(CastError::Alignment(err)); 590 } 591 Err(MetadataCastError::Size) => return Err(CastError::Size(SizeError::new(self))), 592 }; 593 594 // SAFETY: `validate_cast_and_convert_metadata` promises to return 595 // `split_at <= self.meta()`. 596 // 597 // Lemma 0: `l_slice` and `r_slice` are non-overlapping. Proof: By 598 // contract on `PtrInner::split_at_unchecked`, the produced `PtrInner`s 599 // are always non-overlapping if `self` is a `[T]`; here it is a `[u8]`. 600 let (l_slice, r_slice) = unsafe { self.split_at_unchecked(split_at) }; 601 602 let (target, remainder) = match cast_type { 603 CastType::Prefix => (l_slice, r_slice), 604 CastType::Suffix => (r_slice, l_slice), 605 }; 606 607 let base = target.as_non_null().cast::<u8>(); 608 609 let ptr = U::raw_from_ptr_len(base, elems.get()); 610 611 // SAFETY: 612 // 0. By invariant, if `target`'s referent is not zero sized, then 613 // `target` has provenance valid for some Rust allocation, `A`. 614 // Because `ptr` is derived from `target` via provenance-preserving 615 // operations, `ptr` will also have provenance valid for its entire 616 // referent. 617 // 1. `validate_cast_and_convert_metadata` promises that the object 618 // described by `elems` and `split_at` lives at a byte range which is 619 // a subset of the input byte range. Thus, by invariant, if 620 // `target`'s referent is not zero sized, then `target` refers to an 621 // allocation which is guaranteed to live for at least `'a`, and thus 622 // so does `ptr`. 623 Ok((unsafe { PtrInner::new(ptr) }, remainder)) 624 } 625 } 626 627 #[cfg(test)] 628 mod tests { 629 use super::*; 630 use crate::*; 631 632 #[test] 633 fn test_meta() { 634 let arr = [1; 16]; 635 let dst = <[u8]>::ref_from_bytes(&arr[..]).unwrap(); 636 let ptr = PtrInner::from_ref(dst); 637 assert_eq!(ptr.meta().get(), 16); 638 639 // SAFETY: 8 is less than 16 640 let ptr = unsafe { ptr.with_meta(8) }; 641 642 assert_eq!(ptr.meta().get(), 8); 643 } 644 645 #[test] 646 fn test_split_at() { 647 fn test_split_at<const OFFSET: usize, const BUFFER_SIZE: usize>() { 648 #[derive(FromBytes, KnownLayout, SplitAt, Immutable)] 649 #[repr(C)] 650 struct SliceDst<const OFFSET: usize> { 651 prefix: [u8; OFFSET], 652 trailing: [u8], 653 } 654 655 let n: usize = BUFFER_SIZE - OFFSET; 656 let arr = [1; BUFFER_SIZE]; 657 let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap(); 658 let ptr = PtrInner::from_ref(dst); 659 for i in 0..=n { 660 assert_eq!(ptr.meta().get(), n); 661 // SAFETY: `i` is in bounds by construction. 662 let i = unsafe { MetadataOf::new_unchecked(i) }; 663 // SAFETY: `i` is in bounds by construction. 664 let (l, r) = unsafe { ptr.split_at_unchecked(i) }; 665 // SAFETY: Points to a valid value by construction. 666 #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)] 667 // Clippy false positive 668 let l_sum: usize = l 669 .trailing_slice() 670 .iter() 671 .map( 672 #[inline(always)] 673 |ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize, 674 ) 675 .sum(); 676 // SAFETY: Points to a valid value by construction. 677 #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)] 678 // Clippy false positive 679 let r_sum: usize = r 680 .iter() 681 .map( 682 #[inline(always)] 683 |ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize, 684 ) 685 .sum(); 686 assert_eq!(l_sum, i.get()); 687 assert_eq!(r_sum, n - i.get()); 688 assert_eq!(l_sum + r_sum, n); 689 } 690 } 691 692 test_split_at::<0, 16>(); 693 test_split_at::<1, 17>(); 694 test_split_at::<2, 18>(); 695 } 696 697 #[test] 698 fn test_trailing_slice() { 699 fn test_trailing_slice<const OFFSET: usize, const BUFFER_SIZE: usize>() { 700 #[derive(FromBytes, KnownLayout, SplitAt, Immutable)] 701 #[repr(C)] 702 struct SliceDst<const OFFSET: usize> { 703 prefix: [u8; OFFSET], 704 trailing: [u8], 705 } 706 707 let n: usize = BUFFER_SIZE - OFFSET; 708 let arr = [1; BUFFER_SIZE]; 709 let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap(); 710 let ptr = PtrInner::from_ref(dst); 711 712 assert_eq!(ptr.meta().get(), n); 713 let trailing = ptr.trailing_slice(); 714 assert_eq!(trailing.meta().get(), n); 715 716 assert_eq!( 717 // SAFETY: We assume this to be sound for the sake of this test, 718 // which will fail, here, in miri, if the safety precondition of 719 // `offset_of` is not satisfied. 720 unsafe { 721 #[allow(clippy::as_conversions)] 722 let offset = (trailing.as_ptr() as *mut u8).offset_from(ptr.as_ptr() as *mut _); 723 offset 724 }, 725 isize::try_from(OFFSET).unwrap(), 726 ); 727 728 // SAFETY: Points to a valid value by construction. 729 #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)] 730 // Clippy false positive 731 let trailing: usize = trailing 732 .iter() 733 .map(|ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize) 734 .sum(); 735 736 assert_eq!(trailing, n); 737 } 738 739 test_trailing_slice::<0, 16>(); 740 test_trailing_slice::<1, 17>(); 741 test_trailing_slice::<2, 18>(); 742 } 743 #[test] 744 fn test_ptr_inner_clone() { 745 let mut x = 0u8; 746 let p = PtrInner::from_mut(&mut x); 747 #[allow(clippy::clone_on_copy)] 748 let p2 = p.clone(); 749 assert_eq!(p.as_non_null(), p2.as_non_null()); 750 } 751 } 752