diff --git a/crates/generate/src/funcs.rs b/crates/generate/src/funcs.rs index eb3a02ac19..1902a9a6ff 100644 --- a/crates/generate/src/funcs.rs +++ b/crates/generate/src/funcs.rs @@ -1,7 +1,7 @@ use proc_macro2::TokenStream; use quote::quote; -use crate::lifetimes::{anon_lifetime, LifetimeExt}; +use crate::lifetimes::anon_lifetime; use crate::names::Names; pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { @@ -30,7 +30,7 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream { }); let abi_args = quote!( - ctx: &mut #ctx_type, memory: &mut wiggle_runtime::GuestMemory, + ctx: &#ctx_type, memory: &dyn wiggle_runtime::GuestMemory, #(#params),* ); let abi_ret = if let Some(ret) = &coretype.ret { @@ -158,13 +158,8 @@ fn marshal_arg( let arg_name = names.func_ptr_binding(¶m.name); let name = names.func_param(¶m.name); quote! { - let #name = match memory.ptr::<#pointee_type>(#arg_name as u32) { - Ok(p) => match p.read() { - Ok(r) => r, - Err(e) => { - #error_handling - } - }, + let #name = match wiggle_runtime::GuestPtr::<#pointee_type>::new(memory, #arg_name as u32).read() { + Ok(r) => r, Err(e) => { #error_handling } @@ -209,102 +204,25 @@ fn marshal_arg( let len_name = names.func_len_binding(¶m.name); let name = names.func_param(¶m.name); quote! { - let num_elems = match memory.ptr::(#len_name as u32) { - Ok(p) => match p.as_ref() { - Ok(r) => r, - Err(e) => { - #error_handling - } - } - Err(e) => { - #error_handling - } - }; - let #name: wiggle_runtime::GuestString<#lifetime> = match memory.ptr::(#ptr_name as u32) { - Ok(p) => match p.array(*num_elems) { - Ok(s) => s.into(), - Err(e) => { - #error_handling - } - } - Err(e) => { - #error_handling - } - }; + let #name = wiggle_runtime::GuestPtr::<#lifetime, str>::new(memory, (#ptr_name as u32, #len_name as u32)); } } }, - witx::Type::Pointer(pointee) => { + witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => { let pointee_type = names.type_ref(pointee, anon_lifetime()); let name = names.func_param(¶m.name); quote! { - let #name = match memory.ptr_mut::<#pointee_type>(#name as u32) { - Ok(p) => p, - Err(e) => { - #error_handling - } - }; + let #name = wiggle_runtime::GuestPtr::<#pointee_type>::new(memory, #name as u32); } } - witx::Type::ConstPointer(pointee) => { - let pointee_type = names.type_ref(pointee, anon_lifetime()); - let name = names.func_param(¶m.name); - quote! { - let #name = match memory.ptr::<#pointee_type>(#name as u32) { - Ok(p) => p, - Err(e) => { - #error_handling - } - }; - } - } - witx::Type::Struct(s) if !s.needs_lifetime() => { - let pointee_type = names.type_ref(tref, anon_lifetime()); - let arg_name = names.func_ptr_binding(¶m.name); - let name = names.func_param(¶m.name); - quote! { - let #name = match memory.ptr::<#pointee_type>(#arg_name as u32) { - Ok(p) => match p.as_ref() { - Ok(r) => r, - Err(e) => { - #error_handling - } - }, - Err(e) => { - #error_handling - } - }; - } - } - witx::Type::Struct(s) if s.needs_lifetime() => read_conversion, + witx::Type::Struct(_) => read_conversion, witx::Type::Array(arr) => { let pointee_type = names.type_ref(arr, anon_lifetime()); let ptr_name = names.func_ptr_binding(¶m.name); let len_name = names.func_len_binding(¶m.name); let name = names.func_param(¶m.name); quote! { - let num_elems = match memory.ptr::(#len_name as u32) { - Ok(p) => match p.as_ref() { - Ok(r) => r, - Err(e) => { - #error_handling - } - } - Err(e) => { - #error_handling - } - }; - let #name = match memory.ptr::<#pointee_type>(#ptr_name as u32) { - Ok(p) => match p.array(*num_elems) { - Ok(s) => s, - Err(e) => { - #error_handling - } - } - Err(e) => { - #error_handling - } - }; + let #name = wiggle_runtime::GuestPtr::<[#pointee_type]>::new(memory, (#ptr_name as u32, #len_name as u32)); } } witx::Type::Union(_u) => read_conversion, @@ -313,7 +231,6 @@ fn marshal_arg( let handle_type = names.type_ref(tref, anon_lifetime()); quote!( let #name = #handle_type::from(#name); ) } - _ => unimplemented!("argument type marshalling"), } } @@ -333,17 +250,14 @@ where let ptr_name = names.func_ptr_binding(&result.name); let ptr_err_handling = error_handling(&format!("{}:result_ptr_mut", result.name.as_str())); let pre = quote! { - let mut #ptr_name = match memory.ptr_mut::<#pointee_type>(#ptr_name as u32) { - Ok(p) => p, - Err(e) => { - #ptr_err_handling - } - }; + let #ptr_name = wiggle_runtime::GuestPtr::<#pointee_type>::new(memory, #ptr_name as u32); }; // trait binding returns func_param name. let val_name = names.func_param(&result.name); let post = quote! { - #ptr_name.write(&#val_name); + if let Err(e) = #ptr_name.write(#val_name) { + #ptr_err_handling + } }; (pre, post) }; diff --git a/crates/generate/src/module_trait.rs b/crates/generate/src/module_trait.rs index 96515499f0..bd94946bba 100644 --- a/crates/generate/src/module_trait.rs +++ b/crates/generate/src/module_trait.rs @@ -11,7 +11,12 @@ pub fn define_module_trait(names: &Names, m: &Module) -> TokenStream { // Check if we're returning an entity anotated with a lifetime, // in which case, we'll need to annotate the function itself, and // hence will need an explicit lifetime (rather than anonymous) - let (lifetime, is_anonymous) = if f.results.iter().any(|ret| ret.tref.needs_lifetime()) { + let (lifetime, is_anonymous) = if f + .params + .iter() + .chain(&f.results) + .any(|ret| ret.tref.needs_lifetime()) + { (quote!('a), false) } else { (anon_lifetime(), true) diff --git a/crates/generate/src/names.rs b/crates/generate/src/names.rs index 1167d25a60..e66b6f8d81 100644 --- a/crates/generate/src/names.rs +++ b/crates/generate/src/names.rs @@ -24,7 +24,7 @@ impl Names { } pub fn builtin_type(&self, b: BuiltinType, lifetime: TokenStream) -> TokenStream { match b { - BuiltinType::String => quote!(wiggle_runtime::GuestString<#lifetime>), + BuiltinType::String => quote!(wiggle_runtime::GuestPtr<#lifetime, str>), BuiltinType::U8 => quote!(u8), BuiltinType::U16 => quote!(u16), BuiltinType::U32 => quote!(u32), @@ -60,11 +60,7 @@ impl Names { } TypeRef::Value(ty) => match &**ty { witx::Type::Builtin(builtin) => self.builtin_type(*builtin, lifetime.clone()), - witx::Type::Pointer(pointee) => { - let pointee_type = self.type_ref(&pointee, lifetime.clone()); - quote!(wiggle_runtime::GuestPtrMut<#lifetime, #pointee_type>) - } - witx::Type::ConstPointer(pointee) => { + witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => { let pointee_type = self.type_ref(&pointee, lifetime.clone()); quote!(wiggle_runtime::GuestPtr<#lifetime, #pointee_type>) } diff --git a/crates/generate/src/types/enum.rs b/crates/generate/src/types/enum.rs index e40d6b50de..ec9ab021b0 100644 --- a/crates/generate/src/types/enum.rs +++ b/crates/generate/src/types/enum.rs @@ -77,37 +77,25 @@ pub(super) fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype } impl<'a> wiggle_runtime::GuestType<'a> for #ident { - fn size() -> u32 { - ::std::mem::size_of::<#repr>() as u32 + fn guest_size() -> u32 { + #repr::guest_size() } - fn align() -> u32 { - ::std::mem::align_of::<#repr>() as u32 - } - - fn name() -> String { - stringify!(#ident).to_owned() - } - - fn validate(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> { - use ::std::convert::TryFrom; - let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() }; - let _ = #ident::try_from(raw)?; - Ok(()) + fn guest_align() -> usize { + #repr::guest_align() } fn read(location: &wiggle_runtime::GuestPtr<#ident>) -> Result<#ident, wiggle_runtime::GuestError> { - // Perform validation as part of as_ref: - let r = location.as_ref()?; - Ok(*r) + use std::convert::TryFrom; + let val = #repr::read(&location.cast())?; + #ident::try_from(val) } - fn write(&self, location: &wiggle_runtime::GuestPtrMut<#ident>) { - let val: #repr = #repr::from(*self); - unsafe { (location.as_raw() as *mut #repr).write(val) }; + fn write(location: &wiggle_runtime::GuestPtr<'_, #ident>, val: Self) + -> Result<(), wiggle_runtime::GuestError> + { + #repr::write(&location.cast(), #repr::from(val)) } } - - impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident {} } } diff --git a/crates/generate/src/types/flags.rs b/crates/generate/src/types/flags.rs index 67e380ff77..201e0a4529 100644 --- a/crates/generate/src/types/flags.rs +++ b/crates/generate/src/types/flags.rs @@ -126,35 +126,24 @@ pub(super) fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDataty } impl<'a> wiggle_runtime::GuestType<'a> for #ident { - fn size() -> u32 { - ::std::mem::size_of::<#repr>() as u32 + fn guest_size() -> u32 { + #repr::guest_size() } - fn align() -> u32 { - ::std::mem::align_of::<#repr>() as u32 + fn guest_align() -> usize { + #repr::guest_align() } - fn name() -> String { - stringify!(#ident).to_owned() + fn read(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> { + use std::convert::TryFrom; + let bits = #repr::read(&location.cast())?; + #ident::try_from(bits) } - fn validate(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> { - use ::std::convert::TryFrom; - let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() }; - let _ = #ident::try_from(raw)?; - Ok(()) - } - - fn read(location: &wiggle_runtime::GuestPtr<#ident>) -> Result<#ident, wiggle_runtime::GuestError> { - Ok(*location.as_ref()?) - } - - fn write(&self, location: &wiggle_runtime::GuestPtrMut<#ident>) { - let val: #repr = #repr::from(*self); - unsafe { (location.as_raw() as *mut #repr).write(val) }; + fn write(location: &wiggle_runtime::GuestPtr<'_, #ident>, val: Self) -> Result<(), wiggle_runtime::GuestError> { + let val: #repr = #repr::from(val); + #repr::write(&location.cast(), val) } } - - impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident {} } } diff --git a/crates/generate/src/types/handle.rs b/crates/generate/src/types/handle.rs index ab83593508..294e36a028 100644 --- a/crates/generate/src/types/handle.rs +++ b/crates/generate/src/types/handle.rs @@ -11,7 +11,7 @@ pub(super) fn define_handle( ) -> TokenStream { let ident = names.type_(name); let size = h.mem_size_align().size as u32; - let align = h.mem_size_align().align as u32; + let align = h.mem_size_align().align as usize; quote! { #[derive(Copy, Clone, Debug, ::std::hash::Hash, Eq, PartialEq)] pub struct #ident(u32); @@ -46,32 +46,21 @@ pub(super) fn define_handle( } impl<'a> wiggle_runtime::GuestType<'a> for #ident { - fn size() -> u32 { + fn guest_size() -> u32 { #size } - fn align() -> u32 { + fn guest_align() -> usize { #align } - fn name() -> String { - stringify!(#ident).to_owned() - } - - fn validate(ptr: &wiggle_runtime::GuestPtr<#ident>) -> Result<(), wiggle_runtime::GuestError> { - Ok(()) - } - fn read(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> { - let r = location.as_ref()?; - Ok(*r) + Ok(#ident(u32::read(&location.cast())?)) } - fn write(&self, location: &wiggle_runtime::GuestPtrMut<'a, Self>) { - unsafe { (location.as_raw() as *mut #ident).write(*self) }; + fn write(location: &wiggle_runtime::GuestPtr<'_, Self>, val: Self) -> Result<(), wiggle_runtime::GuestError> { + u32::write(&location.cast(), val.0) } } - - impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident {} } } diff --git a/crates/generate/src/types/int.rs b/crates/generate/src/types/int.rs index bb2f40afee..25375700b9 100644 --- a/crates/generate/src/types/int.rs +++ b/crates/generate/src/types/int.rs @@ -63,35 +63,21 @@ pub(super) fn define_int(names: &Names, name: &witx::Id, i: &witx::IntDatatype) } impl<'a> wiggle_runtime::GuestType<'a> for #ident { - fn size() -> u32 { - ::std::mem::size_of::<#repr>() as u32 + fn guest_size() -> u32 { + #repr::guest_size() } - fn align() -> u32 { - ::std::mem::align_of::<#repr>() as u32 + fn guest_align() -> usize { + #repr::guest_align() } - fn name() -> String { - stringify!(#ident).to_owned() + fn read(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> { + Ok(#ident(#repr::read(&location.cast())?)) } - fn validate(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> { - use ::std::convert::TryFrom; - let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() }; - let _ = #ident::try_from(raw)?; - Ok(()) - } - - fn read(location: &wiggle_runtime::GuestPtr<#ident>) -> Result<#ident, wiggle_runtime::GuestError> { - Ok(*location.as_ref()?) - } - - fn write(&self, location: &wiggle_runtime::GuestPtrMut<#ident>) { - let val: #repr = #repr::from(*self); - unsafe { (location.as_raw() as *mut #repr).write(val) }; + fn write(location: &wiggle_runtime::GuestPtr<'_, #ident>, val: Self) -> Result<(), wiggle_runtime::GuestError> { + #repr::write(&location.cast(), val.0) } } - - impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident {} } } diff --git a/crates/generate/src/types/mod.rs b/crates/generate/src/types/mod.rs index 9d633d0c75..07c748b1d7 100644 --- a/crates/generate/src/types/mod.rs +++ b/crates/generate/src/types/mod.rs @@ -25,7 +25,7 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea witx::Type::Pointer(p) => define_witx_pointer( names, &namedtype.name, - quote!(wiggle_runtime::GuestPtrMut), + quote!(wiggle_runtime::GuestPtr), p, ), witx::Type::ConstPointer(p) => { @@ -71,7 +71,7 @@ fn define_witx_pointer( fn define_witx_array(names: &Names, name: &witx::Id, arr_raw: &witx::TypeRef) -> TokenStream { let ident = names.type_(name); let pointee_type = names.type_ref(arr_raw, quote!('a)); - quote!(pub type #ident<'a> = wiggle_runtime::GuestArray<'a, #pointee_type>;) + quote!(pub type #ident<'a> = wiggle_runtime::GuestPtr<'a, [#pointee_type]>;) } fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream { diff --git a/crates/generate/src/types/struct.rs b/crates/generate/src/types/struct.rs index 465e47279f..11a6bdf06f 100644 --- a/crates/generate/src/types/struct.rs +++ b/crates/generate/src/types/struct.rs @@ -10,87 +10,9 @@ pub(super) fn define_struct( name: &witx::Id, s: &witx::StructDatatype, ) -> TokenStream { - if !s.needs_lifetime() { - define_copy_struct(names, name, s) - } else { - define_ptr_struct(names, name, s) - } -} - -fn define_copy_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) -> TokenStream { let ident = names.type_(name); let size = s.mem_size_align().size as u32; - let align = s.mem_size_align().align as u32; - - let member_decls = s.members.iter().map(|m| { - let name = names.struct_member(&m.name); - let type_ = names.type_ref(&m.tref, anon_lifetime()); - quote!(pub #name: #type_) - }); - let member_valids = s.member_layout().into_iter().map(|ml| { - let type_ = names.type_ref(&ml.member.tref, anon_lifetime()); - let offset = ml.offset as u32; - let fieldname = names.struct_member(&ml.member.name); - quote! { - #type_::validate( - &ptr.cast(#offset).map_err(|e| - wiggle_runtime::GuestError::InDataField{ - typename: stringify!(#ident).to_owned(), - field: stringify!(#fieldname).to_owned(), - err: Box::new(e), - })? - ).map_err(|e| - wiggle_runtime::GuestError::InDataField { - typename: stringify!(#ident).to_owned(), - field: stringify!(#fieldname).to_owned(), - err: Box::new(e), - })?; - } - }); - - quote! { - #[repr(C)] - #[derive(Copy, Clone, Debug, PartialEq)] - pub struct #ident { - #(#member_decls),* - } - - impl<'a> wiggle_runtime::GuestType<'a> for #ident { - fn size() -> u32 { - #size - } - - fn align() -> u32 { - #align - } - - fn name() -> String { - stringify!(#ident).to_owned() - } - - fn validate(ptr: &wiggle_runtime::GuestPtr<#ident>) -> Result<(), wiggle_runtime::GuestError> { - #(#member_valids)* - Ok(()) - } - - fn read(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> { - let r = location.as_ref()?; - Ok(*r) - } - - fn write(&self, location: &wiggle_runtime::GuestPtrMut<'a, Self>) { - unsafe { (location.as_raw() as *mut #ident).write(*self) }; - } - } - - impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident {} - } -} - -fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) -> TokenStream { - let ident = names.type_(name); - let size = s.mem_size_align().size as u32; - let align = s.mem_size_align().align as u32; + let align = s.mem_size_align().align as usize; let member_names = s.members.iter().map(|m| names.struct_member(&m.name)); let member_decls = s.members.iter().map(|m| { @@ -99,11 +21,7 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) - witx::TypeRef::Name(nt) => names.type_(&nt.name), witx::TypeRef::Value(ty) => match &**ty { witx::Type::Builtin(builtin) => names.builtin_type(*builtin, quote!('a)), - witx::Type::Pointer(pointee) => { - let pointee_type = names.type_ref(&pointee, quote!('a)); - quote!(wiggle_runtime::GuestPtrMut<'a, #pointee_type>) - } - witx::Type::ConstPointer(pointee) => { + witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => { let pointee_type = names.type_ref(&pointee, quote!('a)); quote!(wiggle_runtime::GuestPtr<'a, #pointee_type>) } @@ -112,68 +30,29 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) - }; quote!(pub #name: #type_) }); - let member_valids = s.member_layout().into_iter().map(|ml| { - let type_ = match &ml.member.tref { - witx::TypeRef::Name(nt) => names.type_(&nt.name), - witx::TypeRef::Value(ty) => match &**ty { - witx::Type::Builtin(builtin) => names.builtin_type(*builtin, quote!('a)), - witx::Type::Pointer(pointee) => { - let pointee_type = names.type_ref(&pointee, anon_lifetime()); - quote!(wiggle_runtime::GuestPtrMut::<#pointee_type>) - } - witx::Type::ConstPointer(pointee) => { - let pointee_type = names.type_ref(&pointee, anon_lifetime()); - quote!(wiggle_runtime::GuestPtr::<#pointee_type>) - } - _ => unimplemented!("other anonymous struct members"), - }, - }; - let offset = ml.offset as u32; - let fieldname = names.struct_member(&ml.member.name); - quote! { - #type_::validate( - &ptr.cast(#offset).map_err(|e| - wiggle_runtime::GuestError::InDataField{ - typename: stringify!(#ident).to_owned(), - field: stringify!(#fieldname).to_owned(), - err: Box::new(e), - })? - ).map_err(|e| - wiggle_runtime::GuestError::InDataField { - typename: stringify!(#ident).to_owned(), - field: stringify!(#fieldname).to_owned(), - err: Box::new(e), - })?; - } - }); let member_reads = s.member_layout().into_iter().map(|ml| { let name = names.struct_member(&ml.member.name); let offset = ml.offset as u32; + let location = quote!(location.cast::().add(#offset)?.cast()); match &ml.member.tref { witx::TypeRef::Name(nt) => { let type_ = names.type_(&nt.name); quote! { - let #name = <#type_ as wiggle_runtime::GuestType>::read(&location.cast(#offset)?)?; + let #name = <#type_ as wiggle_runtime::GuestType>::read(&#location)?; } } witx::TypeRef::Value(ty) => match &**ty { witx::Type::Builtin(builtin) => { let type_ = names.builtin_type(*builtin, anon_lifetime()); quote! { - let #name = <#type_ as wiggle_runtime::GuestType>::read(&location.cast(#offset)?)?; + let #name = <#type_ as wiggle_runtime::GuestType>::read(&#location)?; } } - witx::Type::Pointer(pointee) => { + witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => { let pointee_type = names.type_ref(&pointee, anon_lifetime()); quote! { - let #name = as wiggle_runtime::GuestType>::read(&location.cast(#offset)?)?; - } - } - witx::Type::ConstPointer(pointee) => { - let pointee_type = names.type_ref(&pointee, anon_lifetime()); - quote! { - let #name = as wiggle_runtime::GuestType>::read(&location.cast(#offset)?)?; + let #name = as wiggle_runtime::GuestType>::read(&#location)?; } } _ => unimplemented!("other anonymous struct members"), @@ -185,41 +64,42 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) - let name = names.struct_member(&ml.member.name); let offset = ml.offset as u32; quote! { - wiggle_runtime::GuestType::write(&self.#name, &location.cast(#offset).expect("cast to inner member")); + wiggle_runtime::GuestType::write( + &location.cast::().add(#offset)?.cast(), + val.#name, + )?; } }); + let (struct_lifetime, extra_derive) = if s.needs_lifetime() { + (quote!(<'a>), quote!()) + } else { + (quote!(), quote!(, Copy, PartialEq)) + }; + quote! { - #[derive(Clone, Debug)] - pub struct #ident<'a> { + #[derive(Clone, Debug #extra_derive)] + pub struct #ident #struct_lifetime { #(#member_decls),* } - impl<'a> wiggle_runtime::GuestType<'a> for #ident<'a> { - fn size() -> u32 { + impl<'a> wiggle_runtime::GuestType<'a> for #ident #struct_lifetime { + fn guest_size() -> u32 { #size } - fn align() -> u32 { + fn guest_align() -> usize { #align } - fn name() -> String { - stringify!(#ident).to_owned() - } - - fn validate(ptr: &wiggle_runtime::GuestPtr<'a, #ident<'a>>) -> Result<(), wiggle_runtime::GuestError> { - #(#member_valids)* - Ok(()) - } - - fn read(location: &wiggle_runtime::GuestPtr<'a, #ident<'a>>) -> Result<#ident<'a>, wiggle_runtime::GuestError> { + fn read(location: &wiggle_runtime::GuestPtr<'a, Self>) -> Result { #(#member_reads)* Ok(#ident { #(#member_names),* }) } - fn write(&self, location: &wiggle_runtime::GuestPtrMut<'a, Self>) { + fn write(location: &wiggle_runtime::GuestPtr<'_, Self>, val: Self) -> Result<(), wiggle_runtime::GuestError> { #(#member_writes)* + Ok(()) } } } diff --git a/crates/generate/src/types/union.rs b/crates/generate/src/types/union.rs index 4a9f6bff9a..4490690050 100644 --- a/crates/generate/src/types/union.rs +++ b/crates/generate/src/types/union.rs @@ -1,4 +1,4 @@ -use crate::lifetimes::{anon_lifetime, LifetimeExt}; +use crate::lifetimes::LifetimeExt; use crate::names::Names; use proc_macro2::TokenStream; @@ -8,7 +8,7 @@ use witx::Layout; pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDatatype) -> TokenStream { let ident = names.type_(name); let size = u.mem_size_align().size as u32; - let align = u.mem_size_align().align as u32; + let align = u.mem_size_align().align as usize; let ulayout = u.union_layout(); let contents_offset = ulayout.contents_offset as u32; @@ -32,8 +32,8 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty let varianttype = names.type_ref(tref, lifetime.clone()); quote! { #tagname::#variantname => { - let variant_ptr = location.cast::<#varianttype>(#contents_offset).expect("union variant ptr validated"); - let variant_val = <#varianttype as wiggle_runtime::GuestType>::read(&variant_ptr)?; + let variant_ptr = location.cast::().add(#contents_offset)?; + let variant_val = <#varianttype as wiggle_runtime::GuestType>::read(&variant_ptr.cast())?; Ok(#ident::#variantname(variant_val)) } } @@ -45,17 +45,15 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty let write_variant = u.variants.iter().map(|v| { let variantname = names.enum_variant(&v.name); let write_tag = quote! { - let tag_ptr = location.cast::<#tagname>(0).expect("union tag ptr TODO error report"); - let mut tag_ref = tag_ptr.as_ref_mut().expect("union tag ref TODO error report"); - *tag_ref = #tagname::#variantname; + location.cast().write(#tagname::#variantname)?; }; if let Some(tref) = &v.tref { let varianttype = names.type_ref(tref, lifetime.clone()); quote! { #ident::#variantname(contents) => { #write_tag - let variant_ptr = location.cast::<#varianttype>(#contents_offset).expect("union variant ptr validated"); - <#varianttype as wiggle_runtime::GuestType>::write(&contents, &variant_ptr); + let variant_ptr = location.cast::().add(#contents_offset)?; + <#varianttype as wiggle_runtime::GuestType>::write(&variant_ptr.cast(), contents)?; } } } else { @@ -66,134 +64,46 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty } } }); - let validate = union_validate(names, ident.clone(), u, &ulayout); - if !u.needs_lifetime() { - // Type does not have a lifetime parameter: - quote! { - #[derive(Copy, Clone, Debug, PartialEq)] - pub enum #ident { - #(#variants),* - } - - impl<'a> wiggle_runtime::GuestType<'a> for #ident { - fn size() -> u32 { - #size - } - - fn align() -> u32 { - #align - } - - fn name() -> String { - stringify!(#ident).to_owned() - } - - fn validate(ptr: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> { - #validate - } - - fn read(location: &wiggle_runtime::GuestPtr<'a, #ident>) - -> Result { - <#ident as wiggle_runtime::GuestType>::validate(location)?; - let tag = *location.cast::<#tagname>(0).expect("validated tag ptr").as_ref().expect("validated tag ref"); - match tag { - #(#read_variant)* - } - - } - - fn write(&self, location: &wiggle_runtime::GuestPtrMut<'a, #ident>) { - match self { - #(#write_variant)* - } - } - } - } + let (enum_lifetime, extra_derive) = if u.needs_lifetime() { + (quote!(<'a>), quote!()) } else { - quote! { - #[derive(Clone, Debug)] - pub enum #ident<#lifetime> { - #(#variants),* - } - - impl<#lifetime> wiggle_runtime::GuestType<#lifetime> for #ident<#lifetime> { - fn size() -> u32 { - #size - } - - fn align() -> u32 { - #align - } - - fn name() -> String { - stringify!(#ident).to_owned() - } - - fn validate(ptr: &wiggle_runtime::GuestPtr<#lifetime, #ident<#lifetime>>) -> Result<(), wiggle_runtime::GuestError> { - #validate - } - - fn read(location: &wiggle_runtime::GuestPtr<#lifetime, #ident<#lifetime>>) - -> Result { - <#ident as wiggle_runtime::GuestType>::validate(location)?; - let tag = *location.cast::<#tagname>(0).expect("validated tag ptr").as_ref().expect("validated tag ref"); - match tag { - #(#read_variant)* - } - - } - - fn write(&self, location: &wiggle_runtime::GuestPtrMut<#lifetime, #ident<#lifetime>>) { - match self { - #(#write_variant)* - } - } - } - } - } -} - -fn union_validate( - names: &Names, - typename: TokenStream, - u: &witx::UnionDatatype, - ulayout: &witx::UnionLayout, -) -> TokenStream { - let tagname = names.type_(&u.tag.name); - let contents_offset = ulayout.contents_offset as u32; - - let with_err = |f: &str| -> TokenStream { - quote!(|e| wiggle_runtime::GuestError::InDataField { - typename: stringify!(#typename).to_owned(), - field: #f.to_owned(), - err: Box::new(e), - }) + (quote!(), quote!(, Copy, PartialEq)) }; - let tag_err = with_err(""); - let variant_validation = u.variants.iter().map(|v| { - let err = with_err(v.name.as_str()); - let variantname = names.enum_variant(&v.name); - if let Some(tref) = &v.tref { - let lifetime = anon_lifetime(); - let varianttype = names.type_ref(tref, lifetime.clone()); - quote! { - #tagname::#variantname => { - let variant_ptr = ptr.cast::<#varianttype>(#contents_offset).map_err(#err)?; - <#varianttype as wiggle_runtime::GuestType>::validate(&variant_ptr).map_err(#err)?; - } - } - } else { - quote! { #tagname::#variantname => {} } - } - }); - quote! { - let tag = *ptr.cast::<#tagname>(0).map_err(#tag_err)?.as_ref().map_err(#tag_err)?; - match tag { - #(#variant_validation)* + #[derive(Clone, Debug #extra_derive)] + pub enum #ident #enum_lifetime { + #(#variants),* + } + + impl<'a> wiggle_runtime::GuestType<'a> for #ident #enum_lifetime { + fn guest_size() -> u32 { + #size + } + + fn guest_align() -> usize { + #align + } + + fn read(location: &wiggle_runtime::GuestPtr<'a, Self>) + -> Result + { + let tag = location.cast().read()?; + match tag { + #(#read_variant)* + } + + } + + fn write(location: &wiggle_runtime::GuestPtr<'_, Self>, val: Self) + -> Result<(), wiggle_runtime::GuestError> + { + match val { + #(#write_variant)* + } + Ok(()) + } } - Ok(()) } } diff --git a/crates/runtime/src/borrow.rs b/crates/runtime/src/borrow.rs deleted file mode 100644 index bd1d077e17..0000000000 --- a/crates/runtime/src/borrow.rs +++ /dev/null @@ -1,67 +0,0 @@ -use std::collections::HashMap; - -use crate::region::Region; - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct BorrowHandle(usize); - -#[derive(Debug)] -pub struct GuestBorrows { - immutable: HashMap, - mutable: HashMap, - next_handle: BorrowHandle, -} - -impl GuestBorrows { - pub fn new() -> Self { - GuestBorrows { - immutable: HashMap::new(), - mutable: HashMap::new(), - next_handle: BorrowHandle(0), - } - } - - fn is_borrowed_immut(&self, r: Region) -> bool { - !self.immutable.values().all(|b| !b.overlaps(r)) - } - - fn is_borrowed_mut(&self, r: Region) -> bool { - !self.mutable.values().all(|b| !b.overlaps(r)) - } - - fn new_handle(&mut self) -> BorrowHandle { - let h = self.next_handle; - self.next_handle = BorrowHandle(h.0 + 1); - h - } - - pub fn borrow_immut(&mut self, r: Region) -> Option { - if self.is_borrowed_mut(r) { - return None; - } - let h = self.new_handle(); - self.immutable.insert(h, r); - Some(h) - } - - pub fn unborrow_immut(&mut self, h: BorrowHandle) { - self.immutable - .remove(&h) - .expect("handle exists in immutable borrows"); - } - - pub fn borrow_mut(&mut self, r: Region) -> Option { - if self.is_borrowed_immut(r) || self.is_borrowed_mut(r) { - return None; - } - let h = self.new_handle(); - self.mutable.insert(h, r); - Some(h) - } - - pub fn unborrow_mut(&mut self, h: BorrowHandle) { - self.mutable - .remove(&h) - .expect("handle exists in mutable borrows"); - } -} diff --git a/crates/runtime/src/guest_type.rs b/crates/runtime/src/guest_type.rs index 2d69548554..b23830d062 100644 --- a/crates/runtime/src/guest_type.rs +++ b/crates/runtime/src/guest_type.rs @@ -1,54 +1,80 @@ -use crate::{GuestError, GuestPtr, GuestPtrMut}; - -pub trait GuestType<'a>: Sized + Clone { - // These are morally the same as Rust ::std::mem::size_of / align_of, but they return - // a u32 because the wasm memory space is 32 bits. They have a different names so they - // don't collide with the std::mem methods. - fn size() -> u32; - fn align() -> u32; - fn name() -> String; - fn validate(location: &GuestPtr<'a, Self>) -> Result<(), GuestError>; - fn read(location: &GuestPtr<'a, Self>) -> Result; - fn write(&self, location: &GuestPtrMut<'a, Self>); -} - -/// Represents any guest type which can transparently be represented -/// as a host type. -pub trait GuestTypeTransparent<'a>: GuestType<'a> + Copy {} - -macro_rules! builtin_type { - ( $( $t:ident ), * ) => { - $( - impl<'a> GuestType<'a> for $t { - fn size() -> u32 { - ::std::mem::size_of::<$t>() as u32 - } - fn align() -> u32 { - ::std::mem::align_of::<$t>() as u32 - } - fn name() -> String { - ::std::stringify!($t).to_owned() - } - fn validate(_ptr: &GuestPtr<$t>) -> Result<(), GuestError> { - Ok(()) - } - fn read(location: &GuestPtr<'a, Self>) -> Result { - Ok(*location.as_ref()?) - } - fn write(&self, location: &GuestPtrMut<'a, Self>) { - unsafe { (location.as_raw() as *mut $t).write(*self) }; - } - } - impl<'a> GuestTypeTransparent<'a> for $t {} - )* - }; -} - -// These definitions correspond to all the witx BuiltinType variants that are Copy: -builtin_type!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, usize); +use crate::{GuestError, GuestPtr}; +use std::mem; pub trait GuestErrorType { type Context; fn success() -> Self; fn from_error(e: GuestError, ctx: &Self::Context) -> Self; } + +pub trait GuestType<'a>: Sized { + fn guest_size() -> u32; + fn guest_align() -> usize; + fn read(ptr: &GuestPtr<'a, Self>) -> Result; + fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError>; +} + +macro_rules! primitives { + ($($i:ident)*) => ($( + impl<'a> GuestType<'a> for $i { + fn guest_size() -> u32 { mem::size_of::() as u32 } + fn guest_align() -> usize { mem::align_of::() } + + fn read(ptr: &GuestPtr<'a, Self>) -> Result { + + // Any bit pattern for any primitive implemented with this + // macro is safe, so our `as_raw` method will guarantee that if + // we are given a pointer it's valid for the size of our type + // as well as properly aligned. Consequently we should be able + // to safely ready the pointer just after we validated it, + // returning it along here. + let host_ptr = ptr.mem().validate_size_align( + ptr.offset(), + Self::guest_align(), + Self::guest_size(), + )?; + Ok(unsafe { *host_ptr.cast::() }) + } + + fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError> { + let host_ptr = ptr.mem().validate_size_align( + ptr.offset(), + Self::guest_align(), + Self::guest_size(), + )?; + // Similar to above `as_raw` will do a lot of validation, and + // then afterwards we can safely write our value into the + // memory location. + unsafe { + *host_ptr.cast::() = val; + } + Ok(()) + } + } + )*) +} + +primitives! { + i8 i16 i32 i64 i128 isize + u8 u16 u32 u64 u128 usize + f32 f64 +} + +// Support pointers-to-pointers where pointers are always 32-bits in wasm land +impl<'a, T> GuestType<'a> for GuestPtr<'a, T> { + fn guest_size() -> u32 { + u32::guest_size() + } + fn guest_align() -> usize { + u32::guest_align() + } + + fn read(ptr: &GuestPtr<'a, Self>) -> Result { + let offset = ptr.cast::().read()?; + Ok(GuestPtr::new(ptr.mem(), offset)) + } + + fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError> { + ptr.cast::().write(val.offset()) + } +} diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs index 99648c4b1a..93c45fbe87 100644 --- a/crates/runtime/src/lib.rs +++ b/crates/runtime/src/lib.rs @@ -1,13 +1,217 @@ -mod borrow; +use std::cell::Cell; +use std::slice; +use std::str; +use std::marker; +use std::fmt; + mod error; mod guest_type; -mod memory; mod region; - pub use error::GuestError; -pub use guest_type::{GuestErrorType, GuestType, GuestTypeTransparent}; -pub use memory::{ - GuestArray, GuestMemory, GuestPtr, GuestPtrMut, GuestRef, GuestRefMut, GuestString, - GuestStringRef, -}; +pub use guest_type::{GuestErrorType, GuestType}; pub use region::Region; + +pub unsafe trait GuestMemory { + fn base(&self) -> (*mut u8, u32); + + fn validate_size_align( + &self, + offset: u32, + align: usize, + len: u32, + ) -> Result<*mut u8, GuestError> { + let (base_ptr, base_len) = self.base(); + let region = Region { start: offset, len }; + + // Figure out our pointer to the start of memory + let start = match (base_ptr as usize).checked_add(offset as usize) { + Some(ptr) => ptr, + None => return Err(GuestError::PtrOutOfBounds(region)), + }; + // and use that to figure out the end pointer + let end = match start.checked_add(len as usize) { + Some(ptr) => ptr, + None => return Err(GuestError::PtrOutOfBounds(region)), + }; + // and then verify that our end doesn't reach past the end of our memory + if end > (base_ptr as usize) + (base_len as usize) { + return Err(GuestError::PtrOutOfBounds(region)); + } + // and finally verify that the alignment is correct + if start % align != 0 { + return Err(GuestError::PtrNotAligned(region, align as u32)); + } + Ok(start as *mut u8) + } + + fn ptr<'a, T>(&'a self, offset: T::Pointer) -> GuestPtr<'a, T> + where + Self: Sized, + T: ?Sized + Pointee, + { + GuestPtr::new(self, offset) + } +} + +unsafe impl<'a, T: ?Sized + GuestMemory> GuestMemory for &'a T { + fn base(&self) -> (*mut u8, u32) { + T::base(self) + } +} + +unsafe impl<'a, T: ?Sized + GuestMemory> GuestMemory for &'a mut T { + fn base(&self) -> (*mut u8, u32) { + T::base(self) + } +} + +pub struct GuestPtr<'a, T: ?Sized + Pointee> { + mem: &'a (dyn GuestMemory + 'a), + pointer: T::Pointer, + _marker: marker::PhantomData<&'a Cell>, +} + +impl<'a, T: ?Sized + Pointee> GuestPtr<'a, T> { + pub fn new(mem: &'a (dyn GuestMemory + 'a), pointer: T::Pointer) -> GuestPtr<'_, T> { + GuestPtr { + mem, + pointer, + _marker: marker::PhantomData, + } + } + + pub fn offset(&self) -> T::Pointer { + self.pointer + } + + pub fn mem(&self) -> &'a (dyn GuestMemory + 'a) { + self.mem + } + + pub fn cast(&self) -> GuestPtr<'a, U> + where + T: Pointee, + { + GuestPtr::new(self.mem, self.pointer) + } + + pub fn read(&self) -> Result + where + T: GuestType<'a>, + { + T::read(self) + } + + pub fn write(&self, val: T) -> Result<(), GuestError> + where + T: GuestType<'a>, + { + T::write(self, val) + } + + pub fn add(&self, amt: u32) -> Result, GuestError> + where T: GuestType<'a> + Pointee, + { + let offset = amt.checked_mul(T::guest_size()) + .and_then(|o| self.pointer.checked_add(o)); + let offset = match offset { + Some(o) => o, + None => return Err(GuestError::InvalidFlagValue("")), + }; + Ok(GuestPtr::new(self.mem, offset)) + } +} + +impl<'a, T> GuestPtr<'a, [T]> { + pub fn offset_base(&self) -> u32 { + self.pointer.0 + } + + pub fn len(&self) -> u32 { + self.pointer.1 + } + + pub fn iter<'b>(&'b self) -> impl ExactSizeIterator, GuestError>> + 'b + where + T: GuestType<'a>, + { + let base = GuestPtr::new(self.mem, self.offset_base()); + (0..self.len()).map(move |i| base.add(i)) + } +} + +impl<'a> GuestPtr<'a, str> { + pub fn offset_base(&self) -> u32 { + self.pointer.0 + } + + pub fn len(&self) -> u32 { + self.pointer.1 + } + + pub fn as_bytes(&self) -> GuestPtr<'a, [u8]> { + GuestPtr::new(self.mem, self.pointer) + } + + pub fn as_raw(&self) -> Result<*mut str, GuestError> { + let ptr = self.mem.validate_size_align(self.pointer.0, 1, self.pointer.1)?; + + // TODO: doc unsafety here + unsafe { + let s = slice::from_raw_parts_mut(ptr, self.pointer.1 as usize); + match str::from_utf8_mut(s) { + Ok(s) => Ok(s), + Err(e) => Err(GuestError::InvalidUtf8(e)) + } + } + } +} + +impl Clone for GuestPtr<'_, T> { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for GuestPtr<'_, T> {} + +impl fmt::Debug for GuestPtr<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + T::debug(self.pointer, f) + } +} + +mod private { + pub trait Sealed {} + impl Sealed for T {} + impl Sealed for [T] {} + impl Sealed for str {} +} + +pub trait Pointee: private::Sealed { + #[doc(hidden)] + type Pointer: Copy; + #[doc(hidden)] + fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result; +} + +impl Pointee for T { + type Pointer = u32; + fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "*guest {:#x}", pointer) + } +} + +impl Pointee for [T] { + type Pointer = (u32, u32); + fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "*guest {:#x}/{}", pointer.0, pointer.1) + } +} + +impl Pointee for str { + type Pointer = (u32, u32); + fn debug(pointer: Self::Pointer, f: &mut fmt::Formatter) -> fmt::Result { + <[u8]>::debug(pointer, f) + } +} diff --git a/crates/runtime/src/memory/array.rs b/crates/runtime/src/memory/array.rs deleted file mode 100644 index 3c7815536b..0000000000 --- a/crates/runtime/src/memory/array.rs +++ /dev/null @@ -1,260 +0,0 @@ -use super::ptr::{GuestPtr, GuestRef}; -use crate::{GuestError, GuestType, GuestTypeTransparent}; -use std::{fmt, ops::Deref}; - -#[derive(Clone)] -pub struct GuestArray<'a, T> -where - T: GuestType<'a>, -{ - pub(super) ptr: GuestPtr<'a, T>, - pub(super) num_elems: u32, -} - -impl<'a, T> fmt::Debug for GuestArray<'a, T> -where - T: GuestType<'a> + fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "GuestArray {{ ptr: {:?}, num_elems: {:?} }}", - self.ptr, self.num_elems - ) - } -} - -impl<'a, T> GuestArray<'a, T> -where - T: GuestType<'a>, -{ - pub fn iter(&self) -> GuestArrayIter<'a, T> { - let next = GuestPtr { - mem: self.ptr.mem, - region: self.ptr.region, - type_: self.ptr.type_, - }; - GuestArrayIter { - next, - num_elems: self.num_elems, - count: 0, - } - } -} - -pub struct GuestArrayIter<'a, T> -where - T: GuestType<'a>, -{ - next: GuestPtr<'a, T>, - num_elems: u32, - count: u32, -} - -impl<'a, T> Iterator for GuestArrayIter<'a, T> -where - T: GuestType<'a>, -{ - type Item = Result, GuestError>; - - fn next(&mut self) -> Option { - if self.count < self.num_elems { - // ok... - Some(T::validate(&self.next).and_then(|()| { - let curr = GuestPtr { - mem: self.next.mem, - region: self.next.region, - type_: self.next.type_, - }; - self.next = self.next.elem(1)?; - self.count += 1; - Ok(curr) - })) - } else { - // no more elements... - None - } - } -} - -impl<'a, T> GuestArray<'a, T> -where - T: GuestTypeTransparent<'a>, -{ - pub fn as_ref(&self) -> Result, GuestError> { - let mut next = self.ptr.elem(0)?; - for _ in 0..self.num_elems { - T::validate(&next)?; - next = next.elem(1)?; - } - let region = self.ptr.region.extend(self.num_elems); - let handle = { - let mut borrows = self.ptr.mem.borrows.borrow_mut(); - borrows - .borrow_immut(region) - .ok_or_else(|| GuestError::PtrBorrowed(region))? - }; - let ref_ = GuestRef { - mem: self.ptr.mem, - region, - handle, - type_: self.ptr.type_, - }; - Ok(GuestArrayRef { - ref_, - num_elems: self.num_elems, - }) - } -} - -pub struct GuestArrayRef<'a, T> -where - T: GuestTypeTransparent<'a>, -{ - ref_: GuestRef<'a, T>, - num_elems: u32, -} - -impl<'a, T> fmt::Debug for GuestArrayRef<'a, T> -where - T: GuestTypeTransparent<'a> + fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "GuestArrayRef {{ ref_: {:?}, num_elems: {:?} }}", - self.ref_, self.num_elems - ) - } -} - -impl<'a, T> Deref for GuestArrayRef<'a, T> -where - T: GuestTypeTransparent<'a>, -{ - type Target = [T]; - - fn deref(&self) -> &Self::Target { - unsafe { - std::slice::from_raw_parts( - self.ref_.as_ptr().as_raw() as *const _, - self.num_elems as usize, - ) - } - } -} - -#[cfg(test)] -mod test { - use crate::{ - memory::ptr::{GuestPtr, GuestPtrMut}, - GuestError, GuestMemory, GuestType, Region, - }; - - #[repr(align(4096))] - struct HostMemory { - buffer: [u8; 4096], - } - - impl HostMemory { - pub fn new() -> Self { - Self { buffer: [0; 4096] } - } - pub fn as_mut_ptr(&mut self) -> *mut u8 { - self.buffer.as_mut_ptr() - } - pub fn len(&self) -> usize { - self.buffer.len() - } - } - - #[test] - fn out_of_bounds() { - let mut host_memory = HostMemory::new(); - let guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32); - // try extracting an array out of memory bounds - let ptr: GuestPtr = guest_memory.ptr(4092).expect("ptr to last i32 el"); - let err = ptr.array(2).expect_err("out of bounds ptr error"); - assert_eq!(err, GuestError::PtrOutOfBounds(Region::new(4092, 8))); - } - - #[test] - fn ptr_to_array() { - let mut host_memory = HostMemory::new(); - let guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32); - // write a simple array into memory - { - let ptr: GuestPtrMut = guest_memory.ptr_mut(0).expect("ptr mut to first el"); - let mut el = ptr.as_ref_mut().expect("ref mut to first el"); - *el = 1; - let ptr: GuestPtrMut = guest_memory.ptr_mut(4).expect("ptr mut to second el"); - let mut el = ptr.as_ref_mut().expect("ref mu to second el"); - *el = 2; - let ptr: GuestPtrMut = guest_memory.ptr_mut(8).expect("ptr mut to third el"); - let mut el = ptr.as_ref_mut().expect("ref mut to third el"); - *el = 3; - } - // extract as array - let ptr: GuestPtr = guest_memory.ptr(0).expect("ptr to first el"); - let arr = ptr.array(3).expect("convert ptr to array"); - let as_ref = &*arr.as_ref().expect("array borrowed immutably"); - assert_eq!(as_ref, &[1, 2, 3]); - // borrowing again should be fine - let as_ref2 = &*arr.as_ref().expect("array borrowed immutably again"); - assert_eq!(as_ref2, as_ref); - } - - #[test] - fn ptr_to_ptr_array() { - let mut host_memory = HostMemory::new(); - let guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32); - { - let val_ptr: GuestPtrMut = - guest_memory.ptr_mut(0).expect("ptr mut to the first value"); - let mut val = val_ptr.as_ref_mut().expect("ref mut to the first value"); - *val = 255; - let val_ptr: GuestPtrMut = guest_memory - .ptr_mut(4) - .expect("ptr mut to the second value"); - let mut val = val_ptr.as_ref_mut().expect("ref mut to the second value"); - *val = 254; - let val_ptr: GuestPtrMut = - guest_memory.ptr_mut(8).expect("ptr mut to the third value"); - let mut val = val_ptr.as_ref_mut().expect("ref mut to the third value"); - *val = 253; - } - { - let ptr = guest_memory.ptr_mut(12).expect("ptr mut to first el"); - ptr.write( - &guest_memory - .ptr::>(0) - .expect("ptr to the first value"), - ); - let ptr = guest_memory.ptr_mut(16).expect("ptr mut to first el"); - ptr.write( - &guest_memory - .ptr::>(4) - .expect("ptr to the second value"), - ); - let ptr = guest_memory.ptr_mut(20).expect("ptr mut to first el"); - ptr.write( - &guest_memory - .ptr::>(8) - .expect("ptr to the third value"), - ); - } - // extract as array - let ptr: GuestPtr> = guest_memory.ptr(12).expect("ptr to first el"); - let arr = ptr.array(3).expect("convert ptr to array"); - let contents = arr - .iter() - .map(|ptr_ptr| { - *GuestType::read(&ptr_ptr.expect("valid ptr to ptr")) - .expect("valid ptr to some value") - .as_ref() - .expect("deref ptr to some value") - }) - .collect::>(); - assert_eq!(&contents, &[255, 254, 253]); - } -} diff --git a/crates/runtime/src/memory/mod.rs b/crates/runtime/src/memory/mod.rs deleted file mode 100644 index 9fd8f907fe..0000000000 --- a/crates/runtime/src/memory/mod.rs +++ /dev/null @@ -1,72 +0,0 @@ -mod array; -mod ptr; -mod string; - -pub use array::*; -pub use ptr::*; -pub use string::*; - -use crate::{borrow::GuestBorrows, GuestError, GuestType, Region}; -use std::{cell::RefCell, fmt, marker::PhantomData, rc::Rc}; - -pub struct GuestMemory<'a> { - ptr: *mut u8, - len: u32, - lifetime: PhantomData<&'a ()>, - borrows: Rc>, -} - -impl<'a> fmt::Debug for GuestMemory<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "GuestMemory {{ ptr: {:?}, len: {:?}, borrows: {:?} }}", - self.ptr, self.len, self.borrows - ) - } -} - -impl<'a> GuestMemory<'a> { - pub fn new(ptr: *mut u8, len: u32) -> Self { - assert_eq!(ptr as usize % 4096, 0, "GuestMemory must be page-aligned"); - Self { - ptr, - len, - lifetime: PhantomData, - borrows: Rc::new(RefCell::new(GuestBorrows::new())), - } - } - - fn contains(&self, r: Region) -> bool { - r.start < self.len - && r.len < self.len // make sure next clause doesnt underflow - && r.start <= (self.len - r.len) - } - - pub fn ptr>(&'a self, at: u32) -> Result, GuestError> { - let region = Region { - start: at, - len: T::size(), - }; - if !self.contains(region) { - Err(GuestError::PtrOutOfBounds(region))?; - } - if at % T::align() != 0 { - Err(GuestError::PtrNotAligned(region, T::align()))?; - } - Ok(GuestPtr { - mem: &self, - region, - type_: PhantomData, - }) - } - - pub fn ptr_mut>(&'a self, at: u32) -> Result, GuestError> { - let ptr = self.ptr(at)?; - Ok(GuestPtrMut { - mem: ptr.mem, - region: ptr.region, - type_: ptr.type_, - }) - } -} diff --git a/crates/runtime/src/memory/ptr.rs b/crates/runtime/src/memory/ptr.rs deleted file mode 100644 index 54a80e8ab4..0000000000 --- a/crates/runtime/src/memory/ptr.rs +++ /dev/null @@ -1,515 +0,0 @@ -use super::{array::GuestArray, GuestMemory}; -use crate::{borrow::BorrowHandle, GuestError, GuestType, GuestTypeTransparent, Region}; -use std::{ - fmt, - marker::PhantomData, - ops::{Deref, DerefMut}, -}; - -#[derive(Clone)] -pub struct GuestPtr<'a, T> { - pub(super) mem: &'a GuestMemory<'a>, - pub(super) region: Region, - pub(super) type_: PhantomData, -} - -impl<'a, T> fmt::Debug for GuestPtr<'a, T> -where - T: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "GuestPtr {{ mem: {:?}, region: {:?} }}", - self.mem, self.region - ) - } -} - -impl<'a, T: GuestType<'a>> GuestPtr<'a, T> { - pub fn as_raw(&self) -> *const u8 { - (self.mem.ptr as usize + self.region.start as usize) as *const u8 - } - - pub fn elem(&self, elements: i32) -> Result { - self.mem - .ptr(self.region.start + (elements * self.region.len as i32) as u32) - } - - pub fn cast>( - &self, - offset: u32, - ) -> Result, GuestError> { - self.mem.ptr(self.region.start + offset) - } - - pub fn array(&self, num_elems: u32) -> Result, GuestError> { - let region = self.region.extend(num_elems); - if self.mem.contains(region) { - let ptr = GuestPtr { - mem: self.mem, - region: self.region, - type_: self.type_, - }; - Ok(GuestArray { ptr, num_elems }) - } else { - Err(GuestError::PtrOutOfBounds(region)) - } - } -} - -impl<'a, T> GuestPtr<'a, T> -where - T: GuestTypeTransparent<'a>, -{ - pub fn as_ref(&self) -> Result, GuestError> { - T::validate(&self)?; - let handle = { - let mut borrows = self.mem.borrows.borrow_mut(); - borrows - .borrow_immut(self.region) - .ok_or_else(|| GuestError::PtrBorrowed(self.region))? - }; - Ok(GuestRef { - mem: self.mem, - region: self.region, - handle, - type_: self.type_, - }) - } -} - -impl<'a, T> GuestPtr<'a, T> -where - T: GuestType<'a>, -{ - pub fn read(&self) -> Result { - T::read(self) - } -} - -impl<'a, T> GuestType<'a> for GuestPtr<'a, T> -where - T: GuestType<'a>, -{ - fn size() -> u32 { - 4 - } - - fn align() -> u32 { - 4 - } - - fn name() -> String { - format!("GuestPtr<{}>", T::name()) - } - - fn validate(location: &GuestPtr<'a, GuestPtr<'a, T>>) -> Result<(), GuestError> { - // location is guaranteed to be in GuestMemory and aligned to 4 - let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) }; - // GuestMemory can validate that the raw pointer contents are legal for T: - let _guest_ptr: GuestPtr = location.mem.ptr(raw_ptr)?; - Ok(()) - } - - // Operations for reading and writing Ptrs to memory: - fn read(location: &GuestPtr<'a, Self>) -> Result { - // location is guaranteed to be in GuestMemory and aligned to 4 - let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) }; - // GuestMemory can validate that the raw pointer contents are legal for T: - let guest_ptr: GuestPtr<'a, T> = location.mem.ptr(raw_ptr)?; - Ok(guest_ptr) - } - - fn write(&self, location: &GuestPtrMut<'a, Self>) { - // location is guaranteed to be in GuestMemory and aligned to 4 - unsafe { - let raw_ptr: *mut u32 = location.as_raw() as *mut u32; - raw_ptr.write(self.region.start); - } - } -} - -#[derive(Clone)] -pub struct GuestPtrMut<'a, T> { - pub(super) mem: &'a GuestMemory<'a>, - pub(super) region: Region, - pub(super) type_: PhantomData, -} - -impl<'a, T> fmt::Debug for GuestPtrMut<'a, T> -where - T: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "GuestPtrMut {{ mem: {:?}, region: {:?} }}", - self.mem, self.region - ) - } -} - -impl<'a, T> GuestPtrMut<'a, T> -where - T: GuestType<'a>, -{ - pub fn as_immut(&self) -> GuestPtr<'a, T> { - GuestPtr { - mem: self.mem, - region: self.region, - type_: self.type_, - } - } - - pub fn as_raw(&self) -> *mut u8 { - (self.mem.ptr as usize + self.region.start as usize) as *mut u8 - } - - pub fn elem(&self, elements: i32) -> Result { - self.mem - .ptr_mut(self.region.start + (elements * self.region.len as i32) as u32) - } - - pub fn cast>( - &self, - offset: u32, - ) -> Result, GuestError> { - self.mem.ptr_mut(self.region.start + offset) - } -} - -impl<'a, T> GuestPtrMut<'a, T> -where - T: GuestTypeTransparent<'a>, -{ - pub fn as_ref(&self) -> Result, GuestError> { - self.as_immut().as_ref() - } - - pub fn as_ref_mut(&self) -> Result, GuestError> { - T::validate(&self.as_immut())?; - let handle = { - let mut borrows = self.mem.borrows.borrow_mut(); - borrows - .borrow_mut(self.region) - .ok_or_else(|| GuestError::PtrBorrowed(self.region))? - }; - Ok(GuestRefMut { - mem: self.mem, - region: self.region, - handle, - type_: self.type_, - }) - } -} - -impl<'a, T> GuestPtrMut<'a, T> -where - T: GuestType<'a>, -{ - pub fn read(&self) -> Result { - T::read(&self.as_immut()) - } - - pub fn write(&self, ptr: &T) { - T::write(ptr, &self); - } -} - -impl<'a, T> GuestType<'a> for GuestPtrMut<'a, T> -where - T: GuestType<'a>, -{ - fn size() -> u32 { - 4 - } - - fn align() -> u32 { - 4 - } - - fn name() -> String { - format!("GuestPtrMut<{}>", T::name()) - } - - fn validate(location: &GuestPtr<'a, GuestPtrMut<'a, T>>) -> Result<(), GuestError> { - // location is guaranteed to be in GuestMemory and aligned to 4 - let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) }; - // GuestMemory can validate that the raw pointer contents are legal for T: - let _guest_ptr: GuestPtr = location.mem.ptr(raw_ptr)?; - Ok(()) - } - - // Reading and writing GuestPtrMuts to memory: - fn read(location: &GuestPtr<'a, Self>) -> Result { - // location is guaranteed to be in GuestMemory and aligned to 4 - let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) }; - // GuestMemory can validate that the raw pointer contents are legal for T: - let guest_ptr_mut: GuestPtrMut<'a, T> = location.mem.ptr_mut(raw_ptr)?; - Ok(guest_ptr_mut) - } - - fn write(&self, location: &GuestPtrMut<'a, Self>) { - // location is guaranteed to be in GuestMemory and aligned to 4 - unsafe { - let raw_ptr: *mut u32 = location.as_raw() as *mut u32; - raw_ptr.write(self.region.start); - } - } -} - -pub struct GuestRef<'a, T> { - pub(super) mem: &'a GuestMemory<'a>, - pub(super) region: Region, - pub(super) handle: BorrowHandle, - pub(super) type_: PhantomData, -} - -impl<'a, T> fmt::Debug for GuestRef<'a, T> -where - T: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "GuestRef {{ mem: {:?}, region: {:?}, handle: {:?} }}", - self.mem, self.region, self.handle - ) - } -} - -impl<'a, T> GuestRef<'a, T> { - pub fn as_ptr(&self) -> GuestPtr<'a, T> { - GuestPtr { - mem: self.mem, - region: self.region, - type_: self.type_, - } - } -} - -impl<'a, T> Deref for GuestRef<'a, T> -where - T: GuestTypeTransparent<'a>, -{ - type Target = T; - - fn deref(&self) -> &Self::Target { - unsafe { - ((self.mem.ptr as usize + self.region.start as usize) as *const T) - .as_ref() - .expect("GuestRef implies non-null") - } - } -} - -impl<'a, T> Drop for GuestRef<'a, T> { - fn drop(&mut self) { - let mut borrows = self.mem.borrows.borrow_mut(); - borrows.unborrow_immut(self.handle); - } -} - -pub struct GuestRefMut<'a, T> { - pub(super) mem: &'a GuestMemory<'a>, - pub(super) region: Region, - pub(super) handle: BorrowHandle, - pub(super) type_: PhantomData, -} - -impl<'a, T> fmt::Debug for GuestRefMut<'a, T> -where - T: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "GuestRefMut {{ mem: {:?}, region: {:?}, handle: {:?} }}", - self.mem, self.region, self.handle - ) - } -} - -impl<'a, T> GuestRefMut<'a, T> { - pub fn as_ptr(&self) -> GuestPtr<'a, T> { - GuestPtr { - mem: self.mem, - region: self.region, - type_: self.type_, - } - } - pub fn as_ptr_mut(&self) -> GuestPtrMut<'a, T> { - GuestPtrMut { - mem: self.mem, - region: self.region, - type_: self.type_, - } - } -} - -impl<'a, T> ::std::ops::Deref for GuestRefMut<'a, T> -where - T: GuestTypeTransparent<'a>, -{ - type Target = T; - - fn deref(&self) -> &Self::Target { - unsafe { - ((self.mem.ptr as usize + self.region.start as usize) as *const T) - .as_ref() - .expect("GuestRef implies non-null") - } - } -} - -impl<'a, T> DerefMut for GuestRefMut<'a, T> -where - T: GuestTypeTransparent<'a>, -{ - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { - ((self.mem.ptr as usize + self.region.start as usize) as *mut T) - .as_mut() - .expect("GuestRef implies non-null") - } - } -} - -impl<'a, T> Drop for GuestRefMut<'a, T> { - fn drop(&mut self) { - let mut borrows = self.mem.borrows.borrow_mut(); - borrows.unborrow_mut(self.handle); - } -} - -#[cfg(test)] -mod test { - use super::{ - super::{GuestError, GuestMemory, Region}, - {GuestPtr, GuestPtrMut}, - }; - - #[repr(align(4096))] - struct HostMemory { - buffer: [u8; 4096], - } - - impl HostMemory { - pub fn new() -> Self { - Self { buffer: [0; 4096] } - } - pub fn as_mut_ptr(&mut self) -> *mut u8 { - self.buffer.as_mut_ptr() - } - pub fn len(&self) -> usize { - self.buffer.len() - } - } - - #[test] - fn out_of_bounds() { - let mut host_memory = HostMemory::new(); - let guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32); - // try extracting an immutable ptr out of memory bounds - let err = guest_memory - .ptr::>(4096) - .expect_err("out of bounds ptr error"); - assert_eq!(err, GuestError::PtrOutOfBounds(Region::new(4096, 4))); - // try extracting an mutable ptr out of memory bounds - let err = guest_memory - .ptr_mut::>(4096) - .expect_err("out of bounds ptr error"); - assert_eq!(err, GuestError::PtrOutOfBounds(Region::new(4096, 4))); - } - - #[test] - fn not_aligned() { - let mut host_memory = HostMemory::new(); - let guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32); - // try extracting a misaligned immutable ptr - let err = guest_memory - .ptr::>(2) - .expect_err("ptr misaligned"); - assert_eq!(err, GuestError::PtrNotAligned(Region::new(2, 4), 4)); - // try extracting a misaligned mutable ptr - let err = guest_memory - .ptr_mut::>(2) - .expect_err("ptr mut misaligned"); - assert_eq!(err, GuestError::PtrNotAligned(Region::new(2, 4), 4)); - } - - #[test] - fn ptr_from_memory() { - let mut host_memory = HostMemory::new(); - let guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32); - // write something to memory - { - let ptr: GuestPtrMut = guest_memory.ptr_mut(8).expect("ptr mut to the el"); - let mut el = ptr.as_ref_mut().expect("ref mut to the el"); - *el = 100; - } - // extract as ref - let ptr: GuestPtr = guest_memory.ptr(8).expect("ptr to the el"); - let as_ref = ptr.as_ref().expect("el borrowed immutably"); - assert_eq!(*as_ref, 100); - // borrowing again should be fine - let as_ref2 = ptr.as_ref().expect("el borrowed immutably again"); - assert_eq!(*as_ref2, *as_ref); - } - - #[test] - fn ptr_mut_from_memory() { - let mut host_memory = HostMemory::new(); - let guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32); - // set elems of array to zero - { - let ptr: GuestPtrMut = guest_memory.ptr_mut(8).expect("ptr mut to the el"); - let mut el = ptr.as_ref_mut().expect("ref mut to the el"); - *el = 100; - } - // extract as ref - let ptr: GuestPtrMut = guest_memory.ptr_mut(8).expect("ptr mut to the el"); - assert_eq!(*ptr.as_ref().expect("el borrowed immutably"), 100); - // overwrite the memory and re-verify - *ptr.as_ref_mut().expect("el borrowed mutably") = 2000; - // re-validate - assert_eq!(*ptr.as_ref().expect("el borrowed immutably"), 2000); - } - - #[test] - #[should_panic( - expected = "el borrowed immutably while borrowed mutably: PtrBorrowed(Region { start: 0, len: 2 })" - )] - fn borrow_mut_then_immut() { - let mut host_memory = HostMemory::new(); - let guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32); - let ptr: GuestPtrMut = guest_memory.ptr_mut(0).expect("ptr mut to the el"); - // borrow mutably - let _as_mut = ptr - .as_ref_mut() - .expect("el borrowed mutably for the first time"); - // borrow immutably should fail - let _as_ref = ptr - .as_ref() - .expect("el borrowed immutably while borrowed mutably"); - } - - #[test] - #[should_panic( - expected = "el borrowed mutably while borrowed mutably: PtrBorrowed(Region { start: 0, len: 2 })" - )] - fn borrow_mut_twice() { - let mut host_memory = HostMemory::new(); - let guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32); - let ptr: GuestPtrMut = guest_memory.ptr_mut(0).expect("ptr mut to the el"); - // borrow mutably - let _as_mut = ptr - .as_ref_mut() - .expect("el borrowed mutably for the first time"); - // try borrowing mutably again - let _as_mut2 = ptr - .as_ref_mut() - .expect("el borrowed mutably while borrowed mutably"); - } -} diff --git a/crates/runtime/src/memory/string.rs b/crates/runtime/src/memory/string.rs deleted file mode 100644 index a4e6deac6d..0000000000 --- a/crates/runtime/src/memory/string.rs +++ /dev/null @@ -1,124 +0,0 @@ -use super::array::{GuestArray, GuestArrayRef}; -use crate::GuestError; -use std::fmt; - -pub struct GuestString<'a> { - pub(super) array: GuestArray<'a, u8>, -} - -impl<'a> fmt::Debug for GuestString<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "GuestString {{ array: {:?} }}", self.array) - } -} - -impl<'a> GuestString<'a> { - pub fn as_ref(&self) -> Result, GuestError> { - let ref_ = self.array.as_ref()?; - Ok(GuestStringRef { ref_ }) - } - - pub fn to_string(&self) -> Result { - Ok(self.as_ref()?.as_str()?.to_owned()) - } -} - -impl<'a> From> for GuestString<'a> { - fn from(array: GuestArray<'a, u8>) -> Self { - Self { array } - } -} - -pub struct GuestStringRef<'a> { - pub(super) ref_: GuestArrayRef<'a, u8>, -} - -impl<'a> fmt::Debug for GuestStringRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "GuestStringRef {{ ref_: {:?} }}", self.ref_) - } -} - -impl<'a> GuestStringRef<'a> { - pub fn as_str(&self) -> Result<&str, GuestError> { - std::str::from_utf8(&*self.ref_).map_err(Into::into) - } -} - -#[cfg(test)] -mod test { - use super::{ - super::{ - ptr::{GuestPtr, GuestPtrMut}, - GuestError, GuestMemory, - }, - GuestString, - }; - - #[repr(align(4096))] - struct HostMemory { - buffer: [u8; 4096], - } - - impl HostMemory { - pub fn new() -> Self { - Self { buffer: [0; 4096] } - } - pub fn as_mut_ptr(&mut self) -> *mut u8 { - self.buffer.as_mut_ptr() - } - pub fn len(&self) -> usize { - self.buffer.len() - } - } - - #[test] - fn valid_utf8() { - let mut host_memory = HostMemory::new(); - let guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32); - // write string into memory - let mut ptr: GuestPtrMut = guest_memory.ptr_mut(0).expect("ptr mut to start of string"); - let input_str = "cześć WASI!"; - for byte in input_str.as_bytes() { - let mut ref_mut = ptr.as_ref_mut().expect("valid deref"); - *ref_mut = *byte; - ptr = ptr.elem(1).expect("next ptr"); - } - // read the string as GuestString - let ptr: GuestPtr = guest_memory.ptr(0).expect("ptr to start of string"); - let guest_string: GuestString<'_> = ptr - .array(input_str.len() as u32) - .expect("valid null-terminated string") - .into(); - let as_ref = guest_string.as_ref().expect("deref"); - assert_eq!(as_ref.as_str().expect("valid UTF-8"), input_str); - } - - #[test] - fn invalid_utf8() { - let mut host_memory = HostMemory::new(); - let guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32); - // write string into memory - let mut ptr: GuestPtrMut = guest_memory.ptr_mut(0).expect("ptr mut to start of string"); - let input_str = "cześć WASI!"; - let mut bytes = input_str.as_bytes().to_vec(); - // insert 0xFE which is an invalid UTF-8 byte - bytes[5] = 0xfe; - for byte in &bytes { - let mut ref_mut = ptr.as_ref_mut().expect("valid deref"); - *ref_mut = *byte; - ptr = ptr.elem(1).expect("next ptr"); - } - // read the string as GuestString - let ptr: GuestPtr = guest_memory.ptr(0).expect("ptr to start of string"); - let guest_string: GuestString<'_> = ptr - .array(bytes.len() as u32) - .expect("valid null-terminated string") - .into(); - let as_ref = guest_string.as_ref().expect("deref"); - match as_ref.as_str().expect_err("should fail") { - GuestError::InvalidUtf8(_) => {} - x => assert!(false, "expected GuestError::InvalidUtf8(_), got {:?}", x), - } - } -} diff --git a/crates/test/src/lib.rs b/crates/test/src/lib.rs index 2ddf5704f8..bf72036c6f 100644 --- a/crates/test/src/lib.rs +++ b/crates/test/src/lib.rs @@ -1,17 +1,14 @@ use proptest::prelude::*; +use std::cell::UnsafeCell; use wiggle_runtime::GuestMemory; #[repr(align(4096))] pub struct HostMemory { - buffer: [u8; 4096], + buffer: UnsafeCell<[u8; 4096]>, } impl HostMemory { pub fn new() -> Self { - HostMemory { buffer: [0; 4096] } - } - - pub fn guest_memory<'a>(&'a mut self) -> GuestMemory<'a> { - GuestMemory::new(self.buffer.as_mut_ptr(), self.buffer.len() as u32) + HostMemory { buffer: UnsafeCell::new([0; 4096]) } } pub fn mem_area_strat(align: u32) -> BoxedStrategy { @@ -29,6 +26,15 @@ impl HostMemory { } } +unsafe impl GuestMemory for HostMemory { + fn base(&self) -> (*mut u8, u32) { + unsafe { + let ptr = self.buffer.get(); + ((*ptr).as_mut_ptr(), (*ptr).len() as u32) + } + } +} + #[derive(Debug)] pub struct MemArea { pub ptr: u32, diff --git a/tests/arrays.rs b/tests/arrays.rs index 26583911ea..d9ccd4ce93 100644 --- a/tests/arrays.rs +++ b/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 { - 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, excuse_ptr_locs: Vec, 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> = 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::(ptr.ptr) - .expect("ptr to Excuse value"), - ); - next = next.elem(1).expect("increment ptr by 1"); + let array: GuestPtr<'_, [GuestPtr]> = + 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 { #[derive(Debug)] struct PopulateExcusesExcercise { array_ptr_loc: MemArea, - array_len_loc: MemArea, elements: Vec, } @@ -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> = 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::(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" diff --git a/tests/atoms.rs b/tests/atoms.rs index 8eda99ba1d..594edb13ab 100644 --- a/tests/atoms.rs +++ b/tests/atoms.rs @@ -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 = guest_memory - .ptr(self.return_loc.ptr) - .expect("return loc ptr") - .as_ref() - .expect("return val ref"); + let return_val = host_memory + .ptr::(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 { diff --git a/tests/flags.rs b/tests/flags.rs index 0b729c94d4..d008dcb03c 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -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, ) -> Result { - 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::(self.return_ptr_loc.ptr) - .expect("ptr to returned CarConfig") - .as_ref() + .read() .expect("deref to CarConfig value"); assert_eq!( diff --git a/tests/handles.rs b/tests/handles.rs index 7f1e86d7f3..23037f38cf 100644 --- a/tests/handles.rs +++ b/tests/handles.rs @@ -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 { - (HostMemory::mem_area_strat(types::Fd::size())) + (HostMemory::mem_area_strat(types::Fd::guest_size())) .prop_map(|return_loc| HandleExercise { return_loc }) .boxed() } diff --git a/tests/ints.rs b/tests/ints.rs index 928e061e7c..12cb8c929c 100644 --- a/tests/ints.rs +++ b/tests/ints.rs @@ -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::(self.return_ptr_loc.ptr) - .expect("ptr to returned Bool") - .as_ref() + .read() .expect("deref to Bool value"); assert_eq!( diff --git a/tests/pointers.rs b/tests/pointers.rs index 3309cf7742..dc26ed33f6 100644 --- a/tests/pointers.rs +++ b/tests/pointers.rs @@ -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, - input3_ptr: GuestPtr, - input4_ptr_ptr: GuestPtrMut>, + 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 = 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 = GuestType::read(&input4_ptr_ptr.as_immut()) - .map_err(|e| { - eprintln!("input4_ptr_ptr error: {}", e); - types::Errno::InvalidArg - })?; + let input4_ptr: GuestPtr = 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!( diff --git a/tests/strings.rs b/tests/strings.rs index 9bcb634391..dc6526326e 100644 --- a/tests/strings.rs +++ b/tests/strings.rs @@ -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 { - 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) -> Result { + 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 { 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::((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::(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); } diff --git a/tests/structs.rs b/tests/structs.rs index 511e2fffbd..b24bbee9bf 100644 --- a/tests/structs.rs +++ b/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 { - 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 { - 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> = - guest_memory.ptr(self.return_loc.ptr).expect("return ptr"); - let ret_first_ptr: GuestPtr = ptr_pair_int_ptrs - .cast::>(0u32) - .expect("extract ptr to first element in struct") - .read() - .expect("read ptr to first element in struct"); - let ret_second_ptr: GuestPtr = ptr_pair_int_ptrs - .cast::>(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") ); } diff --git a/tests/union.rs b/tests/union.rs index 85e63a7a21..6081b0d4e7 100644 --- a/tests/union.rs +++ b/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 { ( 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 { ( 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), diff --git a/tests/wasi.rs b/tests/wasi.rs index 16042ce86e..daef095b23 100644 --- a/tests/wasi.rs +++ b/tests/wasi.rs @@ -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>, - _argv_buf: GuestPtrMut, + _argv: GuestPtr>, + _argv_buf: GuestPtr, ) -> Result<()> { unimplemented!("args_get") } @@ -37,8 +37,8 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn environ_get( &self, - _environ: GuestPtrMut>, - _environ_buf: GuestPtrMut, + _environ: GuestPtr>, + _environ_buf: GuestPtr, ) -> 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, + _path: GuestPtr, _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, + _buf: GuestPtr, _buf_len: types::Size, _cookie: types::Dircookie, ) -> Result { @@ -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 { 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, + _path: &GuestPtr<'_, str>, + _buf: GuestPtr, _buf_len: types::Size, ) -> Result { 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, - _out: GuestPtrMut, + _out: GuestPtr, _nsubscriptions: types::Size, ) -> Result { unimplemented!("poll_oneoff") @@ -298,7 +298,7 @@ impl crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { unimplemented!("sched_yield") } - fn random_get(&self, _buf: GuestPtrMut, _buf_len: types::Size) -> Result<()> { + fn random_get(&self, _buf: GuestPtr, _buf_len: types::Size) -> Result<()> { unimplemented!("random_get") }