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 /// `l_len.padding_needed_for() == 0`. This is true for all `[T]`. 293 /// 294 /// If `l_len.padding_needed_for() != 0`, then the left pointer will overlap 295 /// the right pointer to satisfy `T`'s padding requirements. 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 `l_len.padding_needed_for() == 0`, then `left` and `right` 317 // are non-overlapping. Proof: `left` is constructed `slf` with `l_len` 318 // as its (exclusive) upper bound. If `l_len.padding_needed_for() == 0`, 319 // then `left` requires no trailing padding following its final element. 320 // Since `right` is constructed from `slf`'s trailing slice with `l_len` 321 // as its (inclusive) lower bound, no byte is referred to by both 322 // pointers. 323 // 324 // Conversely, `l_len.padding_needed_for() == N`, where `N 325 // > 0`, `left` requires `N` bytes of trailing padding following its 326 // final element. Since `right` is constructed from the trailing slice 327 // of `slf` with `l_len` as its (inclusive) lower bound, the first `N` 328 // bytes of `right` are aliased by `left`. 329 (left, right) 330 } 331 332 /// Produces the trailing slice of `self`. 333 #[inline] 334 #[must_use] 335 pub fn trailing_slice(self) -> PtrInner<'a, [T::Elem]> 336 where 337 T: SplitAt, 338 { 339 let offset = crate::trailing_slice_layout::<T>().offset; 340 341 let bytes = self.as_non_null().cast::<u8>().as_ptr(); 342 343 // SAFETY: 344 // - By invariant on `T: KnownLayout`, `T::LAYOUT` describes `T`'s 345 // layout. `offset` is the offset of the trailing slice within `T`, 346 // which is by definition in-bounds or one byte past the end of any 347 // `T`, regardless of metadata. By invariant on `PtrInner`, `self` 348 // (and thus `bytes`) points to a byte range of size `<= isize::MAX`, 349 // and so `offset <= isize::MAX`. Since `size_of::<u8>() == 1`, 350 // `offset * size_of::<u8>() <= isize::MAX`. 351 // - If `offset > 0`, then by invariant on `PtrInner`, `self` (and thus 352 // `bytes`) points to a byte range entirely contained within the same 353 // allocated object as `self`. As explained above, this offset results 354 // in a pointer to or one byte past the end of this allocated object. 355 let bytes = unsafe { bytes.add(offset) }; 356 357 // SAFETY: By the preceding safety argument, `bytes` is within or one 358 // byte past the end of the same allocated object as `self`, which 359 // ensures that it is non-null. 360 let bytes = unsafe { NonNull::new_unchecked(bytes) }; 361 362 let ptr = KnownLayout::raw_from_ptr_len(bytes, self.meta().get()); 363 364 // SAFETY: 365 // 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from 366 // some valid Rust allocation, `A`, because `ptr` is derived from 367 // the same allocated object as `self`. 368 // 1. If `ptr`'s referent is not zero sized, then `ptr` has valid 369 // provenance for `A` because `raw` is derived from the same 370 // allocated object as `self` via provenance-preserving operations. 371 // 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a byte 372 // range which is entirely contained in `A`, by previous safety proof 373 // on `bytes`. 374 // 3. `ptr` addresses a byte range whose length fits in an `isize`, by 375 // consequence of #2. 376 // 4. `ptr` addresses a byte range which does not wrap around the 377 // address space, by consequence of #2. 378 // 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to 379 // live for at least `'a`, because `ptr` is derived from `self`. 380 unsafe { PtrInner::new(ptr) } 381 } 382 } 383 384 #[allow(clippy::needless_lifetimes)] 385 impl<'a, T> PtrInner<'a, [T]> { 386 /// Creates a pointer which addresses the given `range` of self. 387 /// 388 /// # Safety 389 /// 390 /// `range` is a valid range (`start <= end`) and `end <= self.meta()`. 391 #[inline] 392 #[must_use] 393 pub unsafe fn slice_unchecked(self, range: Range<usize>) -> Self { 394 let base = self.as_non_null().cast::<T>().as_ptr(); 395 396 // SAFETY: The caller promises that `start <= end <= self.meta()`. By 397 // invariant, if `self`'s referent is not zero-sized, then `self` refers 398 // to a byte range which is contained within a single allocation, which 399 // is no more than `isize::MAX` bytes long, and which does not wrap 400 // around the address space. Thus, this pointer arithmetic remains 401 // in-bounds of the same allocation, and does not wrap around the 402 // address space. The offset (in bytes) does not overflow `isize`. 403 // 404 // If `self`'s referent is zero-sized, then these conditions are 405 // trivially satisfied. 406 let base = unsafe { base.add(range.start) }; 407 408 // SAFETY: The caller promises that `start <= end`, and so this will not 409 // underflow. 410 #[allow(unstable_name_collisions)] 411 let len = unsafe { range.end.unchecked_sub(range.start) }; 412 413 let ptr = core::ptr::slice_from_raw_parts_mut(base, len); 414 415 // SAFETY: By invariant, `self`'s referent is either a ZST or lives 416 // entirely in an allocation. `ptr` points inside of or one byte past 417 // the end of that referent. Thus, in either case, `ptr` is non-null. 418 let ptr = unsafe { NonNull::new_unchecked(ptr) }; 419 420 // SAFETY: 421 // 422 // Lemma 0: `ptr` addresses a subset of the bytes addressed by `self`, 423 // and has the same provenance. Proof: The caller guarantees 424 // that `start <= end <= self.meta()`. Thus, `base` is 425 // in-bounds of `self`, and `base + (end - start)` is also 426 // in-bounds of self. Finally, `ptr` is constructed using 427 // provenance-preserving operations. 428 // 429 // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not 430 // zero sized, then `ptr` has valid provenance for its referent, 431 // which is entirely contained in some Rust allocation, `A`. 432 // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not 433 // zero sized, then `A` is guaranteed to live for at least `'a`. 434 unsafe { PtrInner::new(ptr) } 435 } 436 437 /// Iteratively projects the elements `PtrInner<T>` from `PtrInner<[T]>`. 438 #[inline] 439 pub fn iter(&self) -> impl Iterator<Item = PtrInner<'a, T>> { 440 // FIXME(#429): Once `NonNull::cast` documents that it preserves 441 // provenance, cite those docs. 442 let base = self.as_non_null().cast::<T>().as_ptr(); 443 (0..self.meta().get()).map(move |i| { 444 // FIXME(https://github.com/rust-lang/rust/issues/74265): Use 445 // `NonNull::get_unchecked_mut`. 446 447 // SAFETY: If the following conditions are not satisfied 448 // `pointer::cast` may induce Undefined Behavior [1]: 449 // 450 // > - The computed offset, `count * size_of::<T>()` bytes, must not 451 // > overflow `isize``. 452 // > - If the computed offset is non-zero, then `self` must be 453 // > derived from a pointer to some allocated object, and the 454 // > entire memory range between `self` and the result must be in 455 // > bounds of that allocated object. In particular, this range 456 // > must not “wrap around” the edge of the address space. 457 // 458 // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add 459 // 460 // We satisfy both of these conditions here: 461 // - By invariant on `Ptr`, `self` addresses a byte range whose 462 // length fits in an `isize`. Since `elem` is contained in `self`, 463 // the computed offset of `elem` must fit within `isize.` 464 // - If the computed offset is non-zero, then this means that the 465 // referent is not zero-sized. In this case, `base` points to an 466 // allocated object (by invariant on `self`). Thus: 467 // - By contract, `self.meta()` accurately reflects the number of 468 // elements in the slice. `i` is in bounds of `c.meta()` by 469 // construction, and so the result of this addition cannot 470 // overflow past the end of the allocation referred to by `c`. 471 // - By invariant on `Ptr`, `self` addresses a byte range which 472 // does not wrap around the address space. Since `elem` is 473 // contained in `self`, the computed offset of `elem` must wrap 474 // around the address space. 475 // 476 // FIXME(#429): Once `pointer::add` documents that it preserves 477 // provenance, cite those docs. 478 let elem = unsafe { base.add(i) }; 479 480 // SAFETY: `elem` must not be null. `base` is constructed from a 481 // `NonNull` pointer, and the addition that produces `elem` must not 482 // overflow or wrap around, so `elem >= base > 0`. 483 // 484 // FIXME(#429): Once `NonNull::new_unchecked` documents that it 485 // preserves provenance, cite those docs. 486 let elem = unsafe { NonNull::new_unchecked(elem) }; 487 488 // SAFETY: The safety invariants of `Ptr::new` (see definition) are 489 // satisfied: 490 // 0. If `elem`'s referent is not zero sized, then `elem` has valid 491 // provenance for its referent, because it derived from `self` 492 // using a series of provenance-preserving operations, and 493 // because `self` has valid provenance for its referent. By the 494 // same argument, `elem`'s referent is entirely contained within 495 // the same allocated object as `self`'s referent. 496 // 1. If `elem`'s referent is not zero sized, then the allocation of 497 // `elem` is guaranteed to live for at least `'a`, because `elem` 498 // is entirely contained in `self`, which lives for at least `'a` 499 // by invariant on `Ptr`. 500 unsafe { PtrInner::new(elem) } 501 }) 502 } 503 } 504 505 impl<'a, T, const N: usize> PtrInner<'a, [T; N]> { 506 /// Casts this pointer-to-array into a slice. 507 /// 508 /// # Safety 509 /// 510 /// Callers may assume that the returned `PtrInner` references the same 511 /// address and length as `self`. 512 #[allow(clippy::wrong_self_convention)] 513 #[inline] 514 #[must_use] 515 pub fn as_slice(self) -> PtrInner<'a, [T]> { 516 let start = self.as_non_null().cast::<T>().as_ptr(); 517 let slice = core::ptr::slice_from_raw_parts_mut(start, N); 518 // SAFETY: `slice` is not null, because it is derived from `start` 519 // which is non-null. 520 let slice = unsafe { NonNull::new_unchecked(slice) }; 521 // SAFETY: Lemma: In the following safety arguments, note that `slice` 522 // is derived from `self` in two steps: first, by casting `self: [T; N]` 523 // to `start: T`, then by constructing a pointer to a slice starting at 524 // `start` of length `N`. As a result, `slice` references exactly the 525 // same allocation as `self`, if any. 526 // 527 // 0. By the above lemma, if `slice`'s referent is not zero sized, then 528 // `slice` has the same referent as `self`. By invariant on `self`, 529 // this referent is entirely contained within some allocation, `A`. 530 // Because `slice` was constructed using provenance-preserving 531 // operations, it has provenance for its entire referent. 532 // 1. By the above lemma, if `slice`'s referent is not zero sized, then 533 // `A` is guaranteed to live for at least `'a`, because it is derived 534 // from the same allocation as `self`, which, by invariant on 535 // `PtrInner`, lives for at least `'a`. 536 unsafe { PtrInner::new(slice) } 537 } 538 } 539 540 impl<'a> PtrInner<'a, [u8]> { 541 /// Attempts to cast `self` to a `U` using the given cast type. 542 /// 543 /// If `U` is a slice DST and pointer metadata (`meta`) is provided, then 544 /// the cast will only succeed if it would produce an object with the given 545 /// metadata. 546 /// 547 /// Returns `None` if the resulting `U` would be invalidly-aligned, if no 548 /// `U` can fit in `self`, or if the provided pointer metadata describes an 549 /// invalid instance of `U`. On success, returns a pointer to the 550 /// largest-possible `U` which fits in `self`. 551 /// 552 /// # Safety 553 /// 554 /// The caller may assume that this implementation is correct, and may rely 555 /// on that assumption for the soundness of their code. In particular, the 556 /// caller may assume that, if `try_cast_into` returns `Some((ptr, 557 /// remainder))`, then `ptr` and `remainder` refer to non-overlapping byte 558 /// ranges within `self`, and that `ptr` and `remainder` entirely cover 559 /// `self`. Finally: 560 /// - If this is a prefix cast, `ptr` has the same address as `self`. 561 /// - If this is a suffix cast, `remainder` has the same address as `self`. 562 #[inline] 563 pub fn try_cast_into<U>( 564 self, 565 cast_type: CastType, 566 meta: Option<U::PointerMetadata>, 567 ) -> Result<(PtrInner<'a, U>, PtrInner<'a, [u8]>), CastError<Self, U>> 568 where 569 U: 'a + ?Sized + KnownLayout, 570 { 571 // PANICS: By invariant, the byte range addressed by 572 // `self.as_non_null()` does not wrap around the address space. This 573 // implies that the sum of the address (represented as a `usize`) and 574 // length do not overflow `usize`, as required by 575 // `validate_cast_and_convert_metadata`. Thus, this call to 576 // `validate_cast_and_convert_metadata` will only panic if `U` is a DST 577 // whose trailing slice element is zero-sized. 578 let maybe_metadata = MetadataOf::<U>::validate_cast_and_convert_metadata( 579 AsAddress::addr(self.as_ptr()), 580 self.meta(), 581 cast_type, 582 meta, 583 ); 584 585 let (elems, split_at) = match maybe_metadata { 586 Ok((elems, split_at)) => (elems, split_at), 587 Err(MetadataCastError::Alignment) => { 588 // SAFETY: Since `validate_cast_and_convert_metadata` returned 589 // an alignment error, `U` must have an alignment requirement 590 // greater than one. 591 let err = unsafe { AlignmentError::<_, U>::new_unchecked(self) }; 592 return Err(CastError::Alignment(err)); 593 } 594 Err(MetadataCastError::Size) => return Err(CastError::Size(SizeError::new(self))), 595 }; 596 597 // SAFETY: `validate_cast_and_convert_metadata` promises to return 598 // `split_at <= self.meta()`. 599 // 600 // Lemma 0: `l_slice` and `r_slice` are non-overlapping. Proof: By 601 // contract on `PtrInner::split_at_unchecked`, the produced `PtrInner`s 602 // are always non-overlapping if `self` is a `[T]`; here it is a `[u8]`. 603 let (l_slice, r_slice) = unsafe { self.split_at_unchecked(split_at) }; 604 605 let (target, remainder) = match cast_type { 606 CastType::Prefix => (l_slice, r_slice), 607 CastType::Suffix => (r_slice, l_slice), 608 }; 609 610 let base = target.as_non_null().cast::<u8>(); 611 612 let ptr = U::raw_from_ptr_len(base, elems.get()); 613 614 // SAFETY: 615 // 0. By invariant, if `target`'s referent is not zero sized, then 616 // `target` has provenance valid for some Rust allocation, `A`. 617 // Because `ptr` is derived from `target` via provenance-preserving 618 // operations, `ptr` will also have provenance valid for its entire 619 // referent. 620 // 1. `validate_cast_and_convert_metadata` promises that the object 621 // described by `elems` and `split_at` lives at a byte range which is 622 // a subset of the input byte range. Thus, by invariant, if 623 // `target`'s referent is not zero sized, then `target` refers to an 624 // allocation which is guaranteed to live for at least `'a`, and thus 625 // so does `ptr`. 626 Ok((unsafe { PtrInner::new(ptr) }, remainder)) 627 } 628 } 629 630 #[cfg(test)] 631 mod tests { 632 use super::*; 633 use crate::*; 634 635 #[test] 636 fn test_meta() { 637 let arr = [1; 16]; 638 let dst = <[u8]>::ref_from_bytes(&arr[..]).unwrap(); 639 let ptr = PtrInner::from_ref(dst); 640 assert_eq!(ptr.meta().get(), 16); 641 642 // SAFETY: 8 is less than 16 643 let ptr = unsafe { ptr.with_meta(8) }; 644 645 assert_eq!(ptr.meta().get(), 8); 646 } 647 648 #[test] 649 fn test_split_at() { 650 fn test_split_at<const OFFSET: usize, const BUFFER_SIZE: usize>() { 651 #[derive(FromBytes, KnownLayout, SplitAt, Immutable)] 652 #[repr(C)] 653 struct SliceDst<const OFFSET: usize> { 654 prefix: [u8; OFFSET], 655 trailing: [u8], 656 } 657 658 let n: usize = BUFFER_SIZE - OFFSET; 659 let arr = [1; BUFFER_SIZE]; 660 let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap(); 661 let ptr = PtrInner::from_ref(dst); 662 for i in 0..=n { 663 assert_eq!(ptr.meta().get(), n); 664 // SAFETY: `i` is in bounds by construction. 665 let i = unsafe { MetadataOf::new_unchecked(i) }; 666 // SAFETY: `i` is in bounds by construction. 667 let (l, r) = unsafe { ptr.split_at_unchecked(i) }; 668 // SAFETY: Points to a valid value by construction. 669 #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)] 670 // Clippy false positive 671 let l_sum: usize = l 672 .trailing_slice() 673 .iter() 674 .map( 675 #[inline(always)] 676 |ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize, 677 ) 678 .sum(); 679 // SAFETY: Points to a valid value by construction. 680 #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)] 681 // Clippy false positive 682 let r_sum: usize = r 683 .iter() 684 .map( 685 #[inline(always)] 686 |ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize, 687 ) 688 .sum(); 689 assert_eq!(l_sum, i.get()); 690 assert_eq!(r_sum, n - i.get()); 691 assert_eq!(l_sum + r_sum, n); 692 } 693 } 694 695 test_split_at::<0, 16>(); 696 test_split_at::<1, 17>(); 697 test_split_at::<2, 18>(); 698 } 699 700 #[test] 701 fn test_trailing_slice() { 702 fn test_trailing_slice<const OFFSET: usize, const BUFFER_SIZE: usize>() { 703 #[derive(FromBytes, KnownLayout, SplitAt, Immutable)] 704 #[repr(C)] 705 struct SliceDst<const OFFSET: usize> { 706 prefix: [u8; OFFSET], 707 trailing: [u8], 708 } 709 710 let n: usize = BUFFER_SIZE - OFFSET; 711 let arr = [1; BUFFER_SIZE]; 712 let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap(); 713 let ptr = PtrInner::from_ref(dst); 714 715 assert_eq!(ptr.meta().get(), n); 716 let trailing = ptr.trailing_slice(); 717 assert_eq!(trailing.meta().get(), n); 718 719 assert_eq!( 720 // SAFETY: We assume this to be sound for the sake of this test, 721 // which will fail, here, in miri, if the safety precondition of 722 // `offset_of` is not satisfied. 723 unsafe { 724 #[allow(clippy::as_conversions)] 725 let offset = (trailing.as_ptr() as *mut u8).offset_from(ptr.as_ptr() as *mut _); 726 offset 727 }, 728 isize::try_from(OFFSET).unwrap(), 729 ); 730 731 // SAFETY: Points to a valid value by construction. 732 #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)] 733 // Clippy false positive 734 let trailing: usize = trailing 735 .iter() 736 .map(|ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize) 737 .sum(); 738 739 assert_eq!(trailing, n); 740 } 741 742 test_trailing_slice::<0, 16>(); 743 test_trailing_slice::<1, 17>(); 744 test_trailing_slice::<2, 18>(); 745 } 746 #[test] 747 fn test_ptr_inner_clone() { 748 let mut x = 0u8; 749 let p = PtrInner::from_mut(&mut x); 750 #[allow(clippy::clone_on_copy)] 751 let p2 = p.clone(); 752 assert_eq!(p.as_non_null(), p2.as_non_null()); 753 } 754 } 755