wiggle: automate borrow checking, explicitly passing borrow checker throughout
This commit is contained in:
@@ -24,7 +24,9 @@ pub fn define_func(
|
|||||||
});
|
});
|
||||||
|
|
||||||
let abi_args = quote!(
|
let abi_args = quote!(
|
||||||
ctx: &#ctx_type, memory: &dyn #rt::GuestMemory,
|
ctx: &#ctx_type,
|
||||||
|
memory: &dyn #rt::GuestMemory,
|
||||||
|
bc: &#rt::BorrowChecker,
|
||||||
#(#params),*
|
#(#params),*
|
||||||
);
|
);
|
||||||
let abi_ret = if let Some(ret) = &coretype.ret {
|
let abi_ret = if let Some(ret) = &coretype.ret {
|
||||||
@@ -210,7 +212,7 @@ fn marshal_arg(
|
|||||||
let arg_name = names.func_ptr_binding(¶m.name);
|
let arg_name = names.func_ptr_binding(¶m.name);
|
||||||
let name = names.func_param(¶m.name);
|
let name = names.func_param(¶m.name);
|
||||||
quote! {
|
quote! {
|
||||||
let #name = match #rt::GuestPtr::<#pointee_type>::new(memory, #arg_name as u32).read() {
|
let #name = match #rt::GuestPtr::<#pointee_type>::new(memory, bc, #arg_name as u32).read() {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
#error_handling
|
#error_handling
|
||||||
@@ -256,7 +258,7 @@ fn marshal_arg(
|
|||||||
let len_name = names.func_len_binding(¶m.name);
|
let len_name = names.func_len_binding(¶m.name);
|
||||||
let name = names.func_param(¶m.name);
|
let name = names.func_param(¶m.name);
|
||||||
quote! {
|
quote! {
|
||||||
let #name = #rt::GuestPtr::<#lifetime, str>::new(memory, (#ptr_name as u32, #len_name as u32));
|
let #name = #rt::GuestPtr::<#lifetime, str>::new(memory, bc, (#ptr_name as u32, #len_name as u32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -264,7 +266,7 @@ fn marshal_arg(
|
|||||||
let pointee_type = names.type_ref(pointee, anon_lifetime());
|
let pointee_type = names.type_ref(pointee, anon_lifetime());
|
||||||
let name = names.func_param(¶m.name);
|
let name = names.func_param(¶m.name);
|
||||||
quote! {
|
quote! {
|
||||||
let #name = #rt::GuestPtr::<#pointee_type>::new(memory, #name as u32);
|
let #name = #rt::GuestPtr::<#pointee_type>::new(memory, bc, #name as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
witx::Type::Struct(_) => read_conversion,
|
witx::Type::Struct(_) => read_conversion,
|
||||||
@@ -274,7 +276,7 @@ fn marshal_arg(
|
|||||||
let len_name = names.func_len_binding(¶m.name);
|
let len_name = names.func_len_binding(¶m.name);
|
||||||
let name = names.func_param(¶m.name);
|
let name = names.func_param(¶m.name);
|
||||||
quote! {
|
quote! {
|
||||||
let #name = #rt::GuestPtr::<[#pointee_type]>::new(memory, (#ptr_name as u32, #len_name as u32));
|
let #name = #rt::GuestPtr::<[#pointee_type]>::new(memory, bc, (#ptr_name as u32, #len_name as u32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
witx::Type::Union(_u) => read_conversion,
|
witx::Type::Union(_u) => read_conversion,
|
||||||
@@ -303,7 +305,7 @@ where
|
|||||||
let ptr_name = names.func_ptr_binding(&result.name);
|
let ptr_name = names.func_ptr_binding(&result.name);
|
||||||
let ptr_err_handling = error_handling(&format!("{}:result_ptr_mut", result.name.as_str()));
|
let ptr_err_handling = error_handling(&format!("{}:result_ptr_mut", result.name.as_str()));
|
||||||
let pre = quote! {
|
let pre = quote! {
|
||||||
let #ptr_name = #rt::GuestPtr::<#pointee_type>::new(memory, #ptr_name as u32);
|
let #ptr_name = #rt::GuestPtr::<#pointee_type>::new(memory, bc, #ptr_name as u32);
|
||||||
};
|
};
|
||||||
// trait binding returns func_param name.
|
// trait binding returns func_param name.
|
||||||
let val_name = names.func_param(&result.name);
|
let val_name = names.func_param(&result.name);
|
||||||
|
|||||||
@@ -1,64 +1,67 @@
|
|||||||
|
use crate::error::GuestError;
|
||||||
use crate::region::Region;
|
use crate::region::Region;
|
||||||
use crate::{GuestError, GuestPtr, GuestType};
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct GuestBorrows {
|
pub struct BorrowHandle(usize);
|
||||||
borrows: Vec<Region>,
|
|
||||||
|
pub struct BorrowChecker {
|
||||||
|
bc: RefCell<InnerBorrowChecker>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GuestBorrows {
|
impl BorrowChecker {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
BorrowChecker {
|
||||||
borrows: Vec::new(),
|
bc: RefCell::new(InnerBorrowChecker::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn borrow(&self, r: Region) -> Result<BorrowHandle, GuestError> {
|
||||||
|
self.bc
|
||||||
|
.borrow_mut()
|
||||||
|
.borrow(r)
|
||||||
|
.ok_or_else(|| GuestError::PtrBorrowed(r))
|
||||||
|
}
|
||||||
|
pub fn unborrow(&self, h: BorrowHandle) {
|
||||||
|
self.bc.borrow_mut().unborrow(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct InnerBorrowChecker {
|
||||||
|
borrows: HashMap<BorrowHandle, Region>,
|
||||||
|
next_handle: BorrowHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InnerBorrowChecker {
|
||||||
|
fn new() -> Self {
|
||||||
|
InnerBorrowChecker {
|
||||||
|
borrows: HashMap::new(),
|
||||||
|
next_handle: BorrowHandle(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_borrowed(&self, r: Region) -> bool {
|
fn is_borrowed(&self, r: Region) -> bool {
|
||||||
!self.borrows.iter().all(|b| !b.overlaps(r))
|
!self.borrows.values().all(|b| !b.overlaps(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn borrow(&mut self, r: Region) -> Result<(), GuestError> {
|
fn new_handle(&mut self) -> BorrowHandle {
|
||||||
|
let h = self.next_handle;
|
||||||
|
self.next_handle = BorrowHandle(h.0 + 1);
|
||||||
|
h
|
||||||
|
}
|
||||||
|
|
||||||
|
fn borrow(&mut self, r: Region) -> Option<BorrowHandle> {
|
||||||
if self.is_borrowed(r) {
|
if self.is_borrowed(r) {
|
||||||
Err(GuestError::PtrBorrowed(r))
|
return None;
|
||||||
} else {
|
|
||||||
self.borrows.push(r);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
let h = self.new_handle();
|
||||||
|
self.borrows.insert(h, r);
|
||||||
|
Some(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrow the region of memory pointed to by a `GuestPtr`. This is required for safety if
|
fn unborrow(&mut self, h: BorrowHandle) {
|
||||||
/// you are dereferencing `GuestPtr`s while holding a reference to a slice via
|
let _ = self.borrows.remove(&h);
|
||||||
/// `GuestPtr::as_raw`.
|
|
||||||
pub fn borrow_pointee<'a, T>(&mut self, p: &GuestPtr<'a, T>) -> Result<(), GuestError>
|
|
||||||
where
|
|
||||||
T: GuestType<'a>,
|
|
||||||
{
|
|
||||||
self.borrow(Region {
|
|
||||||
start: p.offset(),
|
|
||||||
len: T::guest_size(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Borrow the slice of memory pointed to by a `GuestPtr<[T]>`. This is required for safety if
|
|
||||||
/// you are dereferencing the `GuestPtr`s while holding a reference to another slice via
|
|
||||||
/// `GuestPtr::as_raw`. Not required if using `GuestPtr::as_raw` on this pointer.
|
|
||||||
pub fn borrow_slice<'a, T>(&mut self, p: &GuestPtr<'a, [T]>) -> Result<(), GuestError>
|
|
||||||
where
|
|
||||||
T: GuestType<'a>,
|
|
||||||
{
|
|
||||||
let (start, elems) = p.offset();
|
|
||||||
let len = T::guest_size()
|
|
||||||
.checked_mul(elems)
|
|
||||||
.ok_or_else(|| GuestError::PtrOverflow)?;
|
|
||||||
self.borrow(Region { start, len })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Borrow the slice of memory pointed to by a `GuestPtr<str>`. This is required for safety if
|
|
||||||
/// you are dereferencing the `GuestPtr`s while holding a reference to another slice via
|
|
||||||
/// `GuestPtr::as_raw`. Not required if using `GuestPtr::as_raw` on this pointer.
|
|
||||||
pub fn borrow_str(&mut self, p: &GuestPtr<str>) -> Result<(), GuestError> {
|
|
||||||
let (start, len) = p.offset();
|
|
||||||
self.borrow(Region { start, len })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,14 +70,14 @@ mod test {
|
|||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
#[test]
|
||||||
fn nonoverlapping() {
|
fn nonoverlapping() {
|
||||||
let mut bs = GuestBorrows::new();
|
let mut bs = InnerBorrowChecker::new();
|
||||||
let r1 = Region::new(0, 10);
|
let r1 = Region::new(0, 10);
|
||||||
let r2 = Region::new(10, 10);
|
let r2 = Region::new(10, 10);
|
||||||
assert!(!r1.overlaps(r2));
|
assert!(!r1.overlaps(r2));
|
||||||
bs.borrow(r1).expect("can borrow r1");
|
bs.borrow(r1).expect("can borrow r1");
|
||||||
bs.borrow(r2).expect("can borrow r2");
|
bs.borrow(r2).expect("can borrow r2");
|
||||||
|
|
||||||
let mut bs = GuestBorrows::new();
|
let mut bs = InnerBorrowChecker::new();
|
||||||
let r1 = Region::new(10, 10);
|
let r1 = Region::new(10, 10);
|
||||||
let r2 = Region::new(0, 10);
|
let r2 = Region::new(0, 10);
|
||||||
assert!(!r1.overlaps(r2));
|
assert!(!r1.overlaps(r2));
|
||||||
@@ -84,35 +87,35 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn overlapping() {
|
fn overlapping() {
|
||||||
let mut bs = GuestBorrows::new();
|
let mut bs = InnerBorrowChecker::new();
|
||||||
let r1 = Region::new(0, 10);
|
let r1 = Region::new(0, 10);
|
||||||
let r2 = Region::new(9, 10);
|
let r2 = Region::new(9, 10);
|
||||||
assert!(r1.overlaps(r2));
|
assert!(r1.overlaps(r2));
|
||||||
bs.borrow(r1).expect("can borrow r1");
|
bs.borrow(r1).expect("can borrow r1");
|
||||||
assert!(bs.borrow(r2).is_err(), "cant borrow r2");
|
assert!(bs.borrow(r2).is_none(), "cant borrow r2");
|
||||||
|
|
||||||
let mut bs = GuestBorrows::new();
|
let mut bs = InnerBorrowChecker::new();
|
||||||
let r1 = Region::new(0, 10);
|
let r1 = Region::new(0, 10);
|
||||||
let r2 = Region::new(2, 5);
|
let r2 = Region::new(2, 5);
|
||||||
assert!(r1.overlaps(r2));
|
assert!(r1.overlaps(r2));
|
||||||
bs.borrow(r1).expect("can borrow r1");
|
bs.borrow(r1).expect("can borrow r1");
|
||||||
assert!(bs.borrow(r2).is_err(), "cant borrow r2");
|
assert!(bs.borrow(r2).is_none(), "cant borrow r2");
|
||||||
|
|
||||||
let mut bs = GuestBorrows::new();
|
let mut bs = InnerBorrowChecker::new();
|
||||||
let r1 = Region::new(9, 10);
|
let r1 = Region::new(9, 10);
|
||||||
let r2 = Region::new(0, 10);
|
let r2 = Region::new(0, 10);
|
||||||
assert!(r1.overlaps(r2));
|
assert!(r1.overlaps(r2));
|
||||||
bs.borrow(r1).expect("can borrow r1");
|
bs.borrow(r1).expect("can borrow r1");
|
||||||
assert!(bs.borrow(r2).is_err(), "cant borrow r2");
|
assert!(bs.borrow(r2).is_none(), "cant borrow r2");
|
||||||
|
|
||||||
let mut bs = GuestBorrows::new();
|
let mut bs = InnerBorrowChecker::new();
|
||||||
let r1 = Region::new(2, 5);
|
let r1 = Region::new(2, 5);
|
||||||
let r2 = Region::new(0, 10);
|
let r2 = Region::new(0, 10);
|
||||||
assert!(r1.overlaps(r2));
|
assert!(r1.overlaps(r2));
|
||||||
bs.borrow(r1).expect("can borrow r1");
|
bs.borrow(r1).expect("can borrow r1");
|
||||||
assert!(bs.borrow(r2).is_err(), "cant borrow r2");
|
assert!(bs.borrow(r2).is_none(), "cant borrow r2");
|
||||||
|
|
||||||
let mut bs = GuestBorrows::new();
|
let mut bs = InnerBorrowChecker::new();
|
||||||
let r1 = Region::new(2, 5);
|
let r1 = Region::new(2, 5);
|
||||||
let r2 = Region::new(10, 5);
|
let r2 = Region::new(10, 5);
|
||||||
let r3 = Region::new(15, 5);
|
let r3 = Region::new(15, 5);
|
||||||
@@ -121,6 +124,23 @@ mod test {
|
|||||||
bs.borrow(r1).expect("can borrow r1");
|
bs.borrow(r1).expect("can borrow r1");
|
||||||
bs.borrow(r2).expect("can borrow r2");
|
bs.borrow(r2).expect("can borrow r2");
|
||||||
bs.borrow(r3).expect("can borrow r3");
|
bs.borrow(r3).expect("can borrow r3");
|
||||||
assert!(bs.borrow(r4).is_err(), "cant borrow r4");
|
assert!(bs.borrow(r4).is_none(), "cant borrow r4");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unborrowing() {
|
||||||
|
let mut bs = InnerBorrowChecker::new();
|
||||||
|
let r1 = Region::new(0, 10);
|
||||||
|
let r2 = Region::new(10, 10);
|
||||||
|
assert!(!r1.overlaps(r2));
|
||||||
|
let _h1 = bs.borrow(r1).expect("can borrow r1");
|
||||||
|
let h2 = bs.borrow(r2).expect("can borrow r2");
|
||||||
|
|
||||||
|
assert!(bs.borrow(r2).is_none(), "can't borrow r2 twice");
|
||||||
|
bs.unborrow(h2);
|
||||||
|
|
||||||
|
let _h3 = bs
|
||||||
|
.borrow(r2)
|
||||||
|
.expect("can borrow r2 again now that its been unborrowed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ impl<'a, T> GuestType<'a> for GuestPtr<'a, T> {
|
|||||||
|
|
||||||
fn read(ptr: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
|
fn read(ptr: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
|
||||||
let offset = ptr.cast::<u32>().read()?;
|
let offset = ptr.cast::<u32>().read()?;
|
||||||
Ok(GuestPtr::new(ptr.mem(), offset))
|
Ok(GuestPtr::new(ptr.mem(), ptr.borrow_checker(), offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError> {
|
fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError> {
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ mod error;
|
|||||||
mod guest_type;
|
mod guest_type;
|
||||||
mod region;
|
mod region;
|
||||||
|
|
||||||
pub use borrow::GuestBorrows;
|
pub use borrow::BorrowChecker;
|
||||||
|
use borrow::BorrowHandle;
|
||||||
pub use error::GuestError;
|
pub use error::GuestError;
|
||||||
pub use guest_type::{GuestErrorType, GuestType, GuestTypeTransparent};
|
pub use guest_type::{GuestErrorType, GuestType, GuestTypeTransparent};
|
||||||
pub use region::Region;
|
pub use region::Region;
|
||||||
@@ -150,12 +151,12 @@ pub unsafe trait GuestMemory {
|
|||||||
/// Note that `T` can be almost any type, and typically `offset` is a `u32`.
|
/// Note that `T` can be almost any type, and typically `offset` is a `u32`.
|
||||||
/// The exception is slices and strings, in which case `offset` is a `(u32,
|
/// The exception is slices and strings, in which case `offset` is a `(u32,
|
||||||
/// u32)` of `(offset, length)`.
|
/// u32)` of `(offset, length)`.
|
||||||
fn ptr<'a, T>(&'a self, offset: T::Pointer) -> GuestPtr<'a, T>
|
fn ptr<'a, T>(&'a self, bc: &'a BorrowChecker, offset: T::Pointer) -> GuestPtr<'a, T>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
T: ?Sized + Pointee,
|
T: ?Sized + Pointee,
|
||||||
{
|
{
|
||||||
GuestPtr::new(self, offset)
|
GuestPtr::new(self, bc, offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,6 +238,7 @@ unsafe impl<T: ?Sized + GuestMemory> GuestMemory for Arc<T> {
|
|||||||
/// already-attached helper methods.
|
/// already-attached helper methods.
|
||||||
pub struct GuestPtr<'a, T: ?Sized + Pointee> {
|
pub struct GuestPtr<'a, T: ?Sized + Pointee> {
|
||||||
mem: &'a (dyn GuestMemory + 'a),
|
mem: &'a (dyn GuestMemory + 'a),
|
||||||
|
bc: &'a BorrowChecker,
|
||||||
pointer: T::Pointer,
|
pointer: T::Pointer,
|
||||||
_marker: marker::PhantomData<&'a Cell<T>>,
|
_marker: marker::PhantomData<&'a Cell<T>>,
|
||||||
}
|
}
|
||||||
@@ -247,9 +249,14 @@ impl<'a, T: ?Sized + Pointee> GuestPtr<'a, T> {
|
|||||||
/// Note that for sized types like `u32`, `GuestPtr<T>`, etc, the `pointer`
|
/// Note that for sized types like `u32`, `GuestPtr<T>`, etc, the `pointer`
|
||||||
/// vlue is a `u32` offset into guest memory. For slices and strings,
|
/// vlue is a `u32` offset into guest memory. For slices and strings,
|
||||||
/// `pointer` is a `(u32, u32)` offset/length pair.
|
/// `pointer` is a `(u32, u32)` offset/length pair.
|
||||||
pub fn new(mem: &'a (dyn GuestMemory + 'a), pointer: T::Pointer) -> GuestPtr<'_, T> {
|
pub fn new(
|
||||||
|
mem: &'a (dyn GuestMemory + 'a),
|
||||||
|
bc: &'a BorrowChecker,
|
||||||
|
pointer: T::Pointer,
|
||||||
|
) -> GuestPtr<'a, T> {
|
||||||
GuestPtr {
|
GuestPtr {
|
||||||
mem,
|
mem,
|
||||||
|
bc,
|
||||||
pointer,
|
pointer,
|
||||||
_marker: marker::PhantomData,
|
_marker: marker::PhantomData,
|
||||||
}
|
}
|
||||||
@@ -268,6 +275,11 @@ impl<'a, T: ?Sized + Pointee> GuestPtr<'a, T> {
|
|||||||
self.mem
|
self.mem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the borrow checker that this pointer uses
|
||||||
|
pub fn borrow_checker(&self) -> &'a BorrowChecker {
|
||||||
|
self.bc
|
||||||
|
}
|
||||||
|
|
||||||
/// Casts this `GuestPtr` type to a different type.
|
/// Casts this `GuestPtr` type to a different type.
|
||||||
///
|
///
|
||||||
/// This is a safe method which is useful for simply reinterpreting the type
|
/// This is a safe method which is useful for simply reinterpreting the type
|
||||||
@@ -278,7 +290,7 @@ impl<'a, T: ?Sized + Pointee> GuestPtr<'a, T> {
|
|||||||
where
|
where
|
||||||
T: Pointee<Pointer = u32>,
|
T: Pointee<Pointer = u32>,
|
||||||
{
|
{
|
||||||
GuestPtr::new(self.mem, self.pointer)
|
GuestPtr::new(self.mem, self.bc, self.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Safely read a value from this pointer.
|
/// Safely read a value from this pointer.
|
||||||
@@ -345,7 +357,7 @@ impl<'a, T: ?Sized + Pointee> GuestPtr<'a, T> {
|
|||||||
Some(o) => o,
|
Some(o) => o,
|
||||||
None => return Err(GuestError::PtrOverflow),
|
None => return Err(GuestError::PtrOverflow),
|
||||||
};
|
};
|
||||||
Ok(GuestPtr::new(self.mem, offset))
|
Ok(GuestPtr::new(self.mem, self.bc, offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a `GuestPtr` for an array of `T`s using this pointer as the
|
/// Returns a `GuestPtr` for an array of `T`s using this pointer as the
|
||||||
@@ -354,7 +366,7 @@ impl<'a, T: ?Sized + Pointee> GuestPtr<'a, T> {
|
|||||||
where
|
where
|
||||||
T: GuestType<'a> + Pointee<Pointer = u32>,
|
T: GuestType<'a> + Pointee<Pointer = u32>,
|
||||||
{
|
{
|
||||||
GuestPtr::new(self.mem, (self.pointer, elems))
|
GuestPtr::new(self.mem, self.bc, (self.pointer, elems))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,7 +415,7 @@ impl<'a, T> GuestPtr<'a, [T]> {
|
|||||||
/// For safety against overlapping mutable borrows, the user must use the
|
/// For safety against overlapping mutable borrows, the user must use the
|
||||||
/// same `GuestBorrows` to create all `*mut str` or `*mut [T]` that are alive
|
/// same `GuestBorrows` to create all `*mut str` or `*mut [T]` that are alive
|
||||||
/// at the same time.
|
/// at the same time.
|
||||||
pub fn as_raw(&self, bc: &mut GuestBorrows) -> Result<*mut [T], GuestError>
|
pub fn as_slice(&self) -> Result<GuestSlice<'a, T>, GuestError>
|
||||||
where
|
where
|
||||||
T: GuestTypeTransparent<'a>,
|
T: GuestTypeTransparent<'a>,
|
||||||
{
|
{
|
||||||
@@ -415,7 +427,7 @@ impl<'a, T> GuestPtr<'a, [T]> {
|
|||||||
self.mem
|
self.mem
|
||||||
.validate_size_align(self.pointer.0, T::guest_align(), len)? as *mut T;
|
.validate_size_align(self.pointer.0, T::guest_align(), len)? as *mut T;
|
||||||
|
|
||||||
bc.borrow(Region {
|
let borrow = self.bc.borrow(Region {
|
||||||
start: self.pointer.0,
|
start: self.pointer.0,
|
||||||
len,
|
len,
|
||||||
})?;
|
})?;
|
||||||
@@ -428,10 +440,16 @@ impl<'a, T> GuestPtr<'a, [T]> {
|
|||||||
|
|
||||||
// SAFETY: iff there are no overlapping borrows (all uses of as_raw use this same
|
// SAFETY: iff there are no overlapping borrows (all uses of as_raw use this same
|
||||||
// GuestBorrows), its valid to construct a *mut [T]
|
// GuestBorrows), its valid to construct a *mut [T]
|
||||||
unsafe {
|
let ptr = unsafe {
|
||||||
let s = slice::from_raw_parts_mut(ptr, self.pointer.1 as usize);
|
let s = slice::from_raw_parts_mut(ptr, self.pointer.1 as usize);
|
||||||
Ok(s as *mut [T])
|
s as *mut [T]
|
||||||
}
|
};
|
||||||
|
|
||||||
|
Ok(GuestSlice {
|
||||||
|
ptr,
|
||||||
|
bc: self.bc,
|
||||||
|
borrow,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copies the data pointed to by `slice` into this guest region.
|
/// Copies the data pointed to by `slice` into this guest region.
|
||||||
@@ -451,22 +469,20 @@ impl<'a, T> GuestPtr<'a, [T]> {
|
|||||||
T: GuestTypeTransparent<'a> + Copy,
|
T: GuestTypeTransparent<'a> + Copy,
|
||||||
{
|
{
|
||||||
// bounds check ...
|
// bounds check ...
|
||||||
let raw = self.as_raw(&mut GuestBorrows::new())?;
|
let mut self_slice = self.as_slice()?;
|
||||||
unsafe {
|
|
||||||
// ... length check ...
|
// ... length check ...
|
||||||
if (*raw).len() != slice.len() {
|
if self_slice.len() != slice.len() {
|
||||||
return Err(GuestError::SliceLengthsDiffer);
|
return Err(GuestError::SliceLengthsDiffer);
|
||||||
}
|
}
|
||||||
// ... and copy!
|
// ... and copy!
|
||||||
(*raw).copy_from_slice(slice);
|
self_slice.copy_from_slice(slice);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a `GuestPtr` pointing to the base of the array for the interior
|
/// Returns a `GuestPtr` pointing to the base of the array for the interior
|
||||||
/// type `T`.
|
/// type `T`.
|
||||||
pub fn as_ptr(&self) -> GuestPtr<'a, T> {
|
pub fn as_ptr(&self) -> GuestPtr<'a, T> {
|
||||||
GuestPtr::new(self.mem, self.offset_base())
|
GuestPtr::new(self.mem, self.bc, self.offset_base())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,7 +501,7 @@ impl<'a> GuestPtr<'a, str> {
|
|||||||
/// Returns a raw pointer for the underlying slice of bytes that this
|
/// Returns a raw pointer for the underlying slice of bytes that this
|
||||||
/// pointer points to.
|
/// pointer points to.
|
||||||
pub fn as_bytes(&self) -> GuestPtr<'a, [u8]> {
|
pub fn as_bytes(&self) -> GuestPtr<'a, [u8]> {
|
||||||
GuestPtr::new(self.mem, self.pointer)
|
GuestPtr::new(self.mem, self.bc, self.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to read a raw `*mut str` pointer from this pointer, performing
|
/// Attempts to read a raw `*mut str` pointer from this pointer, performing
|
||||||
@@ -505,26 +521,28 @@ impl<'a> GuestPtr<'a, str> {
|
|||||||
/// For safety against overlapping mutable borrows, the user must use the
|
/// For safety against overlapping mutable borrows, the user must use the
|
||||||
/// same `GuestBorrows` to create all `*mut str` or `*mut [T]` that are
|
/// same `GuestBorrows` to create all `*mut str` or `*mut [T]` that are
|
||||||
/// alive at the same time.
|
/// alive at the same time.
|
||||||
pub fn as_raw(&self, bc: &mut GuestBorrows) -> Result<*mut str, GuestError> {
|
pub fn as_str(&self) -> Result<GuestStr<'a>, GuestError> {
|
||||||
let ptr = self
|
let ptr = self
|
||||||
.mem
|
.mem
|
||||||
.validate_size_align(self.pointer.0, 1, self.pointer.1)?;
|
.validate_size_align(self.pointer.0, 1, self.pointer.1)?;
|
||||||
|
|
||||||
bc.borrow(Region {
|
let borrow = self.bc.borrow(Region {
|
||||||
start: self.pointer.0,
|
start: self.pointer.0,
|
||||||
len: self.pointer.1,
|
len: self.pointer.1,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// SAFETY: iff there are no overlapping borrows (all uses of as_raw use this same
|
// SAFETY: iff there are no overlapping borrows (all uses of as_raw use this same
|
||||||
// GuestBorrows), its valid to construct a *mut str
|
// GuestBorrows), its valid to construct a *mut str
|
||||||
unsafe {
|
let ptr = unsafe { slice::from_raw_parts_mut(ptr, self.pointer.1 as usize) };
|
||||||
let s = slice::from_raw_parts_mut(ptr, self.pointer.1 as usize);
|
match str::from_utf8_mut(ptr) {
|
||||||
match str::from_utf8_mut(s) {
|
Ok(ptr) => Ok(GuestStr {
|
||||||
Ok(s) => Ok(s),
|
ptr,
|
||||||
|
bc: self.bc,
|
||||||
|
borrow,
|
||||||
|
}),
|
||||||
Err(e) => Err(GuestError::InvalidUtf8(e)),
|
Err(e) => Err(GuestError::InvalidUtf8(e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized + Pointee> Clone for GuestPtr<'_, T> {
|
impl<T: ?Sized + Pointee> Clone for GuestPtr<'_, T> {
|
||||||
@@ -541,6 +559,56 @@ impl<T: ?Sized + Pointee> fmt::Debug for GuestPtr<'_, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct GuestSlice<'a, T> {
|
||||||
|
ptr: *mut [T],
|
||||||
|
bc: &'a BorrowChecker,
|
||||||
|
borrow: BorrowHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> std::ops::Deref for GuestSlice<'a, T> {
|
||||||
|
type Target = [T];
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { self.ptr.as_ref().expect("ptr guaranteed to be non-null") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> std::ops::DerefMut for GuestSlice<'a, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { self.ptr.as_mut().expect("ptr guaranteed to be non-null") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Drop for GuestSlice<'a, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.bc.unborrow(self.borrow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GuestStr<'a> {
|
||||||
|
ptr: *mut str,
|
||||||
|
bc: &'a BorrowChecker,
|
||||||
|
borrow: BorrowHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::ops::Deref for GuestStr<'a> {
|
||||||
|
type Target = str;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { self.ptr.as_ref().expect("ptr guaranteed to be non-null") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::ops::DerefMut for GuestStr<'a> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { self.ptr.as_mut().expect("ptr guaranteed to be non-null") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Drop for GuestStr<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.bc.unborrow(self.borrow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod private {
|
mod private {
|
||||||
pub trait Sealed {}
|
pub trait Sealed {}
|
||||||
impl<T> Sealed for T {}
|
impl<T> Sealed for T {}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use wiggle::{GuestMemory, GuestPtr};
|
use wiggle::{BorrowChecker, GuestMemory, GuestPtr};
|
||||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||||
|
|
||||||
wiggle::from_witx!({
|
wiggle::from_witx!({
|
||||||
@@ -75,31 +75,35 @@ impl ReduceExcusesExcercise {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let mut ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let mut host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
// Populate memory with pointers to generated Excuse values
|
// Populate memory with pointers to generated Excuse values
|
||||||
for (&excuse, ptr) in self.excuse_values.iter().zip(self.excuse_ptr_locs.iter()) {
|
for (&excuse, ptr) in self.excuse_values.iter().zip(self.excuse_ptr_locs.iter()) {
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(ptr.ptr)
|
.ptr(&bc, ptr.ptr)
|
||||||
.write(excuse)
|
.write(excuse)
|
||||||
.expect("deref ptr mut to Excuse value");
|
.expect("deref ptr mut to Excuse value");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate the array with pointers to generated Excuse values
|
// Populate the array with pointers to generated Excuse values
|
||||||
{
|
{
|
||||||
let array: GuestPtr<'_, [GuestPtr<types::Excuse>]> =
|
let array: GuestPtr<'_, [GuestPtr<types::Excuse>]> = host_memory.ptr(
|
||||||
host_memory.ptr((self.array_ptr_loc.ptr, self.excuse_ptr_locs.len() as u32));
|
&bc,
|
||||||
|
(self.array_ptr_loc.ptr, self.excuse_ptr_locs.len() as u32),
|
||||||
|
);
|
||||||
for (slot, ptr) in array.iter().zip(&self.excuse_ptr_locs) {
|
for (slot, ptr) in array.iter().zip(&self.excuse_ptr_locs) {
|
||||||
let slot = slot.expect("array should be in bounds");
|
let slot = slot.expect("array should be in bounds");
|
||||||
slot.write(host_memory.ptr(ptr.ptr))
|
slot.write(host_memory.ptr(&bc, ptr.ptr))
|
||||||
.expect("should succeed in writing array");
|
.expect("should succeed in writing array");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = arrays::reduce_excuses(
|
let res = arrays::reduce_excuses(
|
||||||
&mut ctx,
|
&ctx,
|
||||||
&mut host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.array_ptr_loc.ptr as i32,
|
self.array_ptr_loc.ptr as i32,
|
||||||
self.excuse_ptr_locs.len() as i32,
|
self.excuse_ptr_locs.len() as i32,
|
||||||
self.return_ptr_loc.ptr as i32,
|
self.return_ptr_loc.ptr as i32,
|
||||||
@@ -112,7 +116,7 @@ impl ReduceExcusesExcercise {
|
|||||||
.last()
|
.last()
|
||||||
.expect("generated vec of excuses should be non-empty");
|
.expect("generated vec of excuses should be non-empty");
|
||||||
let given: types::Excuse = host_memory
|
let given: types::Excuse = host_memory
|
||||||
.ptr(self.return_ptr_loc.ptr)
|
.ptr(&bc, self.return_ptr_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("deref ptr to returned value");
|
.expect("deref ptr to returned value");
|
||||||
assert_eq!(expected, given, "reduce excuses return val");
|
assert_eq!(expected, given, "reduce excuses return val");
|
||||||
@@ -165,28 +169,30 @@ impl PopulateExcusesExcercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
// Populate array with valid pointers to Excuse type in memory
|
// Populate array with valid pointers to Excuse type in memory
|
||||||
let ptr = host_memory.ptr::<[GuestPtr<'_, types::Excuse>]>((
|
let ptr = host_memory.ptr::<[GuestPtr<'_, types::Excuse>]>(
|
||||||
self.array_ptr_loc.ptr,
|
&bc,
|
||||||
self.elements.len() as u32,
|
(self.array_ptr_loc.ptr, self.elements.len() as u32),
|
||||||
));
|
);
|
||||||
for (ptr, val) in ptr.iter().zip(&self.elements) {
|
for (ptr, val) in ptr.iter().zip(&self.elements) {
|
||||||
ptr.expect("should be valid pointer")
|
ptr.expect("should be valid pointer")
|
||||||
.write(host_memory.ptr(val.ptr))
|
.write(host_memory.ptr(&bc, val.ptr))
|
||||||
.expect("failed to write value");
|
.expect("failed to write value");
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = arrays::populate_excuses(
|
let res = arrays::populate_excuses(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.array_ptr_loc.ptr as i32,
|
self.array_ptr_loc.ptr as i32,
|
||||||
self.elements.len() as i32,
|
self.elements.len() as i32,
|
||||||
);
|
);
|
||||||
assert_eq!(res, types::Errno::Ok.into(), "populate excuses errno");
|
assert_eq!(res, types::Errno::Ok.into(), "populate excuses errno");
|
||||||
|
|
||||||
let arr: GuestPtr<'_, [GuestPtr<'_, types::Excuse>]> =
|
let arr: GuestPtr<'_, [GuestPtr<'_, types::Excuse>]> =
|
||||||
host_memory.ptr((self.array_ptr_loc.ptr, self.elements.len() as u32));
|
host_memory.ptr(&bc, (self.array_ptr_loc.ptr, self.elements.len() as u32));
|
||||||
for el in arr.iter() {
|
for el in arr.iter() {
|
||||||
let ptr_to_ptr = el
|
let ptr_to_ptr = el
|
||||||
.expect("valid ptr to ptr")
|
.expect("valid ptr to ptr")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use wiggle::GuestMemory;
|
use wiggle::{BorrowChecker, GuestMemory};
|
||||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||||
|
|
||||||
wiggle::from_witx!({
|
wiggle::from_witx!({
|
||||||
@@ -31,8 +31,9 @@ impl IntFloatExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
let e = atoms::int_float_args(&ctx, &host_memory, self.an_int as i32, self.an_float);
|
let e = atoms::int_float_args(&ctx, &host_memory, &bc, self.an_int as i32, self.an_float);
|
||||||
|
|
||||||
assert_eq!(e, types::Errno::Ok.into(), "int_float_args error");
|
assert_eq!(e, types::Errno::Ok.into(), "int_float_args error");
|
||||||
}
|
}
|
||||||
@@ -60,16 +61,18 @@ impl DoubleIntExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
let e = atoms::double_int_return_float(
|
let e = atoms::double_int_return_float(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.input as i32,
|
self.input as i32,
|
||||||
self.return_loc.ptr as i32,
|
self.return_loc.ptr as i32,
|
||||||
);
|
);
|
||||||
|
|
||||||
let return_val = host_memory
|
let return_val = host_memory
|
||||||
.ptr::<types::AliasToFloat>(self.return_loc.ptr)
|
.ptr::<types::AliasToFloat>(&bc, self.return_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("failed to read return");
|
.expect("failed to read return");
|
||||||
assert_eq!(e, types::Errno::Ok.into(), "errno");
|
assert_eq!(e, types::Errno::Ok.into(), "errno");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use wiggle::{GuestMemory, GuestPtr};
|
use wiggle::{BorrowChecker, GuestMemory, GuestPtr};
|
||||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||||
|
|
||||||
wiggle::from_witx!({
|
wiggle::from_witx!({
|
||||||
@@ -65,16 +65,18 @@ impl ConfigureCarExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
// Populate input ptr
|
// Populate input ptr
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.other_config_by_ptr.ptr)
|
.ptr(&bc, self.other_config_by_ptr.ptr)
|
||||||
.write(self.other_config)
|
.write(self.other_config)
|
||||||
.expect("deref ptr mut to CarConfig");
|
.expect("deref ptr mut to CarConfig");
|
||||||
|
|
||||||
let res = flags::configure_car(
|
let res = flags::configure_car(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.old_config.into(),
|
self.old_config.into(),
|
||||||
self.other_config_by_ptr.ptr as i32,
|
self.other_config_by_ptr.ptr as i32,
|
||||||
self.return_ptr_loc.ptr as i32,
|
self.return_ptr_loc.ptr as i32,
|
||||||
@@ -82,7 +84,7 @@ impl ConfigureCarExercise {
|
|||||||
assert_eq!(res, types::Errno::Ok.into(), "configure car errno");
|
assert_eq!(res, types::Errno::Ok.into(), "configure car errno");
|
||||||
|
|
||||||
let res_config = host_memory
|
let res_config = host_memory
|
||||||
.ptr::<types::CarConfig>(self.return_ptr_loc.ptr)
|
.ptr::<types::CarConfig>(&bc, self.return_ptr_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("deref to CarConfig value");
|
.expect("deref to CarConfig value");
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use wiggle::{GuestMemory, GuestType};
|
use wiggle::{BorrowChecker, GuestMemory, GuestType};
|
||||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||||
|
|
||||||
const FD_VAL: u32 = 123;
|
const FD_VAL: u32 = 123;
|
||||||
@@ -34,23 +34,24 @@ impl HandleExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
let e = handle_examples::fd_create(&ctx, &host_memory, self.return_loc.ptr as i32);
|
let e = handle_examples::fd_create(&ctx, &host_memory, &bc, self.return_loc.ptr as i32);
|
||||||
|
|
||||||
assert_eq!(e, types::Errno::Ok.into(), "fd_create error");
|
assert_eq!(e, types::Errno::Ok.into(), "fd_create error");
|
||||||
|
|
||||||
let h_got: u32 = host_memory
|
let h_got: u32 = host_memory
|
||||||
.ptr(self.return_loc.ptr)
|
.ptr(&bc, self.return_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("return ref_mut");
|
.expect("return ref_mut");
|
||||||
|
|
||||||
assert_eq!(h_got, 123, "fd_create return val");
|
assert_eq!(h_got, 123, "fd_create return val");
|
||||||
|
|
||||||
let e = handle_examples::fd_consume(&ctx, &host_memory, h_got as i32);
|
let e = handle_examples::fd_consume(&ctx, &host_memory, &bc, h_got as i32);
|
||||||
|
|
||||||
assert_eq!(e, types::Errno::Ok.into(), "fd_consume error");
|
assert_eq!(e, types::Errno::Ok.into(), "fd_consume error");
|
||||||
|
|
||||||
let e = handle_examples::fd_consume(&ctx, &host_memory, h_got as i32 + 1);
|
let e = handle_examples::fd_consume(&ctx, &host_memory, &bc, h_got as i32 + 1);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
e,
|
e,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use wiggle::GuestMemory;
|
use wiggle::{BorrowChecker, GuestMemory};
|
||||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||||
|
|
||||||
wiggle::from_witx!({
|
wiggle::from_witx!({
|
||||||
@@ -46,17 +46,19 @@ impl CookieCutterExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
let res = ints::cookie_cutter(
|
let res = ints::cookie_cutter(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.cookie.into(),
|
self.cookie.into(),
|
||||||
self.return_ptr_loc.ptr as i32,
|
self.return_ptr_loc.ptr as i32,
|
||||||
);
|
);
|
||||||
assert_eq!(res, types::Errno::Ok.into(), "cookie cutter errno");
|
assert_eq!(res, types::Errno::Ok.into(), "cookie cutter errno");
|
||||||
|
|
||||||
let is_cookie_start = host_memory
|
let is_cookie_start = host_memory
|
||||||
.ptr::<types::Bool>(self.return_ptr_loc.ptr)
|
.ptr::<types::Bool>(&bc, self.return_ptr_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("deref to Bool value");
|
.expect("deref to Bool value");
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use wiggle::{GuestMemory, GuestPtr};
|
use wiggle::{BorrowChecker, GuestMemory, GuestPtr};
|
||||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||||
|
|
||||||
wiggle::from_witx!({
|
wiggle::from_witx!({
|
||||||
@@ -128,30 +128,32 @@ impl PointersAndEnumsExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input2_loc.ptr)
|
.ptr(&bc, self.input2_loc.ptr)
|
||||||
.write(self.input2)
|
.write(self.input2)
|
||||||
.expect("input2 ref_mut");
|
.expect("input2 ref_mut");
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input3_loc.ptr)
|
.ptr(&bc, self.input3_loc.ptr)
|
||||||
.write(self.input3)
|
.write(self.input3)
|
||||||
.expect("input3 ref_mut");
|
.expect("input3 ref_mut");
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input4_loc.ptr)
|
.ptr(&bc, self.input4_loc.ptr)
|
||||||
.write(self.input4)
|
.write(self.input4)
|
||||||
.expect("input4 ref_mut");
|
.expect("input4 ref_mut");
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input4_ptr_loc.ptr)
|
.ptr(&bc, self.input4_ptr_loc.ptr)
|
||||||
.write(self.input4_loc.ptr)
|
.write(self.input4_loc.ptr)
|
||||||
.expect("input4 ptr ref_mut");
|
.expect("input4 ptr ref_mut");
|
||||||
|
|
||||||
let e = pointers::pointers_and_enums(
|
let e = pointers::pointers_and_enums(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.input1.into(),
|
self.input1.into(),
|
||||||
self.input2_loc.ptr as i32,
|
self.input2_loc.ptr as i32,
|
||||||
self.input3_loc.ptr as i32,
|
self.input3_loc.ptr as i32,
|
||||||
@@ -161,7 +163,7 @@ impl PointersAndEnumsExercise {
|
|||||||
|
|
||||||
// Implementation of pointers_and_enums writes input3 to the input2_loc:
|
// Implementation of pointers_and_enums writes input3 to the input2_loc:
|
||||||
let written_to_input2_loc: i32 = host_memory
|
let written_to_input2_loc: i32 = host_memory
|
||||||
.ptr(self.input2_loc.ptr)
|
.ptr(&bc, self.input2_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("input2 ref");
|
.expect("input2 ref");
|
||||||
|
|
||||||
@@ -173,7 +175,7 @@ impl PointersAndEnumsExercise {
|
|||||||
|
|
||||||
// Implementation of pointers_and_enums writes input2_loc to input4_ptr_loc:
|
// Implementation of pointers_and_enums writes input2_loc to input4_ptr_loc:
|
||||||
let written_to_input4_ptr: u32 = host_memory
|
let written_to_input4_ptr: u32 = host_memory
|
||||||
.ptr(self.input4_ptr_loc.ptr)
|
.ptr(&bc, self.input4_ptr_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("input4_ptr_loc ref");
|
.expect("input4_ptr_loc ref");
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use wiggle::{GuestBorrows, GuestMemory, GuestPtr};
|
use wiggle::{BorrowChecker, GuestMemory, GuestPtr};
|
||||||
use wiggle_test::{impl_errno, HostMemory, MemArea, MemAreas, WasiCtx};
|
use wiggle_test::{impl_errno, HostMemory, MemArea, MemAreas, WasiCtx};
|
||||||
|
|
||||||
wiggle::from_witx!({
|
wiggle::from_witx!({
|
||||||
@@ -11,12 +11,9 @@ impl_errno!(types::Errno, types::GuestErrorConversion);
|
|||||||
|
|
||||||
impl<'a> strings::Strings for WasiCtx<'a> {
|
impl<'a> strings::Strings for WasiCtx<'a> {
|
||||||
fn hello_string(&self, a_string: &GuestPtr<str>) -> Result<u32, types::Errno> {
|
fn hello_string(&self, a_string: &GuestPtr<str>) -> Result<u32, types::Errno> {
|
||||||
let mut bc = GuestBorrows::new();
|
let s = a_string.as_str().expect("should be valid string");
|
||||||
let s = a_string.as_raw(&mut bc).expect("should be valid string");
|
|
||||||
unsafe {
|
|
||||||
println!("a_string='{}'", &*s);
|
println!("a_string='{}'", &*s);
|
||||||
Ok((*s).len() as u32)
|
Ok(s.len() as u32)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multi_string(
|
fn multi_string(
|
||||||
@@ -25,19 +22,16 @@ impl<'a> strings::Strings for WasiCtx<'a> {
|
|||||||
b: &GuestPtr<str>,
|
b: &GuestPtr<str>,
|
||||||
c: &GuestPtr<str>,
|
c: &GuestPtr<str>,
|
||||||
) -> Result<u32, types::Errno> {
|
) -> Result<u32, types::Errno> {
|
||||||
let mut bc = GuestBorrows::new();
|
let sa = a.as_str().expect("A should be valid string");
|
||||||
let sa = a.as_raw(&mut bc).expect("A should be valid string");
|
let sb = b.as_str().expect("B should be valid string");
|
||||||
let sb = b.as_raw(&mut bc).expect("B should be valid string");
|
let sc = c.as_str().expect("C should be valid string");
|
||||||
let sc = c.as_raw(&mut bc).expect("C should be valid string");
|
let total_len = sa.len() + sb.len() + sc.len();
|
||||||
unsafe {
|
|
||||||
let total_len = (&*sa).len() + (&*sb).len() + (&*sc).len();
|
|
||||||
println!(
|
println!(
|
||||||
"len={}, a='{}', b='{}', c='{}'",
|
"len={}, a='{}', b='{}', c='{}'",
|
||||||
total_len, &*sa, &*sb, &*sc
|
total_len, &*sa, &*sb, &*sc
|
||||||
);
|
);
|
||||||
Ok(total_len as u32)
|
Ok(total_len as u32)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_string_strategy() -> impl Strategy<Value = String> {
|
fn test_string_strategy() -> impl Strategy<Value = String> {
|
||||||
@@ -75,9 +69,11 @@ impl HelloStringExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
// Populate string in guest's memory
|
// Populate string in guest's memory
|
||||||
let ptr = host_memory.ptr::<str>((self.string_ptr_loc.ptr, self.test_word.len() as u32));
|
let ptr =
|
||||||
|
host_memory.ptr::<str>(&bc, (self.string_ptr_loc.ptr, self.test_word.len() as u32));
|
||||||
for (slot, byte) in ptr.as_bytes().iter().zip(self.test_word.bytes()) {
|
for (slot, byte) in ptr.as_bytes().iter().zip(self.test_word.bytes()) {
|
||||||
slot.expect("should be valid pointer")
|
slot.expect("should be valid pointer")
|
||||||
.write(byte)
|
.write(byte)
|
||||||
@@ -87,6 +83,7 @@ impl HelloStringExercise {
|
|||||||
let res = strings::hello_string(
|
let res = strings::hello_string(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.string_ptr_loc.ptr as i32,
|
self.string_ptr_loc.ptr as i32,
|
||||||
self.test_word.len() as i32,
|
self.test_word.len() as i32,
|
||||||
self.return_ptr_loc.ptr as i32,
|
self.return_ptr_loc.ptr as i32,
|
||||||
@@ -94,7 +91,7 @@ impl HelloStringExercise {
|
|||||||
assert_eq!(res, types::Errno::Ok.into(), "hello string errno");
|
assert_eq!(res, types::Errno::Ok.into(), "hello string errno");
|
||||||
|
|
||||||
let given = host_memory
|
let given = host_memory
|
||||||
.ptr::<u32>(self.return_ptr_loc.ptr)
|
.ptr::<u32>(&bc, self.return_ptr_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("deref ptr to return value");
|
.expect("deref ptr to return value");
|
||||||
assert_eq!(self.test_word.len() as u32, given);
|
assert_eq!(self.test_word.len() as u32, given);
|
||||||
@@ -181,9 +178,10 @@ impl MultiStringExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
let write_string = |val: &str, loc: MemArea| {
|
let write_string = |val: &str, loc: MemArea| {
|
||||||
let ptr = host_memory.ptr::<str>((loc.ptr, val.len() as u32));
|
let ptr = host_memory.ptr::<str>(&bc, (loc.ptr, val.len() as u32));
|
||||||
for (slot, byte) in ptr.as_bytes().iter().zip(val.bytes()) {
|
for (slot, byte) in ptr.as_bytes().iter().zip(val.bytes()) {
|
||||||
slot.expect("should be valid pointer")
|
slot.expect("should be valid pointer")
|
||||||
.write(byte)
|
.write(byte)
|
||||||
@@ -198,6 +196,7 @@ impl MultiStringExercise {
|
|||||||
let res = strings::multi_string(
|
let res = strings::multi_string(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.sa_ptr_loc.ptr as i32,
|
self.sa_ptr_loc.ptr as i32,
|
||||||
self.a.len() as i32,
|
self.a.len() as i32,
|
||||||
self.sb_ptr_loc.ptr as i32,
|
self.sb_ptr_loc.ptr as i32,
|
||||||
@@ -209,7 +208,7 @@ impl MultiStringExercise {
|
|||||||
assert_eq!(res, types::Errno::Ok.into(), "multi string errno");
|
assert_eq!(res, types::Errno::Ok.into(), "multi string errno");
|
||||||
|
|
||||||
let given = host_memory
|
let given = host_memory
|
||||||
.ptr::<u32>(self.return_ptr_loc.ptr)
|
.ptr::<u32>(&bc, self.return_ptr_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("deref ptr to return value");
|
.expect("deref ptr to return value");
|
||||||
assert_eq!((self.a.len() + self.b.len() + self.c.len()) as u32, given);
|
assert_eq!((self.a.len() + self.b.len() + self.c.len()) as u32, given);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use wiggle::{GuestMemory, GuestPtr};
|
use wiggle::{BorrowChecker, GuestMemory, GuestPtr};
|
||||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||||
|
|
||||||
wiggle::from_witx!({
|
wiggle::from_witx!({
|
||||||
@@ -83,18 +83,20 @@ impl SumOfPairExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_loc.ptr)
|
.ptr(&bc, self.input_loc.ptr)
|
||||||
.write(self.input.first)
|
.write(self.input.first)
|
||||||
.expect("input ref_mut");
|
.expect("input ref_mut");
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_loc.ptr + 4)
|
.ptr(&bc, self.input_loc.ptr + 4)
|
||||||
.write(self.input.second)
|
.write(self.input.second)
|
||||||
.expect("input ref_mut");
|
.expect("input ref_mut");
|
||||||
let sum_err = structs::sum_of_pair(
|
let sum_err = structs::sum_of_pair(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.input_loc.ptr as i32,
|
self.input_loc.ptr as i32,
|
||||||
self.return_loc.ptr as i32,
|
self.return_loc.ptr as i32,
|
||||||
);
|
);
|
||||||
@@ -102,7 +104,7 @@ impl SumOfPairExercise {
|
|||||||
assert_eq!(sum_err, types::Errno::Ok.into(), "sum errno");
|
assert_eq!(sum_err, types::Errno::Ok.into(), "sum errno");
|
||||||
|
|
||||||
let return_val: i64 = host_memory
|
let return_val: i64 = host_memory
|
||||||
.ptr(self.return_loc.ptr)
|
.ptr(&bc, self.return_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("return ref");
|
.expect("return ref");
|
||||||
|
|
||||||
@@ -171,28 +173,30 @@ impl SumPairPtrsExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_first_loc.ptr)
|
.ptr(&bc, self.input_first_loc.ptr)
|
||||||
.write(self.input_first)
|
.write(self.input_first)
|
||||||
.expect("input_first ref");
|
.expect("input_first ref");
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_second_loc.ptr)
|
.ptr(&bc, self.input_second_loc.ptr)
|
||||||
.write(self.input_second)
|
.write(self.input_second)
|
||||||
.expect("input_second ref");
|
.expect("input_second ref");
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_struct_loc.ptr)
|
.ptr(&bc, self.input_struct_loc.ptr)
|
||||||
.write(self.input_first_loc.ptr)
|
.write(self.input_first_loc.ptr)
|
||||||
.expect("input_struct ref");
|
.expect("input_struct ref");
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_struct_loc.ptr + 4)
|
.ptr(&bc, self.input_struct_loc.ptr + 4)
|
||||||
.write(self.input_second_loc.ptr)
|
.write(self.input_second_loc.ptr)
|
||||||
.expect("input_struct ref");
|
.expect("input_struct ref");
|
||||||
|
|
||||||
let res = structs::sum_of_pair_of_ptrs(
|
let res = structs::sum_of_pair_of_ptrs(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.input_struct_loc.ptr as i32,
|
self.input_struct_loc.ptr as i32,
|
||||||
self.return_loc.ptr as i32,
|
self.return_loc.ptr as i32,
|
||||||
);
|
);
|
||||||
@@ -200,7 +204,7 @@ impl SumPairPtrsExercise {
|
|||||||
assert_eq!(res, types::Errno::Ok.into(), "sum of pair of ptrs errno");
|
assert_eq!(res, types::Errno::Ok.into(), "sum of pair of ptrs errno");
|
||||||
|
|
||||||
let doubled: i64 = host_memory
|
let doubled: i64 = host_memory
|
||||||
.ptr(self.return_loc.ptr)
|
.ptr(&bc, self.return_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("return ref");
|
.expect("return ref");
|
||||||
|
|
||||||
@@ -255,23 +259,25 @@ impl SumIntAndPtrExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_first_loc.ptr)
|
.ptr(&bc, self.input_first_loc.ptr)
|
||||||
.write(self.input_first)
|
.write(self.input_first)
|
||||||
.expect("input_first ref");
|
.expect("input_first ref");
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_struct_loc.ptr)
|
.ptr(&bc, self.input_struct_loc.ptr)
|
||||||
.write(self.input_first_loc.ptr)
|
.write(self.input_first_loc.ptr)
|
||||||
.expect("input_struct ref");
|
.expect("input_struct ref");
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_struct_loc.ptr + 4)
|
.ptr(&bc, self.input_struct_loc.ptr + 4)
|
||||||
.write(self.input_second)
|
.write(self.input_second)
|
||||||
.expect("input_struct ref");
|
.expect("input_struct ref");
|
||||||
|
|
||||||
let res = structs::sum_of_int_and_ptr(
|
let res = structs::sum_of_int_and_ptr(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.input_struct_loc.ptr as i32,
|
self.input_struct_loc.ptr as i32,
|
||||||
self.return_loc.ptr as i32,
|
self.return_loc.ptr as i32,
|
||||||
);
|
);
|
||||||
@@ -279,7 +285,7 @@ impl SumIntAndPtrExercise {
|
|||||||
assert_eq!(res, types::Errno::Ok.into(), "sum of int and ptr errno");
|
assert_eq!(res, types::Errno::Ok.into(), "sum of int and ptr errno");
|
||||||
|
|
||||||
let doubled: i64 = host_memory
|
let doubled: i64 = host_memory
|
||||||
.ptr(self.return_loc.ptr)
|
.ptr(&bc, self.return_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("return ref");
|
.expect("return ref");
|
||||||
|
|
||||||
@@ -312,13 +318,14 @@ impl ReturnPairInts {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
let err = structs::return_pair_ints(&ctx, &host_memory, self.return_loc.ptr as i32);
|
let err = structs::return_pair_ints(&ctx, &host_memory, &bc, self.return_loc.ptr as i32);
|
||||||
|
|
||||||
assert_eq!(err, types::Errno::Ok.into(), "return struct errno");
|
assert_eq!(err, types::Errno::Ok.into(), "return struct errno");
|
||||||
|
|
||||||
let return_struct: types::PairInts = host_memory
|
let return_struct: types::PairInts = host_memory
|
||||||
.ptr(self.return_loc.ptr)
|
.ptr(&bc, self.return_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("return ref");
|
.expect("return ref");
|
||||||
|
|
||||||
@@ -377,19 +384,21 @@ impl ReturnPairPtrsExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_first_loc.ptr)
|
.ptr(&bc, self.input_first_loc.ptr)
|
||||||
.write(self.input_first)
|
.write(self.input_first)
|
||||||
.expect("input_first ref");
|
.expect("input_first ref");
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_second_loc.ptr)
|
.ptr(&bc, self.input_second_loc.ptr)
|
||||||
.write(self.input_second)
|
.write(self.input_second)
|
||||||
.expect("input_second ref");
|
.expect("input_second ref");
|
||||||
|
|
||||||
let res = structs::return_pair_of_ptrs(
|
let res = structs::return_pair_of_ptrs(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.input_first_loc.ptr as i32,
|
self.input_first_loc.ptr as i32,
|
||||||
self.input_second_loc.ptr as i32,
|
self.input_second_loc.ptr as i32,
|
||||||
self.return_loc.ptr as i32,
|
self.return_loc.ptr as i32,
|
||||||
@@ -398,7 +407,7 @@ impl ReturnPairPtrsExercise {
|
|||||||
assert_eq!(res, types::Errno::Ok.into(), "return pair of ptrs errno");
|
assert_eq!(res, types::Errno::Ok.into(), "return pair of ptrs errno");
|
||||||
|
|
||||||
let ptr_pair_int_ptrs: types::PairIntPtrs<'_> = host_memory
|
let ptr_pair_int_ptrs: types::PairIntPtrs<'_> = host_memory
|
||||||
.ptr(self.return_loc.ptr)
|
.ptr(&bc, self.return_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("failed to read return location");
|
.expect("failed to read return location");
|
||||||
let ret_first_ptr = ptr_pair_int_ptrs.first;
|
let ret_first_ptr = ptr_pair_int_ptrs.first;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use wiggle::{GuestMemory, GuestType};
|
use wiggle::{BorrowChecker, GuestMemory, GuestType};
|
||||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||||
|
|
||||||
wiggle::from_witx!({
|
wiggle::from_witx!({
|
||||||
@@ -107,21 +107,22 @@ impl GetTagExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
let discriminant: u8 = reason_tag(&self.input).into();
|
let discriminant: u8 = reason_tag(&self.input).into();
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_loc.ptr)
|
.ptr(&bc, self.input_loc.ptr)
|
||||||
.write(discriminant)
|
.write(discriminant)
|
||||||
.expect("input discriminant ptr");
|
.expect("input discriminant ptr");
|
||||||
match self.input {
|
match self.input {
|
||||||
types::Reason::DogAte(f) => {
|
types::Reason::DogAte(f) => {
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_loc.ptr + 4)
|
.ptr(&bc, self.input_loc.ptr + 4)
|
||||||
.write(f)
|
.write(f)
|
||||||
.expect("input contents ref_mut");
|
.expect("input contents ref_mut");
|
||||||
}
|
}
|
||||||
types::Reason::Traffic(v) => host_memory
|
types::Reason::Traffic(v) => host_memory
|
||||||
.ptr(self.input_loc.ptr + 4)
|
.ptr(&bc, self.input_loc.ptr + 4)
|
||||||
.write(v)
|
.write(v)
|
||||||
.expect("input contents ref_mut"),
|
.expect("input contents ref_mut"),
|
||||||
types::Reason::Sleeping => {} // Do nothing
|
types::Reason::Sleeping => {} // Do nothing
|
||||||
@@ -129,6 +130,7 @@ impl GetTagExercise {
|
|||||||
let e = union_example::get_tag(
|
let e = union_example::get_tag(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.input_loc.ptr as i32,
|
self.input_loc.ptr as i32,
|
||||||
self.return_loc.ptr as i32,
|
self.return_loc.ptr as i32,
|
||||||
);
|
);
|
||||||
@@ -136,7 +138,7 @@ impl GetTagExercise {
|
|||||||
assert_eq!(e, types::Errno::Ok.into(), "get_tag errno");
|
assert_eq!(e, types::Errno::Ok.into(), "get_tag errno");
|
||||||
|
|
||||||
let return_val: types::Excuse = host_memory
|
let return_val: types::Excuse = host_memory
|
||||||
.ptr(self.return_loc.ptr)
|
.ptr(&bc, self.return_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("return ref");
|
.expect("return ref");
|
||||||
|
|
||||||
@@ -184,27 +186,28 @@ impl ReasonMultExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
|
let bc = BorrowChecker::new();
|
||||||
|
|
||||||
let discriminant: u8 = reason_tag(&self.input).into();
|
let discriminant: u8 = reason_tag(&self.input).into();
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_loc.ptr)
|
.ptr(&bc, self.input_loc.ptr)
|
||||||
.write(discriminant)
|
.write(discriminant)
|
||||||
.expect("input discriminant ref_mut");
|
.expect("input discriminant ref_mut");
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_loc.ptr + 4)
|
.ptr(&bc, self.input_loc.ptr + 4)
|
||||||
.write(self.input_pointee_loc.ptr)
|
.write(self.input_pointee_loc.ptr)
|
||||||
.expect("input pointer ref_mut");
|
.expect("input pointer ref_mut");
|
||||||
|
|
||||||
match self.input {
|
match self.input {
|
||||||
types::Reason::DogAte(f) => {
|
types::Reason::DogAte(f) => {
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_pointee_loc.ptr)
|
.ptr(&bc, self.input_pointee_loc.ptr)
|
||||||
.write(f)
|
.write(f)
|
||||||
.expect("input contents ref_mut");
|
.expect("input contents ref_mut");
|
||||||
}
|
}
|
||||||
types::Reason::Traffic(v) => {
|
types::Reason::Traffic(v) => {
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(self.input_pointee_loc.ptr)
|
.ptr(&bc, self.input_pointee_loc.ptr)
|
||||||
.write(v)
|
.write(v)
|
||||||
.expect("input contents ref_mut");
|
.expect("input contents ref_mut");
|
||||||
}
|
}
|
||||||
@@ -213,6 +216,7 @@ impl ReasonMultExercise {
|
|||||||
let e = union_example::reason_mult(
|
let e = union_example::reason_mult(
|
||||||
&ctx,
|
&ctx,
|
||||||
&host_memory,
|
&host_memory,
|
||||||
|
&bc,
|
||||||
self.input_loc.ptr as i32,
|
self.input_loc.ptr as i32,
|
||||||
self.multiply_by as i32,
|
self.multiply_by as i32,
|
||||||
);
|
);
|
||||||
@@ -222,7 +226,7 @@ impl ReasonMultExercise {
|
|||||||
match self.input {
|
match self.input {
|
||||||
types::Reason::DogAte(f) => {
|
types::Reason::DogAte(f) => {
|
||||||
let f_result: f32 = host_memory
|
let f_result: f32 = host_memory
|
||||||
.ptr(self.input_pointee_loc.ptr)
|
.ptr(&bc, self.input_pointee_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("input contents ref_mut");
|
.expect("input contents ref_mut");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -233,7 +237,7 @@ impl ReasonMultExercise {
|
|||||||
}
|
}
|
||||||
types::Reason::Traffic(v) => {
|
types::Reason::Traffic(v) => {
|
||||||
let v_result: i32 = host_memory
|
let v_result: i32 = host_memory
|
||||||
.ptr(self.input_pointee_loc.ptr)
|
.ptr(&bc, self.input_pointee_loc.ptr)
|
||||||
.read()
|
.read()
|
||||||
.expect("input contents ref_mut");
|
.expect("input contents ref_mut");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use wiggle::{GuestBorrows, GuestError, GuestErrorType, GuestPtr};
|
use wiggle::{GuestError, GuestErrorType, GuestPtr, GuestSlice};
|
||||||
use wiggle_test::WasiCtx;
|
use wiggle_test::WasiCtx;
|
||||||
|
|
||||||
// This test file exists to make sure that the entire `wasi.witx` file can be
|
// This test file exists to make sure that the entire `wasi.witx` file can be
|
||||||
@@ -141,11 +141,11 @@ impl<'a> crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx<'a> {
|
|||||||
// that we can use the wiggle API to create the datastructures we want
|
// that we can use the wiggle API to create the datastructures we want
|
||||||
// for efficient implementation of this function elsewhere.
|
// for efficient implementation of this function elsewhere.
|
||||||
|
|
||||||
let mut bc = GuestBorrows::new();
|
let mut slices: Vec<GuestSlice<'_, u8>> = Vec::new();
|
||||||
let mut slices: Vec<&'_ mut [u8]> = Vec::new();
|
// XXX FIXME make sure this property still holds:
|
||||||
// Mark the iov elements as borrowed, to ensure that they does not
|
// Mark the iov elements as borrowed, to ensure that they does not
|
||||||
// overlap with any of the as_raw regions.
|
// overlap with any of the as_raw regions.
|
||||||
bc.borrow_slice(&iovs).expect("borrow iovec array");
|
// bc.borrow_slice(&iovs).expect("borrow iovec array");
|
||||||
for iov_ptr in iovs.iter() {
|
for iov_ptr in iovs.iter() {
|
||||||
let iov_ptr = iov_ptr.expect("iovec element pointer is valid");
|
let iov_ptr = iov_ptr.expect("iovec element pointer is valid");
|
||||||
|
|
||||||
@@ -153,10 +153,14 @@ impl<'a> crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx<'a> {
|
|||||||
let base: GuestPtr<u8> = iov.buf;
|
let base: GuestPtr<u8> = iov.buf;
|
||||||
let len: u32 = iov.buf_len;
|
let len: u32 = iov.buf_len;
|
||||||
let buf: GuestPtr<[u8]> = base.as_array(len);
|
let buf: GuestPtr<[u8]> = base.as_array(len);
|
||||||
let slice = buf.as_raw(&mut bc).expect("borrow slice from iovec");
|
let slice = buf.as_slice().expect("borrow slice from iovec");
|
||||||
slices.push(unsafe { &mut *slice });
|
slices.push(slice);
|
||||||
}
|
}
|
||||||
println!("iovec slices: {:?}", slices);
|
println!("iovec slices: [");
|
||||||
|
for slice in slices {
|
||||||
|
println!(" {:?},", &*slice);
|
||||||
|
}
|
||||||
|
println!("]");
|
||||||
unimplemented!("fd_pread")
|
unimplemented!("fd_pread")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user