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