Skip to main content

zerocopy/
byte_slice.rs

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