• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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]
split_at(self, mid: usize) -> Result<(Self, Self), Self>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]
split_at_unchecked(self, mid: usize) -> (Self, Self)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.
into_byte_slice(self) -> &'a [u8]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.
into_byte_slice_mut(self) -> &'a mut [u8]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]
split_at_unchecked(self, mid: usize) -> (Self, Self)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, mid..)) }
217     }
218 }
219 
220 // SAFETY: See inline.
221 unsafe impl<'a> IntoByteSlice<'a> for &'a [u8] {
222     #[inline(always)]
into_byte_slice(self) -> &'a [u8]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]
split_at_unchecked(self, mid: usize) -> (Self, Self)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)]
into_byte_slice(self) -> &'a [u8]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)]
into_byte_slice_mut(self) -> &'a mut [u8]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]
split_at_unchecked(self, mid: usize) -> (Self, Self)327     unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
328         cell::Ref::map_split(self, |slice|
329             // SAFETY: By precondition on caller, `mid` is not greater than
330             // `slice.len()`.
331             unsafe {
332                 SplitByteSlice::split_at_unchecked(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]
split_at_unchecked(self, mid: usize) -> (Self, Self)347     unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
348         cell::RefMut::map_split(self, |slice|
349             // SAFETY: By precondition on caller, `mid` is not greater than
350             // `slice.len()`
351             unsafe {
352                 SplitByteSlice::split_at_unchecked(slice, mid)
353             })
354     }
355 }
356