You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
6.7 KiB

use proptest::prelude::*;
use wiggle::{GuestError, GuestMemory, GuestPtr};
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
wiggle::from_witx!({
witx: ["tests/arrays.witx"],
ctx: WasiCtx,
});
impl_errno!(types::Errno);
impl<'a> arrays::Arrays for WasiCtx<'a> {
fn reduce_excuses(
&self,
excuses: &types::ConstExcuseArray,
) -> Result<types::Excuse, types::Errno> {
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
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() {
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
let ptr_to_excuse = excuse
.expect("valid ptr to ptr")
.read()
.expect("valid ptr to some Excuse value");
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
ptr_to_excuse
.write(types::Excuse::Sleeping)
.expect("dereferencing mut ptr should succeed");
}
Ok(())
}
}
#[derive(Debug)]
struct ReduceExcusesExcercise {
excuse_values: Vec<types::Excuse>,
excuse_ptr_locs: Vec<MemArea>,
array_ptr_loc: MemArea,
return_ptr_loc: MemArea,
}
impl ReduceExcusesExcercise {
pub fn strat() -> BoxedStrategy<Self> {
(1..256u32)
.prop_flat_map(|len| {
let len_usize = len as usize;
(
proptest::collection::vec(excuse_strat(), len_usize..=len_usize),
proptest::collection::vec(HostMemory::mem_area_strat(4), len_usize..=len_usize),
HostMemory::mem_area_strat(4 * len),
HostMemory::mem_area_strat(4),
)
})
.prop_map(
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
|(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.return_ptr_loc];
all.extend(e.excuse_ptr_locs.iter());
MemArea::non_overlapping_set(all)
})
.boxed()
}
pub fn test(&self) {
let mut ctx = WasiCtx::new();
let mut host_memory = HostMemory::new();
// Populate memory with pointers to generated Excuse values
for (&excuse, ptr) in self.excuse_values.iter().zip(self.excuse_ptr_locs.iter()) {
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
host_memory
.ptr(ptr.ptr)
.write(excuse)
.expect("deref ptr mut to Excuse value");
}
// Populate the array with pointers to generated Excuse values
{
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
let array: GuestPtr<'_, [GuestPtr<types::Excuse>]> =
host_memory.ptr((self.array_ptr_loc.ptr, self.excuse_ptr_locs.len() as u32));
for (slot, ptr) in array.iter().zip(&self.excuse_ptr_locs) {
let slot = slot.expect("array should be in bounds");
slot.write(host_memory.ptr(ptr.ptr))
.expect("should succeed in writing array");
}
}
let res = arrays::reduce_excuses(
&mut ctx,
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
&mut host_memory,
self.array_ptr_loc.ptr as i32,
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
self.excuse_ptr_locs.len() as i32,
self.return_ptr_loc.ptr as i32,
);
assert_eq!(res, types::Errno::Ok.into(), "reduce excuses errno");
let expected = *self
.excuse_values
.last()
.expect("generated vec of excuses should be non-empty");
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
let given: types::Excuse = host_memory
.ptr(self.return_ptr_loc.ptr)
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
.read()
.expect("deref ptr to returned value");
assert_eq!(expected, given, "reduce excuses return val");
}
}
proptest! {
#[test]
fn reduce_excuses(e in ReduceExcusesExcercise::strat()) {
e.test()
}
}
fn excuse_strat() -> impl Strategy<Value = types::Excuse> {
prop_oneof![
Just(types::Excuse::DogAte),
Just(types::Excuse::Traffic),
Just(types::Excuse::Sleeping),
]
.boxed()
}
#[derive(Debug)]
struct PopulateExcusesExcercise {
array_ptr_loc: MemArea,
elements: Vec<MemArea>,
}
impl PopulateExcusesExcercise {
pub fn strat() -> BoxedStrategy<Self> {
(1..256u32)
.prop_flat_map(|len| {
let len_usize = len as usize;
(
HostMemory::mem_area_strat(4 * len),
proptest::collection::vec(HostMemory::mem_area_strat(4), len_usize..=len_usize),
)
})
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
.prop_map(|(array_ptr_loc, elements)| Self {
array_ptr_loc,
elements,
})
.prop_filter("non-overlapping pointers", |e| {
let mut all = vec![e.array_ptr_loc];
all.extend(e.elements.iter());
MemArea::non_overlapping_set(all)
})
.boxed()
}
pub fn test(&self) {
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
let ctx = WasiCtx::new();
let host_memory = HostMemory::new();
// Populate array with valid pointers to Excuse type in memory
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
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(
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
&ctx,
&host_memory,
self.array_ptr_loc.ptr as i32,
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
self.elements.len() as i32,
);
assert_eq!(res, types::Errno::Ok.into(), "populate excuses errno");
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
let arr: GuestPtr<'_, [GuestPtr<'_, types::Excuse>]> =
host_memory.ptr((self.array_ptr_loc.ptr, self.elements.len() as u32));
for el in arr.iter() {
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
let ptr_to_ptr = el
.expect("valid ptr to ptr")
.read()
.expect("valid ptr to some Excuse value");
assert_eq!(
Rewrite for recursive safety This commit rewrites the runtime crate to provide safety in the face of recursive calls to the guest. The basic principle is that `GuestMemory` is now a trait which dynamically returns the pointer/length pair. This also has an implicit contract (hence the `unsafe` trait) that the pointer/length pair point to a valid list of bytes in host memory &#34;until something is reentrant&#34;. After this changes the various suite of `Guest*` types were rewritten. `GuestRef` and `GuestRefMut` were both removed since they cannot safely exist. The `GuestPtrMut` type was removed for simplicity, and the final `GuestPtr` type subsumes `GuestString` and `GuestArray`. This means that there&#39;s only one guest pointer type, `GuestPtr&lt;&#39;a, T&gt;`, where `&#39;a` is the borrow into host memory, basically borrowing the `GuestMemory` trait object itself. Some core utilities are exposed on `GuestPtr`, but they&#39;re all 100% safe. Unsafety is now entirely contained within a few small locations: * Implementations of the `GuestType` for primitive types (e.g. `i8`, `u8`, etc) use `unsafe` to read/write memory. The `unsafe` trait of `GuestMemory` though should prove that they&#39;re safe. * `GuestPtr&lt;&#39;_, str&gt;` has a method which validates utf-8 contents, and this requires `unsafe` internally to read all the bytes. This is guaranteed to be safe however given the contract of `GuestMemory`. And that&#39;s it! Everything else is a bunch of safe combinators all built up on the various utilities provided by `GuestPtr`. The general idioms are roughly the same as before, with various tweaks here and there. A summary of expected idioms are: * For small values you&#39;d `.read()` or `.write()` very quickly. You&#39;d pass around the type itself. * For strings, you&#39;d pass `GuestPtr&lt;&#39;_, str&gt;` down to the point where it&#39;s actually consumed. At that moment you&#39;d either decide to copy it out (a safe operation) or you&#39;d get a raw view to the string (an unsafe operation) and assert that you won&#39;t call back into wasm while you&#39;re holding that pointer. * Arrays are similar to strings, passing around `GuestPtr&lt;&#39;_, [T]&gt;`. Arrays also have a `iter()` method which yields an iterator of `GuestPtr&lt;&#39;_, T&gt;` for convenience. Overall there&#39;s still a lot of missing documentation on the runtime crate specifically around the safety of the `GuestMemory` trait as well as how the utilities/methods are expected to be used. Additionally there&#39;s utilities which aren&#39;t currently implemented which would be easy to implement. For example there&#39;s no method to copy out a string or a slice, although that would be pretty easy to add. In any case I&#39;m curious to get feedback on this approach and see what y&#39;all think!
5 years ago
ptr_to_ptr
.read()
.expect("dereferencing ptr to some Excuse value"),
types::Excuse::Sleeping,
"element should equal Excuse::Sleeping"
);
}
}
}
proptest! {
#[test]
fn populate_excuses(e in PopulateExcusesExcercise::strat()) {
e.test()
}
}