Rewrite for recursive safety
This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory "until something is reentrant". After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there's only one guest pointer type, `GuestPtr<'a, T>`, where `'a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they're all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they're safe. * `GuestPtr<'_, str>` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that's it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you'd `.read()` or `.write()` very quickly. You'd pass around the type itself. * For strings, you'd pass `GuestPtr<'_, str>` down to the point where it's actually consumed. At that moment you'd either decide to copy it out (a safe operation) or you'd get a raw view to the string (an unsafe operation) and assert that you won't call back into wasm while you're holding that pointer. * Arrays are similar to strings, passing around `GuestPtr<'_, [T]>`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr<'_, T>` for convenience. Overall there's still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there's utilities which aren't currently implemented which would be easy to implement. For example there's no method to copy out a string or a slice, although that would be pretty easy to add. In any case I'm curious to get feedback on this approach and see what y'all think!
This commit is contained in:
147
tests/arrays.rs
147
tests/arrays.rs
@@ -1,5 +1,5 @@
|
||||
use proptest::prelude::*;
|
||||
use wiggle_runtime::{GuestArray, GuestError, GuestPtr, GuestPtrMut, GuestType};
|
||||
use wiggle_runtime::{GuestError, GuestMemory, GuestPtr};
|
||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||
|
||||
wiggle::from_witx!({
|
||||
@@ -14,25 +14,25 @@ impl arrays::Arrays for WasiCtx {
|
||||
&self,
|
||||
excuses: &types::ConstExcuseArray,
|
||||
) -> Result<types::Excuse, types::Errno> {
|
||||
let last = GuestType::read(
|
||||
&excuses
|
||||
.iter()
|
||||
.last()
|
||||
.expect("input array is non-empty")
|
||||
.expect("valid ptr to ptr"),
|
||||
)
|
||||
.expect("valid ptr to some Excuse value");
|
||||
Ok(*last.as_ref().expect("dereferencing ptr should succeed"))
|
||||
let last = &excuses
|
||||
.iter()
|
||||
.last()
|
||||
.expect("input array is non-empty")
|
||||
.expect("valid ptr to ptr")
|
||||
.read()
|
||||
.expect("valid ptr to some Excuse value");
|
||||
Ok(last.read().expect("dereferencing ptr should succeed"))
|
||||
}
|
||||
|
||||
fn populate_excuses(&self, excuses: &types::ExcuseArray) -> Result<(), types::Errno> {
|
||||
for excuse in excuses.iter() {
|
||||
let ptr_to_ptr = GuestType::read(&excuse.expect("valid ptr to ptr"))
|
||||
let ptr_to_excuse = excuse
|
||||
.expect("valid ptr to ptr")
|
||||
.read()
|
||||
.expect("valid ptr to some Excuse value");
|
||||
let mut ptr = ptr_to_ptr
|
||||
.as_ref_mut()
|
||||
ptr_to_excuse
|
||||
.write(types::Excuse::Sleeping)
|
||||
.expect("dereferencing mut ptr should succeed");
|
||||
*ptr = types::Excuse::Sleeping;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -43,7 +43,6 @@ struct ReduceExcusesExcercise {
|
||||
excuse_values: Vec<types::Excuse>,
|
||||
excuse_ptr_locs: Vec<MemArea>,
|
||||
array_ptr_loc: MemArea,
|
||||
array_len_loc: MemArea,
|
||||
return_ptr_loc: MemArea,
|
||||
}
|
||||
|
||||
@@ -57,22 +56,18 @@ impl ReduceExcusesExcercise {
|
||||
proptest::collection::vec(HostMemory::mem_area_strat(4), len_usize..=len_usize),
|
||||
HostMemory::mem_area_strat(4 * len),
|
||||
HostMemory::mem_area_strat(4),
|
||||
HostMemory::mem_area_strat(4),
|
||||
)
|
||||
})
|
||||
.prop_map(
|
||||
|(excuse_values, excuse_ptr_locs, array_ptr_loc, array_len_loc, return_ptr_loc)| {
|
||||
Self {
|
||||
excuse_values,
|
||||
excuse_ptr_locs,
|
||||
array_ptr_loc,
|
||||
array_len_loc,
|
||||
return_ptr_loc,
|
||||
}
|
||||
|(excuse_values, excuse_ptr_locs, array_ptr_loc, return_ptr_loc)| Self {
|
||||
excuse_values,
|
||||
excuse_ptr_locs,
|
||||
array_ptr_loc,
|
||||
return_ptr_loc,
|
||||
},
|
||||
)
|
||||
.prop_filter("non-overlapping pointers", |e| {
|
||||
let mut all = vec![&e.array_ptr_loc, &e.array_len_loc, &e.return_ptr_loc];
|
||||
let mut all = vec![&e.array_ptr_loc, &e.return_ptr_loc];
|
||||
all.extend(e.excuse_ptr_locs.iter());
|
||||
MemArea::non_overlapping_set(&all)
|
||||
})
|
||||
@@ -82,44 +77,31 @@ impl ReduceExcusesExcercise {
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
|
||||
// Populate memory with pointers to generated Excuse values
|
||||
for (&excuse, ptr) in self.excuse_values.iter().zip(self.excuse_ptr_locs.iter()) {
|
||||
*guest_memory
|
||||
.ptr_mut(ptr.ptr)
|
||||
.expect("ptr mut to Excuse value")
|
||||
.as_ref_mut()
|
||||
.expect("deref ptr mut to Excuse value") = excuse;
|
||||
host_memory
|
||||
.ptr(ptr.ptr)
|
||||
.write(excuse)
|
||||
.expect("deref ptr mut to Excuse value");
|
||||
}
|
||||
|
||||
// Populate array length info
|
||||
*guest_memory
|
||||
.ptr_mut(self.array_len_loc.ptr)
|
||||
.expect("ptr to array len")
|
||||
.as_ref_mut()
|
||||
.expect("deref ptr mut to array len") = self.excuse_ptr_locs.len() as u32;
|
||||
|
||||
// Populate the array with pointers to generated Excuse values
|
||||
{
|
||||
let mut next: GuestPtrMut<'_, GuestPtr<types::Excuse>> = guest_memory
|
||||
.ptr_mut(self.array_ptr_loc.ptr)
|
||||
.expect("ptr to array mut");
|
||||
for ptr in &self.excuse_ptr_locs {
|
||||
next.write(
|
||||
&guest_memory
|
||||
.ptr::<types::Excuse>(ptr.ptr)
|
||||
.expect("ptr to Excuse value"),
|
||||
);
|
||||
next = next.elem(1).expect("increment ptr by 1");
|
||||
let array: GuestPtr<'_, [GuestPtr<types::Excuse>]> =
|
||||
host_memory.ptr((self.array_ptr_loc.ptr, self.excuse_ptr_locs.len() as u32));
|
||||
for (slot, ptr) in array.iter().zip(&self.excuse_ptr_locs) {
|
||||
let slot = slot.expect("array should be in bounds");
|
||||
slot.write(host_memory.ptr(ptr.ptr))
|
||||
.expect("should succeed in writing array");
|
||||
}
|
||||
}
|
||||
|
||||
let res = arrays::reduce_excuses(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&mut host_memory,
|
||||
self.array_ptr_loc.ptr as i32,
|
||||
self.array_len_loc.ptr as i32,
|
||||
self.excuse_ptr_locs.len() as i32,
|
||||
self.return_ptr_loc.ptr as i32,
|
||||
);
|
||||
|
||||
@@ -129,10 +111,9 @@ impl ReduceExcusesExcercise {
|
||||
.excuse_values
|
||||
.last()
|
||||
.expect("generated vec of excuses should be non-empty");
|
||||
let given: types::Excuse = *guest_memory
|
||||
let given: types::Excuse = host_memory
|
||||
.ptr(self.return_ptr_loc.ptr)
|
||||
.expect("ptr to returned value")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("deref ptr to returned value");
|
||||
assert_eq!(expected, given, "reduce excuses return val");
|
||||
}
|
||||
@@ -156,7 +137,6 @@ fn excuse_strat() -> impl Strategy<Value = types::Excuse> {
|
||||
#[derive(Debug)]
|
||||
struct PopulateExcusesExcercise {
|
||||
array_ptr_loc: MemArea,
|
||||
array_len_loc: MemArea,
|
||||
elements: Vec<MemArea>,
|
||||
}
|
||||
|
||||
@@ -167,17 +147,15 @@ impl PopulateExcusesExcercise {
|
||||
let len_usize = len as usize;
|
||||
(
|
||||
HostMemory::mem_area_strat(4 * len),
|
||||
HostMemory::mem_area_strat(4),
|
||||
proptest::collection::vec(HostMemory::mem_area_strat(4), len_usize..=len_usize),
|
||||
)
|
||||
})
|
||||
.prop_map(|(array_ptr_loc, array_len_loc, elements)| Self {
|
||||
.prop_map(|(array_ptr_loc, elements)| Self {
|
||||
array_ptr_loc,
|
||||
array_len_loc,
|
||||
elements,
|
||||
})
|
||||
.prop_filter("non-overlapping pointers", |e| {
|
||||
let mut all = vec![&e.array_ptr_loc, &e.array_len_loc];
|
||||
let mut all = vec![&e.array_ptr_loc];
|
||||
all.extend(e.elements.iter());
|
||||
MemArea::non_overlapping_set(&all)
|
||||
})
|
||||
@@ -185,51 +163,38 @@ impl PopulateExcusesExcercise {
|
||||
}
|
||||
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
|
||||
// Populate array length info
|
||||
*guest_memory
|
||||
.ptr_mut(self.array_len_loc.ptr)
|
||||
.expect("ptr mut to array len")
|
||||
.as_ref_mut()
|
||||
.expect("deref ptr mut to array len") = self.elements.len() as u32;
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
// Populate array with valid pointers to Excuse type in memory
|
||||
{
|
||||
let mut next: GuestPtrMut<'_, GuestPtrMut<types::Excuse>> = guest_memory
|
||||
.ptr_mut(self.array_ptr_loc.ptr)
|
||||
.expect("ptr mut to the first element of array");
|
||||
for ptr in &self.elements {
|
||||
next.write(
|
||||
&guest_memory
|
||||
.ptr_mut::<types::Excuse>(ptr.ptr)
|
||||
.expect("ptr mut to Excuse value"),
|
||||
);
|
||||
next = next.elem(1).expect("increment ptr by 1");
|
||||
}
|
||||
let ptr = host_memory.ptr::<[GuestPtr<'_, types::Excuse>]>((
|
||||
self.array_ptr_loc.ptr,
|
||||
self.elements.len() as u32,
|
||||
));
|
||||
for (ptr, val) in ptr.iter().zip(&self.elements) {
|
||||
ptr.expect("should be valid pointer")
|
||||
.write(host_memory.ptr(val.ptr))
|
||||
.expect("failed to write value");
|
||||
}
|
||||
|
||||
let res = arrays::populate_excuses(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.array_ptr_loc.ptr as i32,
|
||||
self.array_len_loc.ptr as i32,
|
||||
self.elements.len() as i32,
|
||||
);
|
||||
assert_eq!(res, types::Errno::Ok.into(), "populate excuses errno");
|
||||
|
||||
let arr: GuestArray<'_, GuestPtr<'_, types::Excuse>> = guest_memory
|
||||
.ptr(self.array_ptr_loc.ptr)
|
||||
.expect("ptr to the first element of array")
|
||||
.array(self.elements.len() as u32)
|
||||
.expect("as array");
|
||||
let arr: GuestPtr<'_, [GuestPtr<'_, types::Excuse>]> =
|
||||
host_memory.ptr((self.array_ptr_loc.ptr, self.elements.len() as u32));
|
||||
for el in arr.iter() {
|
||||
let ptr_to_ptr = GuestType::read(&el.expect("valid ptr to ptr"))
|
||||
let ptr_to_ptr = el
|
||||
.expect("valid ptr to ptr")
|
||||
.read()
|
||||
.expect("valid ptr to some Excuse value");
|
||||
assert_eq!(
|
||||
*ptr_to_ptr
|
||||
.as_ref()
|
||||
ptr_to_ptr
|
||||
.read()
|
||||
.expect("dereferencing ptr to some Excuse value"),
|
||||
types::Excuse::Sleeping,
|
||||
"element should equal Excuse::Sleeping"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use proptest::prelude::*;
|
||||
use wiggle_runtime::{GuestError, GuestRef};
|
||||
use wiggle_runtime::{GuestError, GuestMemory};
|
||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||
|
||||
wiggle::from_witx!({
|
||||
@@ -29,16 +29,10 @@ struct IntFloatExercise {
|
||||
|
||||
impl IntFloatExercise {
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
let e = atoms::int_float_args(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
self.an_int as i32,
|
||||
self.an_float,
|
||||
);
|
||||
let e = atoms::int_float_args(&ctx, &host_memory, self.an_int as i32, self.an_float);
|
||||
|
||||
assert_eq!(e, types::Errno::Ok.into(), "int_float_args error");
|
||||
}
|
||||
@@ -64,24 +58,22 @@ struct DoubleIntExercise {
|
||||
|
||||
impl DoubleIntExercise {
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
let e = atoms::double_int_return_float(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.input as i32,
|
||||
self.return_loc.ptr as i32,
|
||||
);
|
||||
|
||||
let return_val: GuestRef<types::AliasToFloat> = guest_memory
|
||||
.ptr(self.return_loc.ptr)
|
||||
.expect("return loc ptr")
|
||||
.as_ref()
|
||||
.expect("return val ref");
|
||||
let return_val = host_memory
|
||||
.ptr::<types::AliasToFloat>(self.return_loc.ptr)
|
||||
.read()
|
||||
.expect("failed to read return");
|
||||
assert_eq!(e, types::Errno::Ok.into(), "errno");
|
||||
assert_eq!(*return_val, (self.input as f32) * 2.0, "return val");
|
||||
assert_eq!(return_val, (self.input as f32) * 2.0, "return val");
|
||||
}
|
||||
|
||||
pub fn strat() -> BoxedStrategy<Self> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use proptest::prelude::*;
|
||||
use std::convert::TryFrom;
|
||||
use wiggle_runtime::{GuestError, GuestPtr};
|
||||
use wiggle_runtime::{GuestError, GuestMemory, GuestPtr};
|
||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||
|
||||
wiggle::from_witx!({
|
||||
@@ -16,7 +16,7 @@ impl flags::Flags for WasiCtx {
|
||||
old_config: types::CarConfig,
|
||||
other_config_ptr: GuestPtr<types::CarConfig>,
|
||||
) -> Result<types::CarConfig, types::Errno> {
|
||||
let other_config = *other_config_ptr.as_ref().map_err(|e| {
|
||||
let other_config = other_config_ptr.read().map_err(|e| {
|
||||
eprintln!("old_config_ptr error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
@@ -63,30 +63,27 @@ impl ConfigureCarExercise {
|
||||
}
|
||||
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
// Populate input ptr
|
||||
*guest_memory
|
||||
.ptr_mut(self.other_config_by_ptr.ptr)
|
||||
.expect("ptr mut to CarConfig")
|
||||
.as_ref_mut()
|
||||
.expect("deref ptr mut to CarConfig") = self.other_config;
|
||||
host_memory
|
||||
.ptr(self.other_config_by_ptr.ptr)
|
||||
.write(self.other_config)
|
||||
.expect("deref ptr mut to CarConfig");
|
||||
|
||||
let res = flags::configure_car(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.old_config.into(),
|
||||
self.other_config_by_ptr.ptr as i32,
|
||||
self.return_ptr_loc.ptr as i32,
|
||||
);
|
||||
assert_eq!(res, types::Errno::Ok.into(), "configure car errno");
|
||||
|
||||
let res_config = *guest_memory
|
||||
let res_config = host_memory
|
||||
.ptr::<types::CarConfig>(self.return_ptr_loc.ptr)
|
||||
.expect("ptr to returned CarConfig")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("deref to CarConfig value");
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use proptest::prelude::*;
|
||||
use wiggle_runtime::{GuestError, GuestType};
|
||||
use wiggle_runtime::{GuestError, GuestType, GuestMemory};
|
||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||
|
||||
const FD_VAL: u32 = 123;
|
||||
@@ -32,27 +32,25 @@ struct HandleExercise {
|
||||
|
||||
impl HandleExercise {
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
let e = handle_examples::fd_create(&mut ctx, &mut guest_memory, self.return_loc.ptr as i32);
|
||||
let e = handle_examples::fd_create(&ctx, &host_memory, self.return_loc.ptr as i32);
|
||||
|
||||
assert_eq!(e, types::Errno::Ok.into(), "fd_create error");
|
||||
|
||||
let h_got: u32 = *guest_memory
|
||||
let h_got: u32 = host_memory
|
||||
.ptr(self.return_loc.ptr)
|
||||
.expect("return ptr")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("return ref_mut");
|
||||
|
||||
assert_eq!(h_got, 123, "fd_create return val");
|
||||
|
||||
let e = handle_examples::fd_consume(&mut ctx, &mut guest_memory, h_got as i32);
|
||||
let e = handle_examples::fd_consume(&ctx, &host_memory, h_got as i32);
|
||||
|
||||
assert_eq!(e, types::Errno::Ok.into(), "fd_consume error");
|
||||
|
||||
let e = handle_examples::fd_consume(&mut ctx, &mut guest_memory, h_got as i32 + 1);
|
||||
let e = handle_examples::fd_consume(&ctx, &host_memory, h_got as i32 + 1);
|
||||
|
||||
assert_eq!(
|
||||
e,
|
||||
@@ -62,7 +60,7 @@ impl HandleExercise {
|
||||
}
|
||||
|
||||
pub fn strat() -> BoxedStrategy<Self> {
|
||||
(HostMemory::mem_area_strat(types::Fd::size()))
|
||||
(HostMemory::mem_area_strat(types::Fd::guest_size()))
|
||||
.prop_map(|return_loc| HandleExercise { return_loc })
|
||||
.boxed()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use proptest::prelude::*;
|
||||
use std::convert::TryFrom;
|
||||
use wiggle_runtime::GuestError;
|
||||
use wiggle_runtime::{GuestError, GuestMemory};
|
||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||
|
||||
wiggle::from_witx!({
|
||||
@@ -44,22 +44,20 @@ impl CookieCutterExercise {
|
||||
}
|
||||
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
let res = ints::cookie_cutter(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.cookie.into(),
|
||||
self.return_ptr_loc.ptr as i32,
|
||||
);
|
||||
assert_eq!(res, types::Errno::Ok.into(), "cookie cutter errno");
|
||||
|
||||
let is_cookie_start = *guest_memory
|
||||
let is_cookie_start = host_memory
|
||||
.ptr::<types::Bool>(self.return_ptr_loc.ptr)
|
||||
.expect("ptr to returned Bool")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("deref to Bool value");
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use proptest::prelude::*;
|
||||
use wiggle_runtime::{GuestError, GuestPtr, GuestPtrMut, GuestRefMut, GuestType};
|
||||
use wiggle_runtime::{GuestError, GuestMemory, GuestPtr};
|
||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||
|
||||
wiggle::from_witx!({
|
||||
@@ -10,49 +10,52 @@ wiggle::from_witx!({
|
||||
impl_errno!(types::Errno);
|
||||
|
||||
impl pointers::Pointers for WasiCtx {
|
||||
fn pointers_and_enums(
|
||||
fn pointers_and_enums<'a>(
|
||||
&self,
|
||||
input1: types::Excuse,
|
||||
input2_ptr: GuestPtrMut<types::Excuse>,
|
||||
input3_ptr: GuestPtr<types::Excuse>,
|
||||
input4_ptr_ptr: GuestPtrMut<GuestPtr<types::Excuse>>,
|
||||
input2_ptr: GuestPtr<'a, types::Excuse>,
|
||||
input3_ptr: GuestPtr<'a, types::Excuse>,
|
||||
input4_ptr_ptr: GuestPtr<'a, GuestPtr<'a, types::Excuse>>,
|
||||
) -> Result<(), types::Errno> {
|
||||
println!("BAZ input1 {:?}", input1);
|
||||
// Read enum value from mutable:
|
||||
let mut input2_ref: GuestRefMut<types::Excuse> = input2_ptr.as_ref_mut().map_err(|e| {
|
||||
let input2: types::Excuse = input2_ptr.read().map_err(|e| {
|
||||
eprintln!("input2_ptr error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
let input2: types::Excuse = *input2_ref;
|
||||
println!("input2 {:?}", input2);
|
||||
|
||||
// Read enum value from immutable ptr:
|
||||
let input3 = *input3_ptr.as_ref().map_err(|e| {
|
||||
let input3 = input3_ptr.read().map_err(|e| {
|
||||
eprintln!("input3_ptr error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
println!("input3 {:?}", input3);
|
||||
|
||||
// Write enum to mutable ptr:
|
||||
*input2_ref = input3;
|
||||
input2_ptr.write(input3).map_err(|e| {
|
||||
eprintln!("input2_ptr error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
println!("wrote to input2_ref {:?}", input3);
|
||||
|
||||
// Read ptr value from mutable ptr:
|
||||
let input4_ptr: GuestPtr<types::Excuse> = GuestType::read(&input4_ptr_ptr.as_immut())
|
||||
.map_err(|e| {
|
||||
eprintln!("input4_ptr_ptr error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
let input4_ptr: GuestPtr<types::Excuse> = input4_ptr_ptr.read().map_err(|e| {
|
||||
eprintln!("input4_ptr_ptr error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
|
||||
// Read enum value from that ptr:
|
||||
let input4: types::Excuse = *input4_ptr.as_ref().map_err(|e| {
|
||||
let input4: types::Excuse = input4_ptr.read().map_err(|e| {
|
||||
eprintln!("input4_ptr error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
println!("input4 {:?}", input4);
|
||||
|
||||
// Write ptr value to mutable ptr:
|
||||
input4_ptr_ptr.write(&input2_ptr.as_immut());
|
||||
input4_ptr_ptr.write(input2_ptr).map_err(|e| {
|
||||
eprintln!("input4_ptr_ptr error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -123,37 +126,32 @@ impl PointersAndEnumsExercise {
|
||||
.boxed()
|
||||
}
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
*guest_memory
|
||||
.ptr_mut(self.input2_loc.ptr)
|
||||
.expect("input2 ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input2 ref_mut") = self.input2;
|
||||
host_memory
|
||||
.ptr(self.input2_loc.ptr)
|
||||
.write(self.input2)
|
||||
.expect("input2 ref_mut");
|
||||
|
||||
*guest_memory
|
||||
.ptr_mut(self.input3_loc.ptr)
|
||||
.expect("input3 ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input3 ref_mut") = self.input3;
|
||||
host_memory
|
||||
.ptr(self.input3_loc.ptr)
|
||||
.write(self.input3)
|
||||
.expect("input3 ref_mut");
|
||||
|
||||
*guest_memory
|
||||
.ptr_mut(self.input4_loc.ptr)
|
||||
.expect("input4 ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input4 ref_mut") = self.input4;
|
||||
host_memory
|
||||
.ptr(self.input4_loc.ptr)
|
||||
.write(self.input4)
|
||||
.expect("input4 ref_mut");
|
||||
|
||||
*guest_memory
|
||||
.ptr_mut(self.input4_ptr_loc.ptr)
|
||||
.expect("input4 ptr ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input4 ptr ref_mut") = self.input4_loc.ptr;
|
||||
host_memory
|
||||
.ptr(self.input4_ptr_loc.ptr)
|
||||
.write(self.input4_loc.ptr)
|
||||
.expect("input4 ptr ref_mut");
|
||||
|
||||
let e = pointers::pointers_and_enums(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.input1.into(),
|
||||
self.input2_loc.ptr as i32,
|
||||
self.input3_loc.ptr as i32,
|
||||
@@ -162,10 +160,9 @@ impl PointersAndEnumsExercise {
|
||||
assert_eq!(e, types::Errno::Ok.into(), "errno");
|
||||
|
||||
// Implementation of pointers_and_enums writes input3 to the input2_loc:
|
||||
let written_to_input2_loc: i32 = *guest_memory
|
||||
let written_to_input2_loc: i32 = host_memory
|
||||
.ptr(self.input2_loc.ptr)
|
||||
.expect("input2 ptr")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("input2 ref");
|
||||
|
||||
assert_eq!(
|
||||
@@ -175,10 +172,9 @@ impl PointersAndEnumsExercise {
|
||||
);
|
||||
|
||||
// Implementation of pointers_and_enums writes input2_loc to input4_ptr_loc:
|
||||
let written_to_input4_ptr: u32 = *guest_memory
|
||||
let written_to_input4_ptr: u32 = host_memory
|
||||
.ptr(self.input4_ptr_loc.ptr)
|
||||
.expect("input4_ptr_loc ptr")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("input4_ptr_loc ref");
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use proptest::prelude::*;
|
||||
use wiggle_runtime::{GuestError, GuestPtrMut, GuestString};
|
||||
use wiggle_runtime::{GuestError, GuestMemory, GuestPtr};
|
||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||
|
||||
wiggle::from_witx!({
|
||||
@@ -10,11 +10,12 @@ wiggle::from_witx!({
|
||||
impl_errno!(types::Errno);
|
||||
|
||||
impl strings::Strings for WasiCtx {
|
||||
fn hello_string(&self, a_string: &GuestString<'_>) -> Result<u32, types::Errno> {
|
||||
let as_ref = a_string.as_ref().expect("deref ptr should succeed");
|
||||
let as_str = as_ref.as_str().expect("valid UTF-8 string");
|
||||
println!("a_string='{}'", as_str);
|
||||
Ok(as_str.len() as u32)
|
||||
fn hello_string(&self, a_string: &GuestPtr<str>) -> Result<u32, types::Errno> {
|
||||
let s = a_string.as_raw().expect("should be valid string");
|
||||
unsafe {
|
||||
println!("a_string='{}'", &*s);
|
||||
Ok((*s).len() as u32)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +27,6 @@ fn test_string_strategy() -> impl Strategy<Value = String> {
|
||||
struct HelloStringExercise {
|
||||
test_word: String,
|
||||
string_ptr_loc: MemArea,
|
||||
string_len_loc: MemArea,
|
||||
return_ptr_loc: MemArea,
|
||||
}
|
||||
|
||||
@@ -38,63 +38,43 @@ impl HelloStringExercise {
|
||||
Just(test_word.clone()),
|
||||
HostMemory::mem_area_strat(test_word.len() as u32),
|
||||
HostMemory::mem_area_strat(4),
|
||||
HostMemory::mem_area_strat(4),
|
||||
)
|
||||
})
|
||||
.prop_map(
|
||||
|(test_word, string_ptr_loc, string_len_loc, return_ptr_loc)| Self {
|
||||
test_word,
|
||||
string_ptr_loc,
|
||||
string_len_loc,
|
||||
return_ptr_loc,
|
||||
},
|
||||
)
|
||||
.prop_map(|(test_word, string_ptr_loc, return_ptr_loc)| Self {
|
||||
test_word,
|
||||
string_ptr_loc,
|
||||
return_ptr_loc,
|
||||
})
|
||||
.prop_filter("non-overlapping pointers", |e| {
|
||||
MemArea::non_overlapping_set(&[
|
||||
&e.string_ptr_loc,
|
||||
&e.string_len_loc,
|
||||
&e.return_ptr_loc,
|
||||
])
|
||||
MemArea::non_overlapping_set(&[&e.string_ptr_loc, &e.return_ptr_loc])
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
|
||||
// Populate string length
|
||||
*guest_memory
|
||||
.ptr_mut(self.string_len_loc.ptr)
|
||||
.expect("ptr mut to string len")
|
||||
.as_ref_mut()
|
||||
.expect("deref ptr mut to string len") = self.test_word.len() as u32;
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
// Populate string in guest's memory
|
||||
{
|
||||
let mut next: GuestPtrMut<'_, u8> = guest_memory
|
||||
.ptr_mut(self.string_ptr_loc.ptr)
|
||||
.expect("ptr mut to the first byte of string");
|
||||
for byte in self.test_word.as_bytes() {
|
||||
*next.as_ref_mut().expect("deref mut") = *byte;
|
||||
next = next.elem(1).expect("increment ptr by 1");
|
||||
}
|
||||
let ptr = host_memory.ptr::<str>((self.string_ptr_loc.ptr, self.test_word.len() as u32));
|
||||
for (slot, byte) in ptr.as_bytes().iter().zip(self.test_word.bytes()) {
|
||||
slot.expect("should be valid pointer")
|
||||
.write(byte)
|
||||
.expect("failed to write");
|
||||
}
|
||||
|
||||
let res = strings::hello_string(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.string_ptr_loc.ptr as i32,
|
||||
self.string_len_loc.ptr as i32,
|
||||
self.test_word.len() as i32,
|
||||
self.return_ptr_loc.ptr as i32,
|
||||
);
|
||||
assert_eq!(res, types::Errno::Ok.into(), "hello string errno");
|
||||
|
||||
let given = *guest_memory
|
||||
let given = host_memory
|
||||
.ptr::<u32>(self.return_ptr_loc.ptr)
|
||||
.expect("ptr to return value")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("deref ptr to return value");
|
||||
assert_eq!(self.test_word.len() as u32, given);
|
||||
}
|
||||
|
||||
201
tests/structs.rs
201
tests/structs.rs
@@ -1,5 +1,5 @@
|
||||
use proptest::prelude::*;
|
||||
use wiggle_runtime::{GuestError, GuestPtr};
|
||||
use wiggle_runtime::{GuestError, GuestMemory, GuestPtr};
|
||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||
|
||||
wiggle::from_witx!({
|
||||
@@ -15,21 +15,21 @@ impl structs::Structs for WasiCtx {
|
||||
}
|
||||
|
||||
fn sum_of_pair_of_ptrs(&self, an_pair: &types::PairIntPtrs) -> Result<i64, types::Errno> {
|
||||
let first = *an_pair
|
||||
let first = an_pair
|
||||
.first
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("dereferencing GuestPtr should succeed");
|
||||
let second = *an_pair
|
||||
let second = an_pair
|
||||
.second
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("dereferncing GuestPtr should succeed");
|
||||
Ok(first as i64 + second as i64)
|
||||
}
|
||||
|
||||
fn sum_of_int_and_ptr(&self, an_pair: &types::PairIntAndPtr) -> Result<i64, types::Errno> {
|
||||
let first = *an_pair
|
||||
let first = an_pair
|
||||
.first
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("dereferencing GuestPtr should succeed");
|
||||
let second = an_pair.second as i64;
|
||||
Ok(first as i64 + second)
|
||||
@@ -78,33 +78,29 @@ impl SumOfPairExercise {
|
||||
}
|
||||
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_loc.ptr)
|
||||
.expect("input ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input ref_mut") = self.input.first;
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_loc.ptr + 4)
|
||||
.expect("input ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input ref_mut") = self.input.second;
|
||||
host_memory
|
||||
.ptr(self.input_loc.ptr)
|
||||
.write(self.input.first)
|
||||
.expect("input ref_mut");
|
||||
host_memory
|
||||
.ptr(self.input_loc.ptr + 4)
|
||||
.write(self.input.second)
|
||||
.expect("input ref_mut");
|
||||
let sum_err = structs::sum_of_pair(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.input_loc.ptr as i32,
|
||||
self.return_loc.ptr as i32,
|
||||
);
|
||||
|
||||
assert_eq!(sum_err, types::Errno::Ok.into(), "sum errno");
|
||||
|
||||
let return_val: i64 = *guest_memory
|
||||
let return_val: i64 = host_memory
|
||||
.ptr(self.return_loc.ptr)
|
||||
.expect("return ptr")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("return ref");
|
||||
|
||||
assert_eq!(
|
||||
@@ -170,45 +166,39 @@ impl SumPairPtrsExercise {
|
||||
.boxed()
|
||||
}
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_first_loc.ptr)
|
||||
.expect("input_first ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input_first ref") = self.input_first;
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_second_loc.ptr)
|
||||
.expect("input_second ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input_second ref") = self.input_second;
|
||||
host_memory
|
||||
.ptr(self.input_first_loc.ptr)
|
||||
.write(self.input_first)
|
||||
.expect("input_first ref");
|
||||
host_memory
|
||||
.ptr(self.input_second_loc.ptr)
|
||||
.write(self.input_second)
|
||||
.expect("input_second ref");
|
||||
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_struct_loc.ptr)
|
||||
.expect("input_struct ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input_struct ref") = self.input_first_loc.ptr;
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_struct_loc.ptr + 4)
|
||||
.expect("input_struct ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input_struct ref") = self.input_second_loc.ptr;
|
||||
host_memory
|
||||
.ptr(self.input_struct_loc.ptr)
|
||||
.write(self.input_first_loc.ptr)
|
||||
.expect("input_struct ref");
|
||||
host_memory
|
||||
.ptr(self.input_struct_loc.ptr + 4)
|
||||
.write(self.input_second_loc.ptr)
|
||||
.expect("input_struct ref");
|
||||
|
||||
let res = structs::sum_of_pair_of_ptrs(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.input_struct_loc.ptr as i32,
|
||||
self.return_loc.ptr as i32,
|
||||
);
|
||||
|
||||
assert_eq!(res, types::Errno::Ok.into(), "sum of pair of ptrs errno");
|
||||
|
||||
let doubled: i64 = *guest_memory
|
||||
let doubled: i64 = host_memory
|
||||
.ptr(self.return_loc.ptr)
|
||||
.expect("return ptr")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("return ref");
|
||||
|
||||
assert_eq!(
|
||||
@@ -264,39 +254,34 @@ impl SumIntAndPtrExercise {
|
||||
.boxed()
|
||||
}
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_first_loc.ptr)
|
||||
.expect("input_first ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input_first ref") = self.input_first;
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_struct_loc.ptr)
|
||||
.expect("input_struct ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input_struct ref") = self.input_first_loc.ptr;
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_struct_loc.ptr + 4)
|
||||
.expect("input_struct ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input_struct ref") = self.input_second;
|
||||
host_memory
|
||||
.ptr(self.input_first_loc.ptr)
|
||||
.write(self.input_first)
|
||||
.expect("input_first ref");
|
||||
host_memory
|
||||
.ptr(self.input_struct_loc.ptr)
|
||||
.write(self.input_first_loc.ptr)
|
||||
.expect("input_struct ref");
|
||||
host_memory
|
||||
.ptr(self.input_struct_loc.ptr + 4)
|
||||
.write(self.input_second)
|
||||
.expect("input_struct ref");
|
||||
|
||||
let res = structs::sum_of_int_and_ptr(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.input_struct_loc.ptr as i32,
|
||||
self.return_loc.ptr as i32,
|
||||
);
|
||||
|
||||
assert_eq!(res, types::Errno::Ok.into(), "sum of int and ptr errno");
|
||||
|
||||
let doubled: i64 = *guest_memory
|
||||
let doubled: i64 = host_memory
|
||||
.ptr(self.return_loc.ptr)
|
||||
.expect("return ptr")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("return ref");
|
||||
|
||||
assert_eq!(
|
||||
@@ -326,19 +311,16 @@ impl ReturnPairInts {
|
||||
}
|
||||
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
let err =
|
||||
structs::return_pair_ints(&mut ctx, &mut guest_memory, self.return_loc.ptr as i32);
|
||||
let err = structs::return_pair_ints(&ctx, &host_memory, self.return_loc.ptr as i32);
|
||||
|
||||
assert_eq!(err, types::Errno::Ok.into(), "return struct errno");
|
||||
|
||||
let return_struct: types::PairInts = *guest_memory
|
||||
let return_struct: types::PairInts = host_memory
|
||||
.ptr(self.return_loc.ptr)
|
||||
.expect("return ptr")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("return ref");
|
||||
|
||||
assert_eq!(
|
||||
@@ -398,24 +380,21 @@ impl ReturnPairPtrsExercise {
|
||||
.boxed()
|
||||
}
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_first_loc.ptr)
|
||||
.expect("input_first ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input_first ref") = self.input_first;
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_second_loc.ptr)
|
||||
.expect("input_second ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input_second ref") = self.input_second;
|
||||
host_memory
|
||||
.ptr(self.input_first_loc.ptr)
|
||||
.write(self.input_first)
|
||||
.expect("input_first ref");
|
||||
host_memory
|
||||
.ptr(self.input_second_loc.ptr)
|
||||
.write(self.input_second)
|
||||
.expect("input_second ref");
|
||||
|
||||
let res = structs::return_pair_of_ptrs(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.input_first_loc.ptr as i32,
|
||||
self.input_second_loc.ptr as i32,
|
||||
self.return_loc.ptr as i32,
|
||||
@@ -423,28 +402,20 @@ impl ReturnPairPtrsExercise {
|
||||
|
||||
assert_eq!(res, types::Errno::Ok.into(), "return pair of ptrs errno");
|
||||
|
||||
let ptr_pair_int_ptrs: GuestPtr<types::PairIntPtrs<'_>> =
|
||||
guest_memory.ptr(self.return_loc.ptr).expect("return ptr");
|
||||
let ret_first_ptr: GuestPtr<i32> = ptr_pair_int_ptrs
|
||||
.cast::<GuestPtr<i32>>(0u32)
|
||||
.expect("extract ptr to first element in struct")
|
||||
.read()
|
||||
.expect("read ptr to first element in struct");
|
||||
let ret_second_ptr: GuestPtr<i32> = ptr_pair_int_ptrs
|
||||
.cast::<GuestPtr<i32>>(4u32)
|
||||
.expect("extract ptr to second element in struct")
|
||||
.read()
|
||||
.expect("read ptr to second element in struct");
|
||||
let ptr_pair_int_ptrs: types::PairIntPtrs<'_> =
|
||||
host_memory.ptr(self.return_loc.ptr).read().expect("failed to read return location");
|
||||
let ret_first_ptr = ptr_pair_int_ptrs.first;
|
||||
let ret_second_ptr = ptr_pair_int_ptrs.second;
|
||||
assert_eq!(
|
||||
self.input_first,
|
||||
*ret_first_ptr
|
||||
.as_ref()
|
||||
ret_first_ptr
|
||||
.read()
|
||||
.expect("deref extracted ptr to first element")
|
||||
);
|
||||
assert_eq!(
|
||||
self.input_second,
|
||||
*ret_second_ptr
|
||||
.as_ref()
|
||||
ret_second_ptr
|
||||
.read()
|
||||
.expect("deref extracted ptr to second element")
|
||||
);
|
||||
}
|
||||
|
||||
118
tests/union.rs
118
tests/union.rs
@@ -1,5 +1,5 @@
|
||||
use proptest::prelude::*;
|
||||
use wiggle_runtime::{GuestError, GuestType};
|
||||
use wiggle_runtime::{GuestError, GuestMemory, GuestType};
|
||||
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
|
||||
|
||||
wiggle::from_witx!({
|
||||
@@ -43,16 +43,16 @@ impl union_example::UnionExample for WasiCtx {
|
||||
fn reason_mult(&self, u: &types::ReasonMut<'_>, multiply_by: u32) -> Result<(), types::Errno> {
|
||||
match u {
|
||||
types::ReasonMut::DogAte(fptr) => {
|
||||
let mut f = fptr.as_ref_mut().expect("valid pointer");
|
||||
let val = *f;
|
||||
let val = fptr.read().expect("valid pointer");
|
||||
println!("REASON MULT DogAte({})", val);
|
||||
*f = mult_zero_nan(val, multiply_by);
|
||||
fptr.write(mult_zero_nan(val, multiply_by))
|
||||
.expect("valid pointer");
|
||||
}
|
||||
types::ReasonMut::Traffic(iptr) => {
|
||||
let mut i = iptr.as_ref_mut().expect("valid pointer");
|
||||
let val: i32 = *i;
|
||||
let val = iptr.read().expect("valid pointer");
|
||||
println!("REASON MULT Traffic({})", val);
|
||||
*i = mult_lose_overflow(val, multiply_by);
|
||||
iptr.write(mult_lose_overflow(val, multiply_by))
|
||||
.expect("valid pointer");
|
||||
}
|
||||
types::ReasonMut::Sleeping => {
|
||||
println!("REASON MULT Sleeping");
|
||||
@@ -90,8 +90,8 @@ impl GetTagExercise {
|
||||
pub fn strat() -> BoxedStrategy<Self> {
|
||||
(
|
||||
reason_strat(),
|
||||
HostMemory::mem_area_strat(types::Reason::size()),
|
||||
HostMemory::mem_area_strat(types::Excuse::size()),
|
||||
HostMemory::mem_area_strat(types::Reason::guest_size()),
|
||||
HostMemory::mem_area_strat(types::Excuse::guest_size()),
|
||||
)
|
||||
.prop_map(|(input, input_loc, return_loc)| GetTagExercise {
|
||||
input,
|
||||
@@ -105,46 +105,39 @@ impl GetTagExercise {
|
||||
}
|
||||
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
let discriminant: u8 = reason_tag(&self.input).into();
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_loc.ptr)
|
||||
.expect("input discriminant ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input discriminant ref_mut") = discriminant;
|
||||
host_memory
|
||||
.ptr(self.input_loc.ptr)
|
||||
.write(discriminant)
|
||||
.expect("input discriminant ptr");
|
||||
match self.input {
|
||||
types::Reason::DogAte(f) => {
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_loc.ptr + 4)
|
||||
.expect("input contents ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input contents ref_mut") = f;
|
||||
}
|
||||
types::Reason::Traffic(v) => {
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_loc.ptr + 4)
|
||||
.expect("input contents ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input contents ref_mut") = v;
|
||||
host_memory
|
||||
.ptr(self.input_loc.ptr + 4)
|
||||
.write(f)
|
||||
.expect("input contents ref_mut");
|
||||
}
|
||||
types::Reason::Traffic(v) => host_memory
|
||||
.ptr(self.input_loc.ptr + 4)
|
||||
.write(v)
|
||||
.expect("input contents ref_mut"),
|
||||
types::Reason::Sleeping => {} // Do nothing
|
||||
}
|
||||
let e = union_example::get_tag(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.input_loc.ptr as i32,
|
||||
self.return_loc.ptr as i32,
|
||||
);
|
||||
|
||||
assert_eq!(e, types::Errno::Ok.into(), "get_tag errno");
|
||||
|
||||
let return_val: types::Excuse = *guest_memory
|
||||
let return_val: types::Excuse = host_memory
|
||||
.ptr(self.return_loc.ptr)
|
||||
.expect("return ptr")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("return ref");
|
||||
|
||||
assert_eq!(return_val, reason_tag(&self.input), "get_tag return value");
|
||||
@@ -170,7 +163,7 @@ impl ReasonMultExercise {
|
||||
pub fn strat() -> BoxedStrategy<Self> {
|
||||
(
|
||||
reason_strat(),
|
||||
HostMemory::mem_area_strat(types::Reason::size()),
|
||||
HostMemory::mem_area_strat(types::Reason::guest_size()),
|
||||
HostMemory::mem_area_strat(4),
|
||||
prop::num::u32::ANY,
|
||||
)
|
||||
@@ -189,42 +182,37 @@ impl ReasonMultExercise {
|
||||
}
|
||||
|
||||
pub fn test(&self) {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let mut guest_memory = host_memory.guest_memory();
|
||||
let ctx = WasiCtx::new();
|
||||
let host_memory = HostMemory::new();
|
||||
|
||||
let discriminant: u8 = reason_tag(&self.input).into();
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_loc.ptr)
|
||||
.expect("input discriminant ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input discriminant ref_mut") = discriminant;
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_loc.ptr + 4)
|
||||
.expect("input pointer ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input pointer ref_mut") = self.input_pointee_loc.ptr;
|
||||
host_memory
|
||||
.ptr(self.input_loc.ptr)
|
||||
.write(discriminant)
|
||||
.expect("input discriminant ref_mut");
|
||||
host_memory
|
||||
.ptr(self.input_loc.ptr + 4)
|
||||
.write(self.input_pointee_loc.ptr)
|
||||
.expect("input pointer ref_mut");
|
||||
|
||||
match self.input {
|
||||
types::Reason::DogAte(f) => {
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_pointee_loc.ptr)
|
||||
.expect("input contents ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input contents ref_mut") = f;
|
||||
host_memory
|
||||
.ptr(self.input_pointee_loc.ptr)
|
||||
.write(f)
|
||||
.expect("input contents ref_mut");
|
||||
}
|
||||
types::Reason::Traffic(v) => {
|
||||
*guest_memory
|
||||
.ptr_mut(self.input_pointee_loc.ptr)
|
||||
.expect("input contents ptr")
|
||||
.as_ref_mut()
|
||||
.expect("input contents ref_mut") = v;
|
||||
host_memory
|
||||
.ptr(self.input_pointee_loc.ptr)
|
||||
.write(v)
|
||||
.expect("input contents ref_mut");
|
||||
}
|
||||
types::Reason::Sleeping => {} // Do nothing
|
||||
}
|
||||
let e = union_example::reason_mult(
|
||||
&mut ctx,
|
||||
&mut guest_memory,
|
||||
&ctx,
|
||||
&host_memory,
|
||||
self.input_loc.ptr as i32,
|
||||
self.multiply_by as i32,
|
||||
);
|
||||
@@ -233,10 +221,9 @@ impl ReasonMultExercise {
|
||||
|
||||
match self.input {
|
||||
types::Reason::DogAte(f) => {
|
||||
let f_result: f32 = *guest_memory
|
||||
let f_result: f32 = host_memory
|
||||
.ptr(self.input_pointee_loc.ptr)
|
||||
.expect("input contents ptr")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("input contents ref_mut");
|
||||
assert_eq!(
|
||||
mult_zero_nan(f, self.multiply_by),
|
||||
@@ -245,10 +232,9 @@ impl ReasonMultExercise {
|
||||
)
|
||||
}
|
||||
types::Reason::Traffic(v) => {
|
||||
let v_result: i32 = *guest_memory
|
||||
let v_result: i32 = host_memory
|
||||
.ptr(self.input_pointee_loc.ptr)
|
||||
.expect("input contents ptr")
|
||||
.as_ref()
|
||||
.read()
|
||||
.expect("input contents ref_mut");
|
||||
assert_eq!(
|
||||
mult_lose_overflow(v, self.multiply_by),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use wiggle_runtime::{GuestError, GuestErrorType, GuestPtr, GuestPtrMut, GuestString};
|
||||
use wiggle_runtime::{GuestError, GuestErrorType, GuestPtr};
|
||||
use wiggle_test::WasiCtx;
|
||||
|
||||
wiggle::from_witx!({
|
||||
@@ -25,8 +25,8 @@ impl GuestErrorType for types::Errno {
|
||||
impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
fn args_get(
|
||||
&self,
|
||||
_argv: GuestPtrMut<GuestPtrMut<u8>>,
|
||||
_argv_buf: GuestPtrMut<u8>,
|
||||
_argv: GuestPtr<GuestPtr<u8>>,
|
||||
_argv_buf: GuestPtr<u8>,
|
||||
) -> Result<()> {
|
||||
unimplemented!("args_get")
|
||||
}
|
||||
@@ -37,8 +37,8 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
|
||||
fn environ_get(
|
||||
&self,
|
||||
_environ: GuestPtrMut<GuestPtrMut<u8>>,
|
||||
_environ_buf: GuestPtrMut<u8>,
|
||||
_environ: GuestPtr<GuestPtr<u8>>,
|
||||
_environ_buf: GuestPtr<u8>,
|
||||
) -> Result<()> {
|
||||
unimplemented!("environ_get")
|
||||
}
|
||||
@@ -137,7 +137,7 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
fn fd_prestat_dir_name(
|
||||
&self,
|
||||
_fd: types::Fd,
|
||||
_path: GuestPtrMut<u8>,
|
||||
_path: GuestPtr<u8>,
|
||||
_path_len: types::Size,
|
||||
) -> Result<()> {
|
||||
unimplemented!("fd_prestat_dir_name")
|
||||
@@ -159,7 +159,7 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
fn fd_readdir(
|
||||
&self,
|
||||
_fd: types::Fd,
|
||||
_buf: GuestPtrMut<u8>,
|
||||
_buf: GuestPtr<u8>,
|
||||
_buf_len: types::Size,
|
||||
_cookie: types::Dircookie,
|
||||
) -> Result<types::Size> {
|
||||
@@ -191,7 +191,7 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
unimplemented!("fd_write")
|
||||
}
|
||||
|
||||
fn path_create_directory(&self, _fd: types::Fd, _path: &GuestString<'_>) -> Result<()> {
|
||||
fn path_create_directory(&self, _fd: types::Fd, _path: &GuestPtr<'_, str>) -> Result<()> {
|
||||
unimplemented!("path_create_directory")
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
&self,
|
||||
_fd: types::Fd,
|
||||
_flags: types::Lookupflags,
|
||||
_path: &GuestString<'_>,
|
||||
_path: &GuestPtr<'_, str>,
|
||||
) -> Result<types::Filestat> {
|
||||
unimplemented!("path_filestat_get")
|
||||
}
|
||||
@@ -208,7 +208,7 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
&self,
|
||||
_fd: types::Fd,
|
||||
_flags: types::Lookupflags,
|
||||
_path: &GuestString<'_>,
|
||||
_path: &GuestPtr<'_, str>,
|
||||
_atim: types::Timestamp,
|
||||
_mtim: types::Timestamp,
|
||||
_fst_flags: types::Fstflags,
|
||||
@@ -220,9 +220,9 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
&self,
|
||||
_old_fd: types::Fd,
|
||||
_old_flags: types::Lookupflags,
|
||||
_old_path: &GuestString<'_>,
|
||||
_old_path: &GuestPtr<'_, str>,
|
||||
_new_fd: types::Fd,
|
||||
_new_path: &GuestString<'_>,
|
||||
_new_path: &GuestPtr<'_, str>,
|
||||
) -> Result<()> {
|
||||
unimplemented!("path_link")
|
||||
}
|
||||
@@ -231,7 +231,7 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
&self,
|
||||
_fd: types::Fd,
|
||||
_dirflags: types::Lookupflags,
|
||||
_path: &GuestString<'_>,
|
||||
_path: &GuestPtr<'_, str>,
|
||||
_oflags: types::Oflags,
|
||||
_fs_rights_base: types::Rights,
|
||||
_fs_rights_inherting: types::Rights,
|
||||
@@ -243,44 +243,44 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
fn path_readlink(
|
||||
&self,
|
||||
_fd: types::Fd,
|
||||
_path: &GuestString<'_>,
|
||||
_buf: GuestPtrMut<u8>,
|
||||
_path: &GuestPtr<'_, str>,
|
||||
_buf: GuestPtr<u8>,
|
||||
_buf_len: types::Size,
|
||||
) -> Result<types::Size> {
|
||||
unimplemented!("path_readlink")
|
||||
}
|
||||
|
||||
fn path_remove_directory(&self, _fd: types::Fd, _path: &GuestString<'_>) -> Result<()> {
|
||||
fn path_remove_directory(&self, _fd: types::Fd, _path: &GuestPtr<'_, str>) -> Result<()> {
|
||||
unimplemented!("path_remove_directory")
|
||||
}
|
||||
|
||||
fn path_rename(
|
||||
&self,
|
||||
_fd: types::Fd,
|
||||
_old_path: &GuestString<'_>,
|
||||
_old_path: &GuestPtr<'_, str>,
|
||||
_new_fd: types::Fd,
|
||||
_new_path: &GuestString<'_>,
|
||||
_new_path: &GuestPtr<'_, str>,
|
||||
) -> Result<()> {
|
||||
unimplemented!("path_rename")
|
||||
}
|
||||
|
||||
fn path_symlink(
|
||||
&self,
|
||||
_old_path: &GuestString<'_>,
|
||||
_old_path: &GuestPtr<'_, str>,
|
||||
_fd: types::Fd,
|
||||
_new_path: &GuestString<'_>,
|
||||
_new_path: &GuestPtr<'_, str>,
|
||||
) -> Result<()> {
|
||||
unimplemented!("path_symlink")
|
||||
}
|
||||
|
||||
fn path_unlink_file(&self, _fd: types::Fd, _path: &GuestString<'_>) -> Result<()> {
|
||||
fn path_unlink_file(&self, _fd: types::Fd, _path: &GuestPtr<'_, str>) -> Result<()> {
|
||||
unimplemented!("path_unlink_file")
|
||||
}
|
||||
|
||||
fn poll_oneoff(
|
||||
&self,
|
||||
_in_: GuestPtr<types::Subscription>,
|
||||
_out: GuestPtrMut<types::Event>,
|
||||
_out: GuestPtr<types::Event>,
|
||||
_nsubscriptions: types::Size,
|
||||
) -> Result<types::Size> {
|
||||
unimplemented!("poll_oneoff")
|
||||
@@ -298,7 +298,7 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
unimplemented!("sched_yield")
|
||||
}
|
||||
|
||||
fn random_get(&self, _buf: GuestPtrMut<u8>, _buf_len: types::Size) -> Result<()> {
|
||||
fn random_get(&self, _buf: GuestPtr<u8>, _buf_len: types::Size) -> Result<()> {
|
||||
unimplemented!("random_get")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user