• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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 use std::ffi::c_void;
6 use std::fmt;
7 use std::fmt::Debug;
8 use std::marker::PhantomData;
9 use std::slice;
10 
11 use libc::iovec;
12 
13 /// Cross platform binary compatible iovec.
14 pub type IoBuf = iovec;
15 
16 /// Cross platform stub to create a platform specific IoBuf.
create_iobuf(addr: *mut u8, len: usize) -> IoBuf17 pub fn create_iobuf(addr: *mut u8, len: usize) -> IoBuf {
18     iovec {
19         iov_base: addr as *mut c_void,
20         iov_len: len,
21     }
22 }
23 
24 /// This type is essentialy `std::io::IoSliceMut`, and guaranteed to be ABI-compatible with
25 /// `libc::iovec`; however, it does NOT automatically deref to `&mut [u8]`, which is critical
26 /// because it can point to guest memory. (Guest memory is implicitly mutably borrowed by the
27 /// guest, so another mutable borrow would violate Rust assumptions about references.)
28 #[derive(Copy, Clone)]
29 #[repr(transparent)]
30 pub struct IoBufMut<'a> {
31     iov: iovec,
32     phantom: PhantomData<&'a mut [u8]>,
33 }
34 
35 impl<'a> IoBufMut<'a> {
new(buf: &mut [u8]) -> IoBufMut<'a>36     pub fn new(buf: &mut [u8]) -> IoBufMut<'a> {
37         // Safe because buf's memory is of the supplied length, and
38         // guaranteed to exist for the lifetime of the returned value.
39         unsafe { Self::from_raw_parts(buf.as_mut_ptr(), buf.len()) }
40     }
41 
42     /// Creates a `IoBufMut` from a pointer and a length.
43     ///
44     /// # Safety
45     ///
46     /// In order to use this method safely, `addr` must be valid for reads and writes of `len` bytes
47     /// and should live for the entire duration of lifetime `'a`.
from_raw_parts(addr: *mut u8, len: usize) -> IoBufMut<'a>48     pub unsafe fn from_raw_parts(addr: *mut u8, len: usize) -> IoBufMut<'a> {
49         IoBufMut {
50             iov: iovec {
51                 iov_base: addr as *mut c_void,
52                 iov_len: len,
53             },
54             phantom: PhantomData,
55         }
56     }
57 
58     /// Creates a `IoBufMut` from an IoBuf.
59     ///
60     /// # Safety
61     ///
62     /// In order to use this method safely, `iobuf` must be valid for reads and writes through its
63     /// length and should live for the entire duration of lifetime `'a`.
from_iobuf(iobuf: IoBuf) -> IoBufMut<'a>64     pub unsafe fn from_iobuf(iobuf: IoBuf) -> IoBufMut<'a> {
65         IoBufMut {
66             iov: iobuf,
67             phantom: PhantomData,
68         }
69     }
70 
71     /// Advance the internal position of the buffer.
72     ///
73     /// Panics if `count > self.len()`.
advance(&mut self, count: usize)74     pub fn advance(&mut self, count: usize) {
75         assert!(count <= self.len());
76 
77         self.iov.iov_len -= count;
78         // Safe because we've checked that `count <= self.len()` so both the starting and resulting
79         // pointer are within the bounds of the allocation.
80         self.iov.iov_base = unsafe { self.iov.iov_base.add(count) };
81     }
82 
83     /// Shorten the length of the buffer.
84     ///
85     /// Has no effect if `len > self.len()`.
truncate(&mut self, len: usize)86     pub fn truncate(&mut self, len: usize) {
87         if len < self.len() {
88             self.iov.iov_len = len;
89         }
90     }
91 
92     #[inline]
len(&self) -> usize93     pub fn len(&self) -> usize {
94         self.iov.iov_len as usize
95     }
96 
97     #[inline]
is_empty(&self) -> bool98     pub fn is_empty(&self) -> bool {
99         self.iov.iov_len == 0
100     }
101 
102     /// Gets a const pointer to this slice's memory.
103     #[inline]
as_ptr(&self) -> *const u8104     pub fn as_ptr(&self) -> *const u8 {
105         self.iov.iov_base as *const u8
106     }
107 
108     /// Gets a mutable pointer to this slice's memory.
109     #[inline]
as_mut_ptr(&self) -> *mut u8110     pub fn as_mut_ptr(&self) -> *mut u8 {
111         self.iov.iov_base as *mut u8
112     }
113 
114     /// Converts a slice of `IoBufMut`s into a slice of `iovec`s.
115     #[allow(clippy::wrong_self_convention)]
116     #[inline]
as_iobufs<'slice>(iovs: &'slice [IoBufMut<'_>]) -> &'slice [iovec]117     pub fn as_iobufs<'slice>(iovs: &'slice [IoBufMut<'_>]) -> &'slice [iovec] {
118         // Safe because `IoBufMut` is ABI-compatible with `iovec`.
119         unsafe { slice::from_raw_parts(iovs.as_ptr() as *const libc::iovec, iovs.len()) }
120     }
121 }
122 
123 impl<'a> AsRef<libc::iovec> for IoBufMut<'a> {
as_ref(&self) -> &libc::iovec124     fn as_ref(&self) -> &libc::iovec {
125         &self.iov
126     }
127 }
128 
129 impl<'a> AsMut<libc::iovec> for IoBufMut<'a> {
as_mut(&mut self) -> &mut libc::iovec130     fn as_mut(&mut self) -> &mut libc::iovec {
131         &mut self.iov
132     }
133 }
134 
135 // It's safe to implement Send + Sync for this type for the same reason that `std::io::IoSliceMut`
136 // is Send + Sync. Internally, it contains a pointer and a length. The integer length is safely Send
137 // + Sync.  There's nothing wrong with sending a pointer between threads and de-referencing the
138 // pointer requires an unsafe block anyway. See also https://github.com/rust-lang/rust/pull/70342.
139 unsafe impl<'a> Send for IoBufMut<'a> {}
140 unsafe impl<'a> Sync for IoBufMut<'a> {}
141 
142 struct DebugIovec(iovec);
143 impl Debug for DebugIovec {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result144     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145         f.debug_struct("iovec")
146             .field("iov_base", &self.0.iov_base)
147             .field("iov_len", &self.0.iov_len)
148             .finish()
149     }
150 }
151 
152 impl<'a> Debug for IoBufMut<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result153     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
154         f.debug_struct("IoBufMut")
155             .field("iov", &DebugIovec(self.iov))
156             .field("phantom", &self.phantom)
157             .finish()
158     }
159 }
160