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()
    }
}