| 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 | //! Traits for types that encapsulate a `[u8]`. |
| 10 | //! |
| 11 | //! These traits are used to bound the `B` parameter of [`Ref`]. |
| 12 | |
| 13 | use core::{ |
| 14 | cell, |
| 15 | ops::{Deref, DerefMut}, |
| 16 | }; |
| 17 | |
| 18 | #[cfg (doc)] |
| 19 | use crate::Ref; |
| 20 | |
| 21 | // For each trait polyfill, as soon as the corresponding feature is stable, the |
| 22 | // polyfill import will be unused because method/function resolution will prefer |
| 23 | // the inherent method/function over a trait method/function. Thus, we suppress |
| 24 | // the `unused_imports` warning. |
| 25 | // |
| 26 | // See the documentation on `util::polyfills` for more information. |
| 27 | #[allow (unused_imports)] |
| 28 | use crate::util::polyfills::{self, NonNullExt as _, NumExt as _}; |
| 29 | |
| 30 | /// A mutable or immutable reference to a byte slice. |
| 31 | /// |
| 32 | /// `ByteSlice` abstracts over the mutability of a byte slice reference, and is |
| 33 | /// implemented for various special reference types such as |
| 34 | /// [`Ref<[u8]>`](core::cell::Ref) and [`RefMut<[u8]>`](core::cell::RefMut). |
| 35 | /// |
| 36 | /// # Safety |
| 37 | /// |
| 38 | /// Implementations of `ByteSlice` must promise that their implementations of |
| 39 | /// [`Deref`] and [`DerefMut`] are "stable". In particular, given `B: ByteSlice` |
| 40 | /// and `b: B`, two calls, each to either `b.deref()` or `b.deref_mut()`, must |
| 41 | /// return a byte slice with the same address and length. This must hold even if |
| 42 | /// the two calls are separated by an arbitrary sequence of calls to methods on |
| 43 | /// `ByteSlice`, [`ByteSliceMut`], [`IntoByteSlice`], or [`IntoByteSliceMut`], |
| 44 | /// or on their super-traits. This does *not* need to hold if the two calls are |
| 45 | /// separated by any method calls, field accesses, or field modifications *other |
| 46 | /// than* those from these traits. |
| 47 | /// |
| 48 | /// Note that this also implies that, given `b: B`, the address and length |
| 49 | /// cannot be modified via objects other than `b`, either on the same thread or |
| 50 | /// on another thread. |
| 51 | pub unsafe trait ByteSlice: Deref<Target = [u8]> + Sized {} |
| 52 | |
| 53 | /// A mutable reference to a byte slice. |
| 54 | /// |
| 55 | /// `ByteSliceMut` abstracts over various ways of storing a mutable reference to |
| 56 | /// a byte slice, and is implemented for various special reference types such as |
| 57 | /// `RefMut<[u8]>`. |
| 58 | /// |
| 59 | /// `ByteSliceMut` is a shorthand for [`ByteSlice`] and [`DerefMut`]. |
| 60 | pub trait ByteSliceMut: ByteSlice + DerefMut {} |
| 61 | impl<B: ByteSlice + DerefMut> ByteSliceMut for B {} |
| 62 | |
| 63 | /// A [`ByteSlice`] which can be copied without violating dereference stability. |
| 64 | /// |
| 65 | /// # Safety |
| 66 | /// |
| 67 | /// If `B: CopyableByteSlice`, then the dereference stability properties |
| 68 | /// required by [`ByteSlice`] (see that trait's safety documentation) do not |
| 69 | /// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also |
| 70 | /// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by |
| 71 | /// copying `b`. |
| 72 | pub unsafe trait CopyableByteSlice: ByteSlice + Copy + CloneableByteSlice {} |
| 73 | |
| 74 | /// A [`ByteSlice`] which can be cloned without violating dereference stability. |
| 75 | /// |
| 76 | /// # Safety |
| 77 | /// |
| 78 | /// If `B: CloneableByteSlice`, then the dereference stability properties |
| 79 | /// required by [`ByteSlice`] (see that trait's safety documentation) do not |
| 80 | /// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also |
| 81 | /// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by |
| 82 | /// `b.clone()`, `b.clone().clone()`, etc. |
| 83 | pub unsafe trait CloneableByteSlice: ByteSlice + Clone {} |
| 84 | |
| 85 | /// A [`ByteSlice`] that can be split in two. |
| 86 | /// |
| 87 | /// # Safety |
| 88 | /// |
| 89 | /// Unsafe code may depend for its soundness on the assumption that `split_at` |
| 90 | /// and `split_at_unchecked` are implemented correctly. In particular, given `B: |
| 91 | /// SplitByteSlice` and `b: B`, if `b.deref()` returns a byte slice with address |
| 92 | /// `addr` and length `len`, then if `split <= len`, both of these |
| 93 | /// invocations: |
| 94 | /// - `b.split_at(split)` |
| 95 | /// - `b.split_at_unchecked(split)` |
| 96 | /// |
| 97 | /// ...will return `(first, second)` such that: |
| 98 | /// - `first`'s address is `addr` and its length is `split` |
| 99 | /// - `second`'s address is `addr + split` and its length is `len - split` |
| 100 | pub unsafe trait SplitByteSlice: ByteSlice { |
| 101 | /// Attempts to split `self` at the midpoint. |
| 102 | /// |
| 103 | /// `s.split_at(mid)` returns `Ok((s[..mid], s[mid..]))` if `mid <= |
| 104 | /// s.deref().len()` and otherwise returns `Err(s)`. |
| 105 | /// |
| 106 | /// # Safety |
| 107 | /// |
| 108 | /// Unsafe code may rely on this function correctly implementing the above |
| 109 | /// functionality. |
| 110 | #[inline ] |
| 111 | fn split_at(self, mid: usize) -> Result<(Self, Self), Self> { |
| 112 | if mid <= self.deref().len() { |
| 113 | // SAFETY: Above, we ensure that `mid <= self.deref().len()`. By |
| 114 | // invariant on `ByteSlice`, a supertrait of `SplitByteSlice`, |
| 115 | // `.deref()` is guranteed to be "stable"; i.e., it will always |
| 116 | // dereference to a byte slice of the same address and length. Thus, |
| 117 | // we can be sure that the above precondition remains satisfied |
| 118 | // through the call to `split_at_unchecked`. |
| 119 | unsafe { Ok(self.split_at_unchecked(mid)) } |
| 120 | } else { |
| 121 | Err(self) |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | /// Splits the slice at the midpoint, possibly omitting bounds checks. |
| 126 | /// |
| 127 | /// `s.split_at_unchecked(mid)` returns `s[..mid]` and `s[mid..]`. |
| 128 | /// |
| 129 | /// # Safety |
| 130 | /// |
| 131 | /// `mid` must not be greater than `self.deref().len()`. |
| 132 | /// |
| 133 | /// # Panics |
| 134 | /// |
| 135 | /// Implementations of this method may choose to perform a bounds check and |
| 136 | /// panic if `mid > self.deref().len()`. They may also panic for any other |
| 137 | /// reason. Since it is optional, callers must not rely on this behavior for |
| 138 | /// soundness. |
| 139 | #[must_use ] |
| 140 | unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self); |
| 141 | } |
| 142 | |
| 143 | /// A shorthand for [`SplitByteSlice`] and [`ByteSliceMut`]. |
| 144 | pub trait SplitByteSliceMut: SplitByteSlice + ByteSliceMut {} |
| 145 | impl<B: SplitByteSlice + ByteSliceMut> SplitByteSliceMut for B {} |
| 146 | |
| 147 | #[allow (clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice`. |
| 148 | /// A [`ByteSlice`] that conveys no ownership, and so can be converted into a |
| 149 | /// byte slice. |
| 150 | /// |
| 151 | /// Some `ByteSlice` types (notably, the standard library's [`Ref`] type) convey |
| 152 | /// ownership, and so they cannot soundly be moved by-value into a byte slice |
| 153 | /// type (`&[u8]`). Some methods in this crate's API (such as [`Ref::into_ref`]) |
| 154 | /// are only compatible with `ByteSlice` types without these ownership |
| 155 | /// semantics. |
| 156 | /// |
| 157 | /// [`Ref`]: core::cell::Ref |
| 158 | pub unsafe trait IntoByteSlice<'a>: ByteSlice { |
| 159 | /// Coverts `self` into a `&[u8]`. |
| 160 | /// |
| 161 | /// # Safety |
| 162 | /// |
| 163 | /// The returned reference has the same address and length as `self.deref()` |
| 164 | /// and `self.deref_mut()`. |
| 165 | /// |
| 166 | /// Note that, combined with the safety invariant on [`ByteSlice`], this |
| 167 | /// safety invariant implies that the returned reference is "stable" in the |
| 168 | /// sense described in the `ByteSlice` docs. |
| 169 | fn into_byte_slice(self) -> &'a [u8]; |
| 170 | } |
| 171 | |
| 172 | #[allow (clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice_mut`. |
| 173 | /// A [`ByteSliceMut`] that conveys no ownership, and so can be converted into a |
| 174 | /// mutable byte slice. |
| 175 | /// |
| 176 | /// Some `ByteSliceMut` types (notably, the standard library's [`RefMut`] type) |
| 177 | /// convey ownership, and so they cannot soundly be moved by-value into a byte |
| 178 | /// slice type (`&mut [u8]`). Some methods in this crate's API (such as |
| 179 | /// [`Ref::into_mut`]) are only compatible with `ByteSliceMut` types without |
| 180 | /// these ownership semantics. |
| 181 | /// |
| 182 | /// [`RefMut`]: core::cell::RefMut |
| 183 | pub unsafe trait IntoByteSliceMut<'a>: IntoByteSlice<'a> + ByteSliceMut { |
| 184 | /// Coverts `self` into a `&mut [u8]`. |
| 185 | /// |
| 186 | /// # Safety |
| 187 | /// |
| 188 | /// The returned reference has the same address and length as `self.deref()` |
| 189 | /// and `self.deref_mut()`. |
| 190 | /// |
| 191 | /// Note that, combined with the safety invariant on [`ByteSlice`], this |
| 192 | /// safety invariant implies that the returned reference is "stable" in the |
| 193 | /// sense described in the `ByteSlice` docs. |
| 194 | fn into_byte_slice_mut(self) -> &'a mut [u8]; |
| 195 | } |
| 196 | |
| 197 | // TODO(#429): Add a "SAFETY" comment and remove this `allow`. |
| 198 | #[allow (clippy::undocumented_unsafe_blocks)] |
| 199 | unsafe impl ByteSlice for &[u8] {} |
| 200 | |
| 201 | // TODO(#429): Add a "SAFETY" comment and remove this `allow`. |
| 202 | #[allow (clippy::undocumented_unsafe_blocks)] |
| 203 | unsafe impl CopyableByteSlice for &[u8] {} |
| 204 | |
| 205 | // TODO(#429): Add a "SAFETY" comment and remove this `allow`. |
| 206 | #[allow (clippy::undocumented_unsafe_blocks)] |
| 207 | unsafe impl CloneableByteSlice for &[u8] {} |
| 208 | |
| 209 | // SAFETY: This delegates to `polyfills:split_at_unchecked`, which is documented |
| 210 | // to correctly split `self` into two slices at the given `mid` point. |
| 211 | unsafe impl SplitByteSlice for &[u8] { |
| 212 | #[inline ] |
| 213 | unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { |
| 214 | // SAFETY: By contract on caller, `mid` is not greater than |
| 215 | // `bytes.len()`. |
| 216 | unsafe { (<[u8]>::get_unchecked(self, ..mid), <[u8]>::get_unchecked(self, index:mid..)) } |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | // SAFETY: See inline. |
| 221 | unsafe impl<'a> IntoByteSlice<'a> for &'a [u8] { |
| 222 | #[inline (always)] |
| 223 | fn into_byte_slice(self) -> &'a [u8] { |
| 224 | // SAFETY: It would be patently insane to implement `<Deref for |
| 225 | // &[u8]>::deref` as anything other than `fn deref(&self) -> &[u8] { |
| 226 | // *self }`. Assuming this holds, then `self` is stable as required by |
| 227 | // `into_byte_slice`. |
| 228 | self |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | // TODO(#429): Add a "SAFETY" comment and remove this `allow`. |
| 233 | #[allow (clippy::undocumented_unsafe_blocks)] |
| 234 | unsafe impl ByteSlice for &mut [u8] {} |
| 235 | |
| 236 | // SAFETY: This delegates to `polyfills:split_at_mut_unchecked`, which is |
| 237 | // documented to correctly split `self` into two slices at the given `mid` |
| 238 | // point. |
| 239 | unsafe impl SplitByteSlice for &mut [u8] { |
| 240 | #[inline ] |
| 241 | unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { |
| 242 | use core::slice::from_raw_parts_mut; |
| 243 | |
| 244 | // `l_ptr` is non-null, because `self` is non-null, by invariant on |
| 245 | // `&mut [u8]`. |
| 246 | let l_ptr = self.as_mut_ptr(); |
| 247 | |
| 248 | // SAFETY: By contract on caller, `mid` is not greater than |
| 249 | // `self.len()`. |
| 250 | let r_ptr = unsafe { l_ptr.add(mid) }; |
| 251 | |
| 252 | let l_len = mid; |
| 253 | |
| 254 | // SAFETY: By contract on caller, `mid` is not greater than |
| 255 | // `self.len()`. |
| 256 | // |
| 257 | // TODO(#67): Remove this allow. See NumExt for more details. |
| 258 | #[allow (unstable_name_collisions, clippy::incompatible_msrv)] |
| 259 | let r_len = unsafe { self.len().unchecked_sub(mid) }; |
| 260 | |
| 261 | // SAFETY: These invocations of `from_raw_parts_mut` satisfy its |
| 262 | // documented safety preconditions [1]: |
| 263 | // - The data `l_ptr` and `r_ptr` are valid for both reads and writes of |
| 264 | // `l_len` and `r_len` bytes, respectively, and they are trivially |
| 265 | // aligned. In particular: |
| 266 | // - The entire memory range of each slice is contained within a |
| 267 | // single allocated object, since `l_ptr` and `r_ptr` are both |
| 268 | // derived from within the address range of `self`. |
| 269 | // - Both `l_ptr` and `r_ptr` are non-null and trivially aligned. |
| 270 | // `self` is non-null by invariant on `&mut [u8]`, and the |
| 271 | // operations that derive `l_ptr` and `r_ptr` from `self` do not |
| 272 | // nullify either pointer. |
| 273 | // - The data `l_ptr` and `r_ptr` point to `l_len` and `r_len`, |
| 274 | // respectively, consecutive properly initialized values of type `u8`. |
| 275 | // This is true for `self` by invariant on `&mut [u8]`, and remains |
| 276 | // true for these two sub-slices of `self`. |
| 277 | // - The memory referenced by the returned slice cannot be accessed |
| 278 | // through any other pointer (not derived from the return value) for |
| 279 | // the duration of lifetime `'a``, because: |
| 280 | // - `split_at_unchecked` consumes `self` (which is not `Copy`), |
| 281 | // - `split_at_unchecked` does not exfiltrate any references to this |
| 282 | // memory, besides those references returned below, |
| 283 | // - the returned slices are non-overlapping. |
| 284 | // - The individual sizes of the sub-slices of `self` are no larger than |
| 285 | // `isize::MAX`, because their combined sizes are no larger than |
| 286 | // `isize::MAX`, by invariant on `self`. |
| 287 | // |
| 288 | // [1] https://doc.rust-lang.org/std/slice/fn.from_raw_parts_mut.html#safety |
| 289 | unsafe { (from_raw_parts_mut(l_ptr, l_len), from_raw_parts_mut(r_ptr, r_len)) } |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | // SAFETY: See inline. |
| 294 | unsafe impl<'a> IntoByteSlice<'a> for &'a mut [u8] { |
| 295 | #[inline (always)] |
| 296 | fn into_byte_slice(self) -> &'a [u8] { |
| 297 | // SAFETY: It would be patently insane to implement `<Deref for &mut |
| 298 | // [u8]>::deref` as anything other than `fn deref(&self) -> &[u8] { |
| 299 | // *self }`. Assuming this holds, then `self` is stable as required by |
| 300 | // `into_byte_slice`. |
| 301 | self |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | // SAFETY: See inline. |
| 306 | unsafe impl<'a> IntoByteSliceMut<'a> for &'a mut [u8] { |
| 307 | #[inline (always)] |
| 308 | fn into_byte_slice_mut(self) -> &'a mut [u8] { |
| 309 | // SAFETY: It would be patently insane to implement `<DerefMut for &mut |
| 310 | // [u8]>::deref` as anything other than `fn deref_mut(&mut self) -> &mut |
| 311 | // [u8] { *self }`. Assuming this holds, then `self` is stable as |
| 312 | // required by `into_byte_slice_mut`. |
| 313 | self |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | // TODO(#429): Add a "SAFETY" comment and remove this `allow`. |
| 318 | #[allow (clippy::undocumented_unsafe_blocks)] |
| 319 | unsafe impl ByteSlice for cell::Ref<'_, [u8]> {} |
| 320 | |
| 321 | // SAFETY: This delegates to stdlib implementation of `Ref::map_split`, which is |
| 322 | // assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is |
| 323 | // documented to correctly split `self` into two slices at the given `mid` |
| 324 | // point. |
| 325 | unsafe impl SplitByteSlice for cell::Ref<'_, [u8]> { |
| 326 | #[inline ] |
| 327 | unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { |
| 328 | cell::Ref::map_split(self, |slice: &[u8]| |
| 329 | // SAFETY: By precondition on caller, `mid` is not greater than |
| 330 | // `slice.len()`. |
| 331 | unsafe { |
| 332 | SplitByteSlice::split_at_unchecked(self:slice, mid) |
| 333 | }) |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | // TODO(#429): Add a "SAFETY" comment and remove this `allow`. |
| 338 | #[allow (clippy::undocumented_unsafe_blocks)] |
| 339 | unsafe impl ByteSlice for cell::RefMut<'_, [u8]> {} |
| 340 | |
| 341 | // SAFETY: This delegates to stdlib implementation of `RefMut::map_split`, which |
| 342 | // is assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is |
| 343 | // documented to correctly split `self` into two slices at the given `mid` |
| 344 | // point. |
| 345 | unsafe impl SplitByteSlice for cell::RefMut<'_, [u8]> { |
| 346 | #[inline ] |
| 347 | unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { |
| 348 | cell::RefMut::map_split(self, |slice: &mut [u8]| |
| 349 | // SAFETY: By precondition on caller, `mid` is not greater than |
| 350 | // `slice.len()` |
| 351 | unsafe { |
| 352 | SplitByteSlice::split_at_unchecked(self:slice, mid) |
| 353 | }) |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | #[cfg (kani)] |
| 358 | mod proofs { |
| 359 | use super::*; |
| 360 | |
| 361 | fn any_vec() -> Vec<u8> { |
| 362 | let len = kani::any(); |
| 363 | kani::assume(len <= isize::MAX as usize); |
| 364 | vec![0u8; len] |
| 365 | } |
| 366 | |
| 367 | #[kani::proof] |
| 368 | fn prove_split_at_unchecked() { |
| 369 | let v = any_vec(); |
| 370 | let slc = v.as_slice(); |
| 371 | let mid = kani::any(); |
| 372 | kani::assume(mid <= slc.len()); |
| 373 | let (l, r) = unsafe { slc.split_at_unchecked(mid) }; |
| 374 | assert_eq!(l.len() + r.len(), slc.len()); |
| 375 | |
| 376 | let slc: *const _ = slc; |
| 377 | let l: *const _ = l; |
| 378 | let r: *const _ = r; |
| 379 | |
| 380 | assert_eq!(slc.cast::<u8>(), l.cast::<u8>()); |
| 381 | assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>()); |
| 382 | |
| 383 | let mut v = any_vec(); |
| 384 | let slc = v.as_mut_slice(); |
| 385 | let len = slc.len(); |
| 386 | let mid = kani::any(); |
| 387 | kani::assume(mid <= slc.len()); |
| 388 | let (l, r) = unsafe { slc.split_at_unchecked(mid) }; |
| 389 | assert_eq!(l.len() + r.len(), len); |
| 390 | |
| 391 | let l: *mut _ = l; |
| 392 | let r: *mut _ = r; |
| 393 | let slc: *mut _ = slc; |
| 394 | |
| 395 | assert_eq!(slc.cast::<u8>(), l.cast::<u8>()); |
| 396 | assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>()); |
| 397 | } |
| 398 | } |
| 399 | |