Merge pull request #1717 from bytecodealliance/pch/wiggle_auto_borrow_checking
Automate borrow checking in wiggle
This commit is contained in:
@@ -3,7 +3,7 @@ use crate::handle::{Handle, HandleRights};
|
||||
use crate::wasi::{types, Errno, Result};
|
||||
use std::path::{Component, Path};
|
||||
use std::str;
|
||||
use wiggle::{GuestBorrows, GuestPtr};
|
||||
use wiggle::GuestPtr;
|
||||
|
||||
pub(crate) use crate::sys::path::{from_host, open_rights};
|
||||
|
||||
@@ -14,19 +14,15 @@ pub(crate) fn get(
|
||||
entry: &Entry,
|
||||
required_rights: &HandleRights,
|
||||
dirflags: types::Lookupflags,
|
||||
path: &GuestPtr<'_, str>,
|
||||
path_ptr: &GuestPtr<'_, str>,
|
||||
needs_final_component: bool,
|
||||
) -> Result<(Box<dyn Handle>, String)> {
|
||||
const MAX_SYMLINK_EXPANSIONS: usize = 128;
|
||||
|
||||
// Extract path as &str from guest's memory.
|
||||
let path = unsafe {
|
||||
let mut bc = GuestBorrows::new();
|
||||
let raw = path.as_raw(&mut bc)?;
|
||||
&*raw
|
||||
};
|
||||
let path = path_ptr.as_str()?;
|
||||
|
||||
log::trace!(" | (path_ptr,path_len)='{}'", path);
|
||||
log::trace!(" | (path_ptr,path_len)='{}'", &*path);
|
||||
|
||||
if path.contains('\0') {
|
||||
// if contains NUL, return Ilseq
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::{path, poll};
|
||||
use log::{debug, error, trace};
|
||||
use std::convert::TryInto;
|
||||
use std::io::{self, SeekFrom};
|
||||
use wiggle::{GuestBorrows, GuestPtr};
|
||||
use wiggle::{GuestPtr, GuestSlice};
|
||||
|
||||
impl<'a> WasiSnapshotPreview1 for WasiCtx {
|
||||
fn args_get<'b>(
|
||||
@@ -199,18 +199,11 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
|
||||
iovs: &types::IovecArray<'_>,
|
||||
offset: types::Filesize,
|
||||
) -> Result<types::Size> {
|
||||
let mut buf = Vec::new();
|
||||
let mut bc = GuestBorrows::new();
|
||||
bc.borrow_slice(iovs)?;
|
||||
let mut guest_slices: Vec<GuestSlice<'_, u8>> = Vec::new();
|
||||
for iov_ptr in iovs.iter() {
|
||||
let iov_ptr = iov_ptr?;
|
||||
let iov: types::Iovec = iov_ptr.read()?;
|
||||
let slice = unsafe {
|
||||
let buf = iov.buf.as_array(iov.buf_len);
|
||||
let raw = buf.as_raw(&mut bc)?;
|
||||
&mut *raw
|
||||
};
|
||||
buf.push(io::IoSliceMut::new(slice));
|
||||
guest_slices.push(iov.buf.as_array(iov.buf_len).as_slice()?);
|
||||
}
|
||||
|
||||
let required_rights =
|
||||
@@ -219,10 +212,18 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
|
||||
if offset > i64::max_value() as u64 {
|
||||
return Err(Errno::Io);
|
||||
}
|
||||
let host_nread = entry
|
||||
.as_handle(&required_rights)?
|
||||
.preadv(&mut buf, offset)?
|
||||
.try_into()?;
|
||||
|
||||
let host_nread = {
|
||||
let mut buf = guest_slices
|
||||
.iter_mut()
|
||||
.map(|s| io::IoSliceMut::new(&mut *s))
|
||||
.collect::<Vec<io::IoSliceMut<'_>>>();
|
||||
entry
|
||||
.as_handle(&required_rights)?
|
||||
.preadv(&mut buf, offset)?
|
||||
.try_into()?
|
||||
};
|
||||
drop(guest_slices);
|
||||
Ok(host_nread)
|
||||
}
|
||||
|
||||
@@ -275,18 +276,11 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
|
||||
ciovs: &types::CiovecArray<'_>,
|
||||
offset: types::Filesize,
|
||||
) -> Result<types::Size> {
|
||||
let mut buf = Vec::new();
|
||||
let mut bc = GuestBorrows::new();
|
||||
bc.borrow_slice(ciovs)?;
|
||||
let mut guest_slices = Vec::new();
|
||||
for ciov_ptr in ciovs.iter() {
|
||||
let ciov_ptr = ciov_ptr?;
|
||||
let ciov: types::Ciovec = ciov_ptr.read()?;
|
||||
let slice = unsafe {
|
||||
let buf = ciov.buf.as_array(ciov.buf_len);
|
||||
let raw = buf.as_raw(&mut bc)?;
|
||||
&*raw
|
||||
};
|
||||
buf.push(io::IoSlice::new(slice));
|
||||
guest_slices.push(ciov.buf.as_array(ciov.buf_len).as_slice()?);
|
||||
}
|
||||
|
||||
let required_rights =
|
||||
@@ -297,34 +291,37 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
|
||||
return Err(Errno::Io);
|
||||
}
|
||||
|
||||
let host_nwritten = entry
|
||||
.as_handle(&required_rights)?
|
||||
.pwritev(&buf, offset)?
|
||||
.try_into()?;
|
||||
let host_nwritten = {
|
||||
let buf: Vec<io::IoSlice> =
|
||||
guest_slices.iter().map(|s| io::IoSlice::new(&*s)).collect();
|
||||
entry
|
||||
.as_handle(&required_rights)?
|
||||
.pwritev(&buf, offset)?
|
||||
.try_into()?
|
||||
};
|
||||
Ok(host_nwritten)
|
||||
}
|
||||
|
||||
fn fd_read(&self, fd: types::Fd, iovs: &types::IovecArray<'_>) -> Result<types::Size> {
|
||||
let mut bc = GuestBorrows::new();
|
||||
let mut slices = Vec::new();
|
||||
bc.borrow_slice(&iovs)?;
|
||||
let mut guest_slices = Vec::new();
|
||||
for iov_ptr in iovs.iter() {
|
||||
let iov_ptr = iov_ptr?;
|
||||
let iov: types::Iovec = iov_ptr.read()?;
|
||||
let slice = unsafe {
|
||||
let buf = iov.buf.as_array(iov.buf_len);
|
||||
let raw = buf.as_raw(&mut bc)?;
|
||||
&mut *raw
|
||||
};
|
||||
slices.push(io::IoSliceMut::new(slice));
|
||||
guest_slices.push(iov.buf.as_array(iov.buf_len).as_slice()?);
|
||||
}
|
||||
|
||||
let required_rights = HandleRights::from_base(types::Rights::FD_READ);
|
||||
let entry = self.get_entry(fd)?;
|
||||
let host_nread = entry
|
||||
.as_handle(&required_rights)?
|
||||
.read_vectored(&mut slices)?
|
||||
.try_into()?;
|
||||
let host_nread = {
|
||||
let mut slices: Vec<io::IoSliceMut> = guest_slices
|
||||
.iter_mut()
|
||||
.map(|s| io::IoSliceMut::new(&mut *s))
|
||||
.collect();
|
||||
entry
|
||||
.as_handle(&required_rights)?
|
||||
.read_vectored(&mut slices)?
|
||||
.try_into()?
|
||||
};
|
||||
|
||||
Ok(host_nread)
|
||||
}
|
||||
@@ -423,25 +420,22 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
|
||||
}
|
||||
|
||||
fn fd_write(&self, fd: types::Fd, ciovs: &types::CiovecArray<'_>) -> Result<types::Size> {
|
||||
let mut bc = GuestBorrows::new();
|
||||
let mut slices = Vec::new();
|
||||
bc.borrow_slice(&ciovs)?;
|
||||
let mut guest_slices = Vec::new();
|
||||
for ciov_ptr in ciovs.iter() {
|
||||
let ciov_ptr = ciov_ptr?;
|
||||
let ciov: types::Ciovec = ciov_ptr.read()?;
|
||||
let slice = unsafe {
|
||||
let buf = ciov.buf.as_array(ciov.buf_len);
|
||||
let raw = buf.as_raw(&mut bc)?;
|
||||
&*raw
|
||||
};
|
||||
slices.push(io::IoSlice::new(slice));
|
||||
guest_slices.push(ciov.buf.as_array(ciov.buf_len).as_slice()?);
|
||||
}
|
||||
let required_rights = HandleRights::from_base(types::Rights::FD_WRITE);
|
||||
let entry = self.get_entry(fd)?;
|
||||
let host_nwritten = entry
|
||||
.as_handle(&required_rights)?
|
||||
.write_vectored(&slices)?
|
||||
.try_into()?;
|
||||
let host_nwritten = {
|
||||
let slices: Vec<io::IoSlice> =
|
||||
guest_slices.iter().map(|s| io::IoSlice::new(&*s)).collect();
|
||||
entry
|
||||
.as_handle(&required_rights)?
|
||||
.write_vectored(&slices)?
|
||||
.try_into()?
|
||||
};
|
||||
Ok(host_nwritten)
|
||||
}
|
||||
|
||||
@@ -596,13 +590,8 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
|
||||
path,
|
||||
false,
|
||||
)?;
|
||||
let slice = unsafe {
|
||||
let mut bc = GuestBorrows::new();
|
||||
let buf = buf.as_array(buf_len);
|
||||
let raw = buf.as_raw(&mut bc)?;
|
||||
&mut *raw
|
||||
};
|
||||
let host_bufused = dirfd.readlink(&path, slice)?.try_into()?;
|
||||
let mut slice = buf.as_array(buf_len).as_slice()?;
|
||||
let host_bufused = dirfd.readlink(&path, &mut *slice)?.try_into()?;
|
||||
Ok(host_bufused)
|
||||
}
|
||||
|
||||
@@ -662,12 +651,8 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
|
||||
new_path,
|
||||
true,
|
||||
)?;
|
||||
let old_path = unsafe {
|
||||
let mut bc = GuestBorrows::new();
|
||||
let raw = old_path.as_raw(&mut bc)?;
|
||||
&*raw
|
||||
};
|
||||
trace!(" | old_path='{}'", old_path);
|
||||
let old_path = old_path.as_str()?;
|
||||
trace!(" | old_path='{}'", &*old_path);
|
||||
new_fd.symlink(&old_path, &new_path)
|
||||
}
|
||||
|
||||
@@ -696,9 +681,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
|
||||
}
|
||||
|
||||
let mut subscriptions = Vec::new();
|
||||
let mut bc = GuestBorrows::new();
|
||||
let subs = in_.as_array(nsubscriptions);
|
||||
bc.borrow_slice(&subs)?;
|
||||
for sub_ptr in subs.iter() {
|
||||
let sub_ptr = sub_ptr?;
|
||||
let sub: types::Subscription = sub_ptr.read()?;
|
||||
@@ -793,7 +776,6 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
|
||||
let nevents = events.len().try_into()?;
|
||||
|
||||
let out_events = out.as_array(nevents);
|
||||
bc.borrow_slice(&out_events)?;
|
||||
for (event, event_ptr) in events.into_iter().zip(out_events.iter()) {
|
||||
let event_ptr = event_ptr?;
|
||||
event_ptr.write(event)?;
|
||||
@@ -820,13 +802,8 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
|
||||
}
|
||||
|
||||
fn random_get(&self, buf: &GuestPtr<u8>, buf_len: types::Size) -> Result<()> {
|
||||
let slice = unsafe {
|
||||
let mut bc = GuestBorrows::new();
|
||||
let buf = buf.as_array(buf_len);
|
||||
let raw = buf.as_raw(&mut bc)?;
|
||||
&mut *raw
|
||||
};
|
||||
getrandom::getrandom(slice).map_err(|err| {
|
||||
let mut slice = buf.as_array(buf_len).as_slice()?;
|
||||
getrandom::getrandom(&mut *slice).map_err(|err| {
|
||||
error!("getrandom failure: {:?}", err);
|
||||
Errno::Io
|
||||
})
|
||||
|
||||
@@ -40,6 +40,7 @@ impl From<wiggle::GuestError> for Errno {
|
||||
InFunc { .. } => Self::Inval,
|
||||
InDataField { .. } => Self::Inval,
|
||||
SliceLengthsDiffer { .. } => Self::Fault,
|
||||
BorrowCheckerOutOfHandles { .. } => Self::Fault,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,7 +467,13 @@ pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream {
|
||||
#handle_early_error
|
||||
}
|
||||
};
|
||||
let mem: WasiMemory = mem.into();
|
||||
// Wiggle does not expose any methods for
|
||||
// functions to re-enter the WebAssembly module,
|
||||
// or expose the memory via non-wiggle mechanisms.
|
||||
// Therefore, creating a new BorrowChecker at the
|
||||
// root of each function invocation is correct.
|
||||
let bc = wiggle::BorrowChecker::new();
|
||||
let mem = WasiMemory { mem, bc };
|
||||
wasi_common::wasi::#module_id::#name_ident(
|
||||
&mut my_cx.borrow_mut(),
|
||||
&mem,
|
||||
@@ -484,17 +490,17 @@ pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream {
|
||||
/// Lightweight `wasmtime::Memory` wrapper so that we can
|
||||
/// implement `wiggle::GuestMemory` trait on it which is
|
||||
/// now required to interface with `wasi-common`.
|
||||
struct WasiMemory(wasmtime::Memory);
|
||||
|
||||
impl From<wasmtime::Memory> for WasiMemory {
|
||||
fn from(mem: wasmtime::Memory) -> Self {
|
||||
Self(mem)
|
||||
}
|
||||
struct WasiMemory {
|
||||
mem: wasmtime::Memory,
|
||||
bc: wiggle::BorrowChecker,
|
||||
}
|
||||
|
||||
unsafe impl wiggle::GuestMemory for WasiMemory {
|
||||
fn base(&self) -> (*mut u8, u32) {
|
||||
(self.0.data_ptr(), self.0.data_size() as _)
|
||||
(self.mem.data_ptr(), self.mem.data_size() as _)
|
||||
}
|
||||
fn borrow_checker(&self) -> &wiggle::BorrowChecker {
|
||||
&self.bc
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user