1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use crate::ffi::{rust_call, ForeignBytes, RustCallStatus};
6 
7 /// Support for passing an allocated-by-Rust buffer of bytes over the FFI.
8 ///
9 /// We can pass a `Vec<u8>` to foreign language code by decomposing it into
10 /// its raw parts (buffer pointer, length, and capacity) and passing those
11 /// around as a struct. Naturally, this can be tremendously unsafe! So here
12 /// are the details:
13 ///
14 ///   * `RustBuffer` structs must only ever be constructed from a `Vec<u8>`,
15 ///     either explicitly via `RustBuffer::from_vec` or indirectly by calling
16 ///     one of the `RustBuffer::new*` constructors.
17 ///
18 ///   * `RustBuffer` structs do not implement `Drop`, since they are intended
19 ///     to be passed to foreign-language code outside of the control of Rust's
20 ///     ownership system. To avoid memory leaks they *must* passed back into
21 ///     Rust and either explicitly destroyed using `RustBuffer::destroy`, or
22 ///     converted back to a `Vec<u8>` using `RustBuffer::destroy_into_vec`
23 ///     (which will then be dropped via Rust's usual ownership-tracking system).
24 ///
25 /// Foreign-language code should not construct `RustBuffer` structs other than
26 /// by receiving them from a call into the Rust code, and should not modify them
27 /// apart from the following safe operations:
28 ///
29 ///   * Writing bytes into the buffer pointed to by `data`, without writing
30 ///     beyond the indicated `capacity`.
31 ///
32 ///   * Adjusting the `len` property to indicate the amount of data written,
33 ///     while ensuring that 0 <= `len` <= `capacity`.
34 ///
35 ///   * As a special case, constructing a `RustBuffer` with zero capacity, zero
36 ///     length, and a null `data` pointer to indicate an empty buffer.
37 ///
38 /// In particular, it is not safe for foreign-language code to construct a `RustBuffer`
39 /// that points to its own allocated memory; use the `ForeignBytes` struct to
40 /// pass a view of foreign-owned memory in to Rust code.
41 ///
42 /// Implementation note: all the fields of this struct are private, so you can't
43 /// manually construct instances that don't come from a `Vec<u8>`. If you've got
44 /// a `RustBuffer` then it either came from a public constructor (all of which
45 /// are safe) or it came from foreign-language code (which should have in turn
46 /// received it by calling some Rust function, and should be respecting the
47 /// invariants listed above).
48 ///
49 /// This struct is based on `ByteBuffer` from the `ffi-support` crate, but modified
50 /// to retain unallocated capacity rather than truncating to the occupied length.
51 #[repr(C)]
52 #[derive(Debug)]
53 pub struct RustBuffer {
54     /// The allocated capacity of the underlying `Vec<u8>`.
55     /// In Rust this is a `usize`, but we use an `u64` to keep the foreign binding code simple.
56     capacity: u64,
57     /// The occupied length of the underlying `Vec<u8>`.
58     /// In Rust this is a `usize`, but we use an `u64` to keep the foreign binding code simple.
59     len: u64,
60     /// The pointer to the allocated buffer of the `Vec<u8>`.
61     data: *mut u8,
62 }
63 
64 // Mark `RustBuffer` as safe to send between threads, despite the `u8` pointer.  The only mutable
65 // use of that pointer is in `destroy_into_vec()` which requires a &mut on the `RustBuffer`.  This
66 // is required to send `RustBuffer` inside a `RustFuture`
67 unsafe impl Send for RustBuffer {}
68 
69 impl RustBuffer {
70     /// Creates an empty `RustBuffer`.
71     ///
72     /// The buffer will not allocate.
73     /// The resulting vector will not be automatically dropped; you must
74     /// arrange to call `destroy` or `destroy_into_vec` when finished with it.
new() -> Self75     pub fn new() -> Self {
76         Self::from_vec(Vec::new())
77     }
78 
79     /// Creates a `RustBuffer` from its constituent fields.
80     ///
81     /// This is intended mainly as an internal convenience function and should not
82     /// be used outside of this module.
83     ///
84     /// # Safety
85     ///
86     /// You must ensure that the raw parts uphold the documented invariants of this class.
from_raw_parts(data: *mut u8, len: u64, capacity: u64) -> Self87     pub unsafe fn from_raw_parts(data: *mut u8, len: u64, capacity: u64) -> Self {
88         Self {
89             capacity,
90             len,
91             data,
92         }
93     }
94 
95     /// Get the current length of the buffer, as a `usize`.
96     ///
97     /// This is mostly a helper function to convert the `i32` length field
98     /// into a `usize`, which is what Rust code usually expects.
99     ///
100     /// # Panics
101     ///
102     /// Panics if called on an invalid struct obtained from foreign-language code,
103     /// in which the `len` field is negative.
len(&self) -> usize104     pub fn len(&self) -> usize {
105         self.len
106             .try_into()
107             .expect("buffer length negative or overflowed")
108     }
109 
110     /// Get a pointer to the data
data_pointer(&self) -> *const u8111     pub fn data_pointer(&self) -> *const u8 {
112         self.data
113     }
114 
115     /// Returns true if the length of the buffer is 0.
is_empty(&self) -> bool116     pub fn is_empty(&self) -> bool {
117         self.len == 0
118     }
119 
120     /// Creates a `RustBuffer` zero-filed to the requested size.
121     ///
122     /// The resulting vector will not be automatically dropped; you must
123     /// arrange to call `destroy` or `destroy_into_vec` when finished with it.
124     ///
125     /// # Panics
126     ///
127     /// Panics if the requested size is too large to fit in an `i32`, and
128     /// hence would risk incompatibility with some foreign-language code.
new_with_size(size: u64) -> Self129     pub fn new_with_size(size: u64) -> Self {
130         Self::from_vec(vec![0u8; size as usize])
131     }
132 
133     /// Consumes a `Vec<u8>` and returns its raw parts as a `RustBuffer`.
134     ///
135     /// The resulting vector will not be automatically dropped; you must
136     /// arrange to call `destroy` or `destroy_into_vec` when finished with it.
137     ///
138     /// # Panics
139     ///
140     /// Panics if the vector's length or capacity are too large to fit in an `i32`,
141     /// and hence would risk incompatibility with some foreign-language code.
from_vec(v: Vec<u8>) -> Self142     pub fn from_vec(v: Vec<u8>) -> Self {
143         let capacity = u64::try_from(v.capacity()).expect("buffer capacity cannot fit into a u64.");
144         let len = u64::try_from(v.len()).expect("buffer length cannot fit into a u64.");
145         let mut v = std::mem::ManuallyDrop::new(v);
146         unsafe { Self::from_raw_parts(v.as_mut_ptr(), len, capacity) }
147     }
148 
149     /// Converts this `RustBuffer` back into an owned `Vec<u8>`.
150     ///
151     /// This restores ownership of the underlying buffer to Rust, meaning it will
152     /// be dropped when the `Vec<u8>` is dropped. The `RustBuffer` *must* have been
153     /// previously obtained from a valid `Vec<u8>` owned by this Rust code.
154     ///
155     /// # Panics
156     ///
157     /// Panics if called on an invalid struct obtained from foreign-language code,
158     /// which does not respect the invairiants on `len` and `capacity`.
destroy_into_vec(self) -> Vec<u8>159     pub fn destroy_into_vec(self) -> Vec<u8> {
160         // Rust will never give us a null `data` pointer for a `Vec`, but
161         // foreign-language code can use it to cheaply pass an empty buffer.
162         if self.data.is_null() {
163             assert!(self.capacity == 0, "null RustBuffer had non-zero capacity");
164             assert!(self.len == 0, "null RustBuffer had non-zero length");
165             vec![]
166         } else {
167             let capacity: usize = self
168                 .capacity
169                 .try_into()
170                 .expect("buffer capacity negative or overflowed");
171             let len: usize = self
172                 .len
173                 .try_into()
174                 .expect("buffer length negative or overflowed");
175             assert!(len <= capacity, "RustBuffer length exceeds capacity");
176             unsafe { Vec::from_raw_parts(self.data, len, capacity) }
177         }
178     }
179 
180     /// Reclaim memory stored in this `RustBuffer`.
181     ///
182     /// # Panics
183     ///
184     /// Panics if called on an invalid struct obtained from foreign-language code,
185     /// which does not respect the invairiants on `len` and `capacity`.
destroy(self)186     pub fn destroy(self) {
187         drop(self.destroy_into_vec());
188     }
189 }
190 
191 impl Default for RustBuffer {
default() -> Self192     fn default() -> Self {
193         Self::new()
194     }
195 }
196 
197 // Functions for the RustBuffer functionality.
198 //
199 // The scaffolding code re-exports these functions, prefixed with the component name and UDL hash
200 // This creates a separate set of functions for each UniFFIed component, which is needed in the
201 // case where we create multiple dylib artifacts since each dylib will have its own allocator.
202 
203 /// This helper allocates a new byte buffer owned by the Rust code, and returns it
204 /// to the foreign-language code as a `RustBuffer` struct. Callers must eventually
205 /// free the resulting buffer, either by explicitly calling [`uniffi_rustbuffer_free`] defined
206 /// below, or by passing ownership of the buffer back into Rust code.
uniffi_rustbuffer_alloc(size: u64, call_status: &mut RustCallStatus) -> RustBuffer207 pub fn uniffi_rustbuffer_alloc(size: u64, call_status: &mut RustCallStatus) -> RustBuffer {
208     rust_call(call_status, || Ok(RustBuffer::new_with_size(size)))
209 }
210 
211 /// This helper copies bytes owned by the foreign-language code into a new byte buffer owned
212 /// by the Rust code, and returns it as a `RustBuffer` struct. Callers must eventually
213 /// free the resulting buffer, either by explicitly calling the destructor defined below,
214 /// or by passing ownership of the buffer back into Rust code.
215 ///
216 /// # Safety
217 /// This function will dereference a provided pointer in order to copy bytes from it, so
218 /// make sure the `ForeignBytes` struct contains a valid pointer and length.
uniffi_rustbuffer_from_bytes( bytes: ForeignBytes, call_status: &mut RustCallStatus, ) -> RustBuffer219 pub fn uniffi_rustbuffer_from_bytes(
220     bytes: ForeignBytes,
221     call_status: &mut RustCallStatus,
222 ) -> RustBuffer {
223     rust_call(call_status, || {
224         let bytes = bytes.as_slice();
225         Ok(RustBuffer::from_vec(bytes.to_vec()))
226     })
227 }
228 
229 /// Free a byte buffer that had previously been passed to the foreign language code.
230 ///
231 /// # Safety
232 /// The argument *must* be a uniquely-owned `RustBuffer` previously obtained from a call
233 /// into the Rust code that returned a buffer, or you'll risk freeing unowned memory or
234 /// corrupting the allocator state.
uniffi_rustbuffer_free(buf: RustBuffer, call_status: &mut RustCallStatus)235 pub fn uniffi_rustbuffer_free(buf: RustBuffer, call_status: &mut RustCallStatus) {
236     rust_call(call_status, || {
237         RustBuffer::destroy(buf);
238         Ok(())
239     })
240 }
241 
242 /// Reserve additional capacity in a byte buffer that had previously been passed to the
243 /// foreign language code.
244 ///
245 /// The first argument *must* be a uniquely-owned `RustBuffer` previously
246 /// obtained from a call into the Rust code that returned a buffer. Its underlying data pointer
247 /// will be reallocated if necessary and returned in a new `RustBuffer` struct.
248 ///
249 /// The second argument must be the minimum number of *additional* bytes to reserve
250 /// capacity for in the buffer; it is likely to reserve additional capacity in practice
251 /// due to amortized growth strategy of Rust vectors.
252 ///
253 /// # Safety
254 /// The first argument *must* be a uniquely-owned `RustBuffer` previously obtained from a call
255 /// into the Rust code that returned a buffer, or you'll risk freeing unowned memory or
256 /// corrupting the allocator state.
uniffi_rustbuffer_reserve( buf: RustBuffer, additional: u64, call_status: &mut RustCallStatus, ) -> RustBuffer257 pub fn uniffi_rustbuffer_reserve(
258     buf: RustBuffer,
259     additional: u64,
260     call_status: &mut RustCallStatus,
261 ) -> RustBuffer {
262     rust_call(call_status, || {
263         let additional: usize = additional
264             .try_into()
265             .expect("additional buffer length negative or overflowed");
266         let mut v = buf.destroy_into_vec();
267         v.reserve(additional);
268         Ok(RustBuffer::from_vec(v))
269     })
270 }
271 
272 #[cfg(test)]
273 mod test {
274     use super::*;
275     #[test]
test_rustbuffer_from_vec()276     fn test_rustbuffer_from_vec() {
277         let rbuf = RustBuffer::from_vec(vec![1u8, 2, 3]);
278         assert_eq!(rbuf.len(), 3);
279         assert_eq!(rbuf.destroy_into_vec(), vec![1u8, 2, 3]);
280     }
281 
282     #[test]
test_rustbuffer_empty()283     fn test_rustbuffer_empty() {
284         let rbuf = RustBuffer::new();
285         assert_eq!(rbuf.len(), 0);
286         // Rust will never give us a null pointer, even for an empty buffer.
287         assert!(!rbuf.data.is_null());
288         assert_eq!(rbuf.destroy_into_vec(), Vec::<u8>::new());
289     }
290 
291     #[test]
test_rustbuffer_new_with_size()292     fn test_rustbuffer_new_with_size() {
293         let rbuf = RustBuffer::new_with_size(5);
294         assert_eq!(rbuf.destroy_into_vec().as_slice(), &[0u8, 0, 0, 0, 0]);
295 
296         let rbuf = RustBuffer::new_with_size(0);
297         assert!(!rbuf.data.is_null());
298         assert_eq!(rbuf.destroy_into_vec().as_slice(), &[0u8; 0]);
299     }
300 
301     #[test]
test_rustbuffer_null_means_empty()302     fn test_rustbuffer_null_means_empty() {
303         // This is how foreign-language code might cheaply indicate an empty buffer.
304         let rbuf = unsafe { RustBuffer::from_raw_parts(std::ptr::null_mut(), 0, 0) };
305         assert_eq!(rbuf.destroy_into_vec().as_slice(), &[0u8; 0]);
306     }
307 
308     #[test]
309     #[should_panic]
test_rustbuffer_null_must_have_no_capacity()310     fn test_rustbuffer_null_must_have_no_capacity() {
311         // We guard against foreign-language code providing this kind of invalid struct.
312         let rbuf = unsafe { RustBuffer::from_raw_parts(std::ptr::null_mut(), 0, 1) };
313         rbuf.destroy_into_vec();
314     }
315     #[test]
316     #[should_panic]
test_rustbuffer_null_must_have_zero_length()317     fn test_rustbuffer_null_must_have_zero_length() {
318         // We guard against foreign-language code providing this kind of invalid struct.
319         let rbuf = unsafe { RustBuffer::from_raw_parts(std::ptr::null_mut(), 12, 0) };
320         rbuf.destroy_into_vec();
321     }
322 
323     #[test]
324     #[should_panic]
test_rustbuffer_provided_len_must_not_exceed_capacity()325     fn test_rustbuffer_provided_len_must_not_exceed_capacity() {
326         // We guard against foreign-language code providing this kind of invalid struct.
327         let mut v = vec![0u8, 1, 2];
328         let rbuf = unsafe { RustBuffer::from_raw_parts(v.as_mut_ptr(), 3, 2) };
329         rbuf.destroy_into_vec();
330     }
331 }
332