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