xref: /aosp_15_r20/external/crosvm/base/src/iobuf.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2023 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Cross platform [`IoBuf`] and [`IoBufMut`] types wrapping `iovec`/`WSABUF`.
6 
7 use std::fmt;
8 use std::fmt::Debug;
9 use std::marker::PhantomData;
10 use std::slice;
11 
12 pub use crate::IoBuf;
13 
14 pub(crate) trait PlatformIoBuf {
new(ptr: *mut u8, len: usize) -> Self15     fn new(ptr: *mut u8, len: usize) -> Self;
len(&self) -> usize16     fn len(&self) -> usize;
ptr(&self) -> *mut u817     fn ptr(&self) -> *mut u8;
set_len(&mut self, len: usize)18     fn set_len(&mut self, len: usize);
set_ptr(&mut self, ptr: *mut u8)19     fn set_ptr(&mut self, ptr: *mut u8);
20 }
21 
22 /// Cross-platform mutable buffer.
23 ///
24 /// This type is essentialy `std::io::IoSliceMut`, and guaranteed to be ABI-compatible with
25 /// `libc::iovec` on Linux/`WSABUF` on Windows; however, it does NOT automatically deref to `&mut
26 /// [u8]`, which is critical because it can point to guest memory. (Guest memory is implicitly
27 /// mutably borrowed by the guest, so another mutable borrow would violate Rust assumptions about
28 /// references.)
29 #[derive(Copy, Clone)]
30 #[repr(transparent)]
31 pub struct IoBufMut<'a> {
32     iobuf: IoBuf,
33     phantom: PhantomData<&'a mut [u8]>,
34 }
35 
36 impl<'a> IoBufMut<'a> {
new(buf: &mut [u8]) -> IoBufMut<'a>37     pub fn new(buf: &mut [u8]) -> IoBufMut<'a> {
38         // SAFETY:
39         // Safe because buf's memory is of the supplied length, and
40         // guaranteed to exist for the lifetime of the returned value.
41         unsafe { Self::from_raw_parts(buf.as_mut_ptr(), buf.len()) }
42     }
43 
44     /// Creates a `IoBufMut` from a pointer and a length.
45     ///
46     /// # Safety
47     ///
48     /// In order to use this method safely, `addr` must be valid for reads and writes of `len` bytes
49     /// and should live for the entire duration of lifetime `'a`.
from_raw_parts(addr: *mut u8, len: usize) -> IoBufMut<'a>50     pub unsafe fn from_raw_parts(addr: *mut u8, len: usize) -> IoBufMut<'a> {
51         IoBufMut {
52             iobuf: IoBuf::new(addr, len),
53             phantom: PhantomData,
54         }
55     }
56 
57     /// Creates a `IoBufMut` from an IoBuf.
58     ///
59     /// # Safety
60     ///
61     /// In order to use this method safely, `iobuf` must be valid for reads and writes through its
62     /// length and should live for the entire duration of lifetime `'a`.
from_iobuf(iobuf: IoBuf) -> IoBufMut<'a>63     pub unsafe fn from_iobuf(iobuf: IoBuf) -> IoBufMut<'a> {
64         IoBufMut {
65             iobuf,
66             phantom: PhantomData,
67         }
68     }
69 
70     /// Advance the internal position of the buffer.
71     ///
72     /// Panics if `count > self.len()`.
advance(&mut self, count: usize)73     pub fn advance(&mut self, count: usize) {
74         assert!(count <= self.len());
75 
76         self.iobuf.set_len(self.len() - count);
77 
78         // SAFETY:
79         // Safe because we've checked that `count <= self.len()` so both the starting and resulting
80         // pointer are within the bounds of the allocation.
81         self.iobuf.set_ptr(unsafe { self.as_mut_ptr().add(count) });
82     }
83 
84     /// Shorten the length of the buffer.
85     ///
86     /// Has no effect if `len > self.len()`.
truncate(&mut self, len: usize)87     pub fn truncate(&mut self, len: usize) {
88         if len < self.len() {
89             self.iobuf.set_len(len);
90         }
91     }
92 
93     #[inline]
len(&self) -> usize94     pub fn len(&self) -> usize {
95         self.iobuf.len()
96     }
97 
98     #[inline]
is_empty(&self) -> bool99     pub fn is_empty(&self) -> bool {
100         self.len() == 0
101     }
102 
103     /// Gets a const pointer to this slice's memory.
104     #[inline]
as_ptr(&self) -> *const u8105     pub fn as_ptr(&self) -> *const u8 {
106         self.iobuf.ptr() as *const u8
107     }
108 
109     /// Gets a mutable pointer to this slice's memory.
110     #[inline]
as_mut_ptr(&self) -> *mut u8111     pub fn as_mut_ptr(&self) -> *mut u8 {
112         self.iobuf.ptr()
113     }
114 
115     /// Converts a slice of `IoBufMut`s into a slice of `IoBuf`s.
116     #[allow(clippy::wrong_self_convention)]
117     #[inline]
as_iobufs<'slice>(iovs: &'slice [IoBufMut<'_>]) -> &'slice [IoBuf]118     pub fn as_iobufs<'slice>(iovs: &'slice [IoBufMut<'_>]) -> &'slice [IoBuf] {
119         // SAFETY:
120         // Safe because `IoBufMut` is ABI-compatible with `IoBuf`.
121         unsafe { slice::from_raw_parts(iovs.as_ptr() as *const IoBuf, iovs.len()) }
122     }
123 
124     /// Converts a mutable slice of `IoBufMut`s into a mutable slice of `IoBuf`s.
125     #[inline]
as_iobufs_mut<'slice>(iovs: &'slice mut [IoBufMut<'_>]) -> &'slice mut [IoBuf]126     pub fn as_iobufs_mut<'slice>(iovs: &'slice mut [IoBufMut<'_>]) -> &'slice mut [IoBuf] {
127         // SAFETY:
128         // Safe because `IoBufMut` is ABI-compatible with `IoBuf`.
129         unsafe { slice::from_raw_parts_mut(iovs.as_mut_ptr() as *mut IoBuf, iovs.len()) }
130     }
131 }
132 
133 impl<'a> AsRef<IoBuf> for IoBufMut<'a> {
as_ref(&self) -> &IoBuf134     fn as_ref(&self) -> &IoBuf {
135         &self.iobuf
136     }
137 }
138 
139 impl<'a> AsMut<IoBuf> for IoBufMut<'a> {
as_mut(&mut self) -> &mut IoBuf140     fn as_mut(&mut self) -> &mut IoBuf {
141         &mut self.iobuf
142     }
143 }
144 
145 // SAFETY:
146 // It's safe to implement Send + Sync for this type for the same reason that `std::io::IoSliceMut`
147 // is Send + Sync. Internally, it contains a pointer and a length. The integer length is safely Send
148 // + Sync.  There's nothing wrong with sending a pointer between threads and de-referencing the
149 // pointer requires an unsafe block anyway. See also https://github.com/rust-lang/rust/pull/70342.
150 unsafe impl<'a> Send for IoBufMut<'a> {}
151 // SAFETY: See comments for impl Send
152 unsafe impl<'a> Sync for IoBufMut<'a> {}
153 
154 impl<'a> Debug for IoBufMut<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result155     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156         f.debug_struct("IoBufMut")
157             .field("ptr", &self.iobuf.ptr())
158             .field("len", &self.iobuf.len())
159             .finish()
160     }
161 }
162