Browse Source

wiggle: adapt Wiggle guest slices for `unsafe` shared use (#5229)

* wiggle: adapt Wiggle guest slices for `unsafe` shared use

When multiple threads can concurrently modify a WebAssembly shared
memory, the underlying data for a Wiggle `GuestSlice` and
`GuestSliceMut` could change due to access from other threads. This
breaks Rust guarantees when `&[T]` and `&mut [T]` slices are handed out.
This change modifies `GuestPtr` to make `as_slice` and `as_slice_mut`
return an `Option` which is `None` when the underlying WebAssembly
memory is shared.

But WASI implementations still need access to the underlying WebAssembly
memory, both to read to it and write from it. This change adds new APIs:
- `GuestPtr::to_vec` copies the  bytes from WebAssembly memory (from
  which we can safely take a `&[T]`)
- `GuestPtr::as_unsafe_slice_mut` returns a wrapper `struct` from which
  we can  `unsafe`-ly return a mutable slice (users must accept the
  unsafety of concurrently modifying a `&mut [T]`)

This approach allows us to maintain Wiggle's borrow-checking
infrastructure, which enforces the guarantee that Wiggle will not modify
overlapping regions, e.g. This is important because the underlying
system calls may expect this. Though other threads may modify the same
underlying region, this is impossible to prevent; at least Wiggle will
not be able to do so.

Finally, the changes to Wiggle's API are propagated to all WASI
implementations in Wasmtime. For now, code locations that attempt to get
a guest slice will panic if the underlying memory is shared. Note that
Wiggle is not enabled for shared memory (that will come later in
something like #5054), but when it is, these panics will be clear
indicators of locations that must be re-implemented in a thread-safe
way.

* review: remove double cast

* review: refactor to include more logic in 'UnsafeGuestSlice'

* review: add reference to #4203

* review: link all thread-safe WASI fixups to #5235

* fix: consume 'UnsafeGuestSlice' during conversion to safe versions

* review: remove 'as_slice' and 'as_slice_mut'

* review: use 'as_unsafe_slice_mut' in 'to_vec'

* review: add `UnsafeBorrowResult`
pull/5242/head
Andrew Brown 2 years ago
committed by GitHub
parent
commit
7717d8fa55
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 48
      crates/wasi-common/src/snapshots/preview_0.rs
  2. 88
      crates/wasi-common/src/snapshots/preview_1.rs
  3. 30
      crates/wasi-crypto/src/wiggle_interfaces/asymmetric_common.rs
  4. 31
      crates/wasi-crypto/src/wiggle_interfaces/common.rs
  5. 3
      crates/wasi-crypto/src/wiggle_interfaces/key_exchange.rs
  6. 15
      crates/wasi-crypto/src/wiggle_interfaces/signatures.rs
  7. 84
      crates/wasi-crypto/src/wiggle_interfaces/symmetric.rs
  8. 5
      crates/wasi-nn/src/impl.rs
  9. 17
      crates/wasi-nn/src/openvino.rs
  10. 266
      crates/wiggle/src/lib.rs
  11. 5
      crates/wiggle/tests/wasi.rs

48
crates/wasi-common/src/snapshots/preview_0.rs

@ -468,14 +468,16 @@ impl wasi_unstable::WasiUnstable for WasiCtx {
.get_file_mut(u32::from(fd))?
.get_cap_mut(FileCaps::READ)?;
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> = iovs
.iter()
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Iovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?)
})
.collect::<Result<_, Error>>()?;
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> =
iovs.iter()
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Iovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?.expect(
"cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)",
))
})
.collect::<Result<_, Error>>()?;
let mut ioslices: Vec<IoSliceMut> = guest_slices
.iter_mut()
@ -497,14 +499,16 @@ impl wasi_unstable::WasiUnstable for WasiCtx {
.get_file_mut(u32::from(fd))?
.get_cap_mut(FileCaps::READ | FileCaps::SEEK)?;
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> = iovs
.iter()
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Iovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?)
})
.collect::<Result<_, Error>>()?;
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> =
iovs.iter()
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Iovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?.expect(
"cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)",
))
})
.collect::<Result<_, Error>>()?;
let mut ioslices: Vec<IoSliceMut> = guest_slices
.iter_mut()
@ -530,7 +534,11 @@ impl wasi_unstable::WasiUnstable for WasiCtx {
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Ciovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice()?)
Ok(iov
.buf
.as_array(iov.buf_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)"))
})
.collect::<Result<_, Error>>()?;
@ -559,7 +567,11 @@ impl wasi_unstable::WasiUnstable for WasiCtx {
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Ciovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice()?)
Ok(iov
.buf
.as_array(iov.buf_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)"))
})
.collect::<Result<_, Error>>()?;

88
crates/wasi-common/src/snapshots/preview_1.rs

@ -521,14 +521,16 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
.get_file_mut(u32::from(fd))?
.get_cap_mut(FileCaps::READ)?;
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> = iovs
.iter()
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Iovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?)
})
.collect::<Result<_, Error>>()?;
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> =
iovs.iter()
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Iovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?.expect(
"cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)",
))
})
.collect::<Result<_, Error>>()?;
let mut ioslices: Vec<IoSliceMut> = guest_slices
.iter_mut()
@ -550,14 +552,16 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
.get_file_mut(u32::from(fd))?
.get_cap_mut(FileCaps::READ | FileCaps::SEEK)?;
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> = iovs
.iter()
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Iovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?)
})
.collect::<Result<_, Error>>()?;
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> =
iovs.iter()
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Iovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?.expect(
"cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)",
))
})
.collect::<Result<_, Error>>()?;
let mut ioslices: Vec<IoSliceMut> = guest_slices
.iter_mut()
@ -583,7 +587,11 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Ciovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice()?)
Ok(iov
.buf
.as_array(iov.buf_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)"))
})
.collect::<Result<_, Error>>()?;
@ -612,7 +620,11 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Ciovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice()?)
Ok(iov
.buf
.as_array(iov.buf_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)"))
})
.collect::<Result<_, Error>>()?;
@ -654,7 +666,10 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
if path_len < path_max_len as usize {
return Err(Error::name_too_long());
}
let mut p_memory = path.as_array(path_len as u32).as_slice_mut()?;
let mut p_memory = path
.as_array(path_len as u32)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
p_memory.copy_from_slice(path_bytes);
Ok(())
} else {
@ -948,7 +963,10 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
if link_len > buf_len as usize {
return Err(Error::range());
}
let mut buf = buf.as_array(link_len as u32).as_slice_mut()?;
let mut buf = buf
.as_array(link_len as u32)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
buf.copy_from_slice(link_bytes);
Ok(link_len as types::Size)
}
@ -1236,7 +1254,10 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
buf: &GuestPtr<'a, u8>,
buf_len: types::Size,
) -> Result<(), Error> {
let mut buf = buf.as_array(buf_len).as_slice_mut()?;
let mut buf = buf
.as_array(buf_len)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
self.random.try_fill_bytes(buf.deref_mut())?;
Ok(())
}
@ -1273,14 +1294,17 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
.get_file_mut(u32::from(fd))?
.get_cap_mut(FileCaps::READ)?;
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> = ri_data
.iter()
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Iovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?)
})
.collect::<Result<_, Error>>()?;
let mut guest_slices: Vec<wiggle::GuestSliceMut<u8>> =
ri_data
.iter()
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Iovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice_mut()?.expect(
"cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)",
))
})
.collect::<Result<_, Error>>()?;
let mut ioslices: Vec<IoSliceMut> = guest_slices
.iter_mut()
@ -1307,7 +1331,11 @@ impl wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
.map(|iov_ptr| {
let iov_ptr = iov_ptr?;
let iov: types::Ciovec = iov_ptr.read()?;
Ok(iov.buf.as_array(iov.buf_len).as_slice()?)
Ok(iov
.buf
.as_array(iov.buf_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)"))
})
.collect::<Result<_, Error>>()?;

30
crates/wasi-crypto/src/wiggle_interfaces/asymmetric_common.rs

@ -39,7 +39,10 @@ impl super::wasi_ephemeral_crypto_asymmetric_common::WasiEphemeralCryptoAsymmetr
kp_id_ptr: &wiggle::GuestPtr<'_, u8>,
kp_id_max_len: guest_types::Size,
) -> Result<(), guest_types::CryptoErrno> {
let key_id_buf = &mut *kp_id_ptr.as_array(kp_id_max_len).as_slice_mut()?;
let key_id_buf = &mut *kp_id_ptr
.as_array(kp_id_max_len)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self).keypair_store_managed(
secrets_manager_handle.into(),
kp_handle.into(),
@ -69,7 +72,10 @@ impl super::wasi_ephemeral_crypto_asymmetric_common::WasiEphemeralCryptoAsymmetr
kp_id_len: guest_types::Size,
kp_version: guest_types::Version,
) -> Result<guest_types::Keypair, guest_types::CryptoErrno> {
let kp_id = &*kp_id_ptr.as_array(kp_id_len).as_slice()?;
let kp_id = &*kp_id_ptr
.as_array(kp_id_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.keypair_from_id(secrets_manager_handle.into(), kp_id, Version(kp_version))?
.into())
@ -102,7 +108,10 @@ impl super::wasi_ephemeral_crypto_asymmetric_common::WasiEphemeralCryptoAsymmetr
encoding: guest_types::KeypairEncoding,
) -> Result<guest_types::Keypair, guest_types::CryptoErrno> {
let alg_str = &*alg_str.as_str()?;
let encoded = &*encoded_ptr.as_array(encoded_len).as_slice()?;
let encoded = &*encoded_ptr
.as_array(encoded_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.keypair_import(alg_type.into(), alg_str, encoded, encoding.into())?
.into())
@ -114,7 +123,10 @@ impl super::wasi_ephemeral_crypto_asymmetric_common::WasiEphemeralCryptoAsymmetr
kp_id_ptr: &wiggle::GuestPtr<'_, u8>,
kp_id_max_len: guest_types::Size,
) -> Result<(guest_types::Size, guest_types::Version), guest_types::CryptoErrno> {
let kp_id_buf = &mut *kp_id_ptr.as_array(kp_id_max_len as _).as_slice_mut()?;
let kp_id_buf = &mut *kp_id_ptr
.as_array(kp_id_max_len as _)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
let (kp_id, version) = (&*self).keypair_id(kp_handle.into())?;
ensure!(kp_id.len() <= kp_id_buf.len(), CryptoError::Overflow.into());
kp_id_buf.copy_from_slice(&kp_id);
@ -156,7 +168,10 @@ impl super::wasi_ephemeral_crypto_asymmetric_common::WasiEphemeralCryptoAsymmetr
encoding: guest_types::PublickeyEncoding,
) -> Result<guest_types::Publickey, guest_types::CryptoErrno> {
let alg_str = &*alg_str.as_str()?;
let encoded = &*encoded_ptr.as_array(encoded_len).as_slice()?;
let encoded = &*encoded_ptr
.as_array(encoded_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.publickey_import(alg_type.into(), alg_str, encoded, encoding.into())?
.into())
@ -204,7 +219,10 @@ impl super::wasi_ephemeral_crypto_asymmetric_common::WasiEphemeralCryptoAsymmetr
encoding: guest_types::SecretkeyEncoding,
) -> Result<guest_types::Secretkey, guest_types::CryptoErrno> {
let alg_str = &*alg_str.as_str()?;
let encoded = &*encoded_ptr.as_array(encoded_len).as_slice()?;
let encoded = &*encoded_ptr
.as_array(encoded_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.secretkey_import(alg_type.into(), alg_str, encoded, encoding.into())?
.into())

31
crates/wasi-crypto/src/wiggle_interfaces/common.rs

@ -28,7 +28,12 @@ impl super::wasi_ephemeral_crypto_common::WasiEphemeralCryptoCommon for WasiCryp
value_len: guest_types::Size,
) -> Result<(), guest_types::CryptoErrno> {
let name_str: &str = &*name_str.as_str()?;
let value: &[u8] = { &*value_ptr.as_array(value_len).as_slice()? };
let value: &[u8] = {
&*value_ptr
.as_array(value_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)")
};
Ok((&*self).options_set(options_handle.into(), name_str, value)?)
}
@ -40,8 +45,14 @@ impl super::wasi_ephemeral_crypto_common::WasiEphemeralCryptoCommon for WasiCryp
buffer_len: guest_types::Size,
) -> Result<(), guest_types::CryptoErrno> {
let name_str: &str = &*name_str.as_str()?;
let buffer: &'static mut [u8] =
unsafe { std::mem::transmute(&mut *buffer_ptr.as_array(buffer_len).as_slice_mut()?) };
let buffer: &'static mut [u8] = unsafe {
std::mem::transmute(
&mut *buffer_ptr
.as_array(buffer_len)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)"),
)
};
Ok((&*self).options_set_guest_buffer(options_handle.into(), name_str, buffer)?)
}
@ -72,7 +83,12 @@ impl super::wasi_ephemeral_crypto_common::WasiEphemeralCryptoCommon for WasiCryp
buf_ptr: &wiggle::GuestPtr<'_, u8>,
buf_len: guest_types::Size,
) -> Result<guest_types::Size, guest_types::CryptoErrno> {
let buf: &mut [u8] = { &mut *buf_ptr.as_array(buf_len).as_slice_mut()? };
let buf: &mut [u8] = {
&mut *buf_ptr
.as_array(buf_len)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)")
};
Ok((&*self)
.array_output_pull(array_output_handle.into(), buf)?
.try_into()?)
@ -107,7 +123,12 @@ impl super::wasi_ephemeral_crypto_common::WasiEphemeralCryptoCommon for WasiCryp
key_id_len: guest_types::Size,
key_version: guest_types::Version,
) -> Result<(), guest_types::CryptoErrno> {
let key_id: &[u8] = { &*key_id_ptr.as_array(key_id_len).as_slice()? };
let key_id: &[u8] = {
&*key_id_ptr
.as_array(key_id_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)")
};
Ok((&*self).secrets_manager_invalidate(
secrets_manager_handle.into(),
key_id,

3
crates/wasi-crypto/src/wiggle_interfaces/key_exchange.rs

@ -31,7 +31,8 @@ impl super::wasi_ephemeral_crypto_kx::WasiEphemeralCryptoKx for WasiCryptoCtx {
) -> Result<guest_types::ArrayOutput, guest_types::CryptoErrno> {
let encapsulated_secret = &*encapsulated_secret_ptr
.as_array(encapsulated_secret_len)
.as_slice()?;
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.kx_decapsulate(sk_handle.into(), encapsulated_secret)?
.into())

15
crates/wasi-crypto/src/wiggle_interfaces/signatures.rs

@ -23,7 +23,10 @@ impl super::wasi_ephemeral_crypto_signatures::WasiEphemeralCryptoSignatures for
encoding: guest_types::SignatureEncoding,
) -> Result<guest_types::Signature, guest_types::CryptoErrno> {
let alg_str = &*alg_str.as_str()?;
let encoded = &*encoded_ptr.as_array(encoded_len).as_slice()?;
let encoded = &*encoded_ptr
.as_array(encoded_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.signature_import(alg_str, encoded, encoding.into())?
.into())
@ -42,7 +45,10 @@ impl super::wasi_ephemeral_crypto_signatures::WasiEphemeralCryptoSignatures for
input_ptr: &wiggle::GuestPtr<'_, u8>,
input_len: guest_types::Size,
) -> Result<(), guest_types::CryptoErrno> {
let input = &*input_ptr.as_array(input_len).as_slice()?;
let input = &*input_ptr
.as_array(input_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self).signature_state_update(state_handle.into(), input)?)
}
@ -77,7 +83,10 @@ impl super::wasi_ephemeral_crypto_signatures::WasiEphemeralCryptoSignatures for
input_ptr: &wiggle::GuestPtr<'_, u8>,
input_len: guest_types::Size,
) -> Result<(), guest_types::CryptoErrno> {
let input: &[u8] = &*input_ptr.as_array(input_len).as_slice()?;
let input: &[u8] = &*input_ptr
.as_array(input_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok(
(&*self)
.signature_verification_state_update(verification_state_handle.into(), input)?,

84
crates/wasi-crypto/src/wiggle_interfaces/symmetric.rs

@ -35,7 +35,8 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
) -> Result<(), guest_types::CryptoErrno> {
let key_id_buf = &mut *symmetric_key_id_ptr
.as_array(symmetric_key_id_max_len)
.as_slice_mut()?;
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self).symmetric_key_store_managed(
secrets_manager_handle.into(),
symmetric_key_handle.into(),
@ -67,7 +68,8 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
) -> Result<guest_types::SymmetricKey, guest_types::CryptoErrno> {
let symmetric_key_id = &*symmetric_key_id_ptr
.as_array(symmetric_key_id_len)
.as_slice()?;
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.symmetric_key_from_id(
secrets_manager_handle.into(),
@ -101,7 +103,10 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
raw_len: guest_types::Size,
) -> Result<guest_types::SymmetricKey, guest_types::CryptoErrno> {
let alg_str = &*alg_str.as_str()?;
let raw = &*raw_ptr.as_array(raw_len).as_slice()?;
let raw = &*raw_ptr
.as_array(raw_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self).symmetric_key_import(alg_str, raw)?.into())
}
@ -122,7 +127,8 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
) -> Result<(guest_types::Size, guest_types::Version), guest_types::CryptoErrno> {
let key_id_buf = &mut *symmetric_key_id_ptr
.as_array(symmetric_key_id_max_len)
.as_slice_mut()?;
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
let (key_id, version) = (&*self).symmetric_key_id(symmetric_key_handle.into())?;
ensure!(
key_id.len() <= key_id_buf.len(),
@ -173,7 +179,10 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
value_max_len: guest_types::Size,
) -> Result<guest_types::Size, guest_types::CryptoErrno> {
let name_str: &str = &*name_str.as_str()?;
let value = &mut *value_ptr.as_array(value_max_len).as_slice_mut()?;
let value = &mut *value_ptr
.as_array(value_max_len)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.options_get(symmetric_state_handle.into(), name_str, value)?
.try_into()?)
@ -201,7 +210,10 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
data_ptr: &wiggle::GuestPtr<'_, u8>,
data_len: guest_types::Size,
) -> Result<(), guest_types::CryptoErrno> {
let data = &*data_ptr.as_array(data_len).as_slice()?;
let data = &*data_ptr
.as_array(data_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self).symmetric_state_absorb(symmetric_state_handle.into(), data)?)
}
@ -211,7 +223,10 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
out_ptr: &wiggle::GuestPtr<'_, u8>,
out_len: guest_types::Size,
) -> Result<(), guest_types::CryptoErrno> {
let out = &mut *out_ptr.as_array(out_len).as_slice_mut()?;
let out = &mut *out_ptr
.as_array(out_len)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self).symmetric_state_squeeze(symmetric_state_handle.into(), out)?)
}
@ -252,8 +267,14 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
data_ptr: &wiggle::GuestPtr<'_, u8>,
data_len: guest_types::Size,
) -> Result<guest_types::Size, guest_types::CryptoErrno> {
let out = &mut *out_ptr.as_array(out_len).as_slice_mut()?;
let data = &*data_ptr.as_array(data_len).as_slice()?;
let out = &mut *out_ptr
.as_array(out_len)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
let data = &*data_ptr
.as_array(data_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.symmetric_state_encrypt(symmetric_state_handle.into(), out, data)?
.try_into()?)
@ -267,8 +288,14 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
data_ptr: &wiggle::GuestPtr<'_, u8>,
data_len: guest_types::Size,
) -> Result<guest_types::SymmetricTag, guest_types::CryptoErrno> {
let out = &mut *out_ptr.as_array(out_len).as_slice_mut()?;
let data = &*data_ptr.as_array(data_len).as_slice()?;
let out = &mut *out_ptr
.as_array(out_len)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
let data = &*data_ptr
.as_array(data_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.symmetric_state_encrypt_detached(symmetric_state_handle.into(), out, data)?
.into())
@ -282,8 +309,14 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
data_ptr: &wiggle::GuestPtr<'_, u8>,
data_len: guest_types::Size,
) -> Result<guest_types::Size, guest_types::CryptoErrno> {
let out = &mut *out_ptr.as_array(out_len).as_slice_mut()?;
let data = &*data_ptr.as_array(data_len).as_slice()?;
let out = &mut *out_ptr
.as_array(out_len)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
let data = &*data_ptr
.as_array(data_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.symmetric_state_decrypt(symmetric_state_handle.into(), out, data)?
.try_into()?)
@ -299,9 +332,18 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
raw_tag_ptr: &wiggle::GuestPtr<'_, u8>,
raw_tag_len: guest_types::Size,
) -> Result<guest_types::Size, guest_types::CryptoErrno> {
let out = &mut *out_ptr.as_array(out_len).as_slice_mut()?;
let data = &*data_ptr.as_array(data_len).as_slice()?;
let raw_tag: &[u8] = &*raw_tag_ptr.as_array(raw_tag_len).as_slice()?;
let out = &mut *out_ptr
.as_array(out_len)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
let data = &*data_ptr
.as_array(data_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
let raw_tag: &[u8] = &*raw_tag_ptr
.as_array(raw_tag_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.symmetric_state_decrypt_detached(symmetric_state_handle.into(), out, data, raw_tag)?
.try_into()?)
@ -331,7 +373,10 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
buf_ptr: &wiggle::GuestPtr<'_, u8>,
buf_len: guest_types::Size,
) -> Result<guest_types::Size, guest_types::CryptoErrno> {
let buf = &mut *buf_ptr.as_array(buf_len).as_slice_mut()?;
let buf = &mut *buf_ptr
.as_array(buf_len)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self)
.symmetric_tag_pull(symmetric_tag_handle.into(), buf)?
.try_into()?)
@ -343,7 +388,10 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa
expected_raw_ptr: &wiggle::GuestPtr<'_, u8>,
expected_raw_len: guest_types::Size,
) -> Result<(), guest_types::CryptoErrno> {
let expected_raw = &*expected_raw_ptr.as_array(expected_raw_len).as_slice()?;
let expected_raw = &*expected_raw_ptr
.as_array(expected_raw_len)
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok((&*self).symmetric_tag_verify(symmetric_tag_handle.into(), expected_raw)?)
}

5
crates/wasi-nn/src/impl.rs

@ -80,8 +80,11 @@ impl<'a> WasiEphemeralNn for WasiNnCtx {
out_buffer: &GuestPtr<'_, u8>,
out_buffer_max_size: u32,
) -> Result<u32> {
let mut destination = out_buffer.as_array(out_buffer_max_size).as_slice_mut()?;
if let Some(exec_context) = self.executions.get_mut(exec_context_id) {
let mut destination = out_buffer
.as_array(out_buffer_max_size)
.as_slice_mut()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
Ok(exec_context.get_output(index, &mut destination)?)
} else {
Err(UsageError::InvalidGraphHandle.into())

17
crates/wasi-nn/src/openvino.rs

@ -31,8 +31,15 @@ impl Backend for OpenvinoBackend {
// Read the guest array.
let builders = builders.as_ptr();
let xml = builders.read()?.as_slice()?;
let weights = builders.add(1)?.read()?.as_slice()?;
let xml = builders
.read()?
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
let weights = builders
.add(1)?
.read()?
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
// Construct OpenVINO graph structures: `cnn_network` contains the graph
// structure, `exec_network` can perform inference.
@ -78,6 +85,7 @@ impl BackendExecutionContext for OpenvinoExecutionContext {
let dimensions = tensor
.dimensions
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)")
.iter()
.map(|d| *d as usize)
.collect::<Vec<_>>();
@ -86,7 +94,10 @@ impl BackendExecutionContext for OpenvinoExecutionContext {
// TODO There must be some good way to discover the layout here; this
// should not have to default to NHWC.
let desc = TensorDesc::new(Layout::NHWC, &dimensions, precision);
let data = tensor.data.as_slice()?;
let data = tensor
.data
.as_slice()?
.expect("cannot use with shared memories; see https://github.com/bytecodealliance/wasmtime/issues/5235 (TODO)");
let blob = openvino::Blob::new(&desc, &data)?;
// Actually assign the blob to the request.

266
crates/wiggle/src/lib.rs

@ -513,90 +513,108 @@ impl<'a, T> GuestPtr<'a, [T]> {
/// Attempts to create a [`GuestSlice<'_, T>`] from this pointer, performing
/// bounds checks and type validation. The `GuestSlice` is a smart pointer
/// that can be used as a `&[T]` via the `Deref` trait.
/// The region of memory backing the slice will be marked as shareably
/// borrowed by the [`GuestMemory`] until the `GuestSlice` is dropped.
/// Multiple shareable borrows of the same memory are permitted, but only
/// one mutable borrow.
/// that can be used as a `&[T]` via the `Deref` trait. The region of memory
/// backing the slice will be marked as shareably borrowed by the
/// [`GuestMemory`] until the `GuestSlice` is dropped. Multiple shareable
/// borrows of the same memory are permitted, but only one mutable borrow.
///
/// This function will return a `GuestSlice` into host memory if all checks
/// succeed (valid utf-8, valid pointers, memory is not borrowed, etc). If
/// succeed (valid utf-8, valid pointers, memory is not borrowed, etc.). If
/// any checks fail then `GuestError` will be returned.
pub fn as_slice(&self) -> Result<GuestSlice<'a, T>, GuestError>
///
/// Additionally, because it is `unsafe` to have a `GuestSlice` of shared
/// memory, this function will return `None` in this case.
pub fn as_slice(&self) -> Result<Option<GuestSlice<'a, T>>, GuestError>
where
T: GuestTypeTransparent<'a>,
{
let len = match self.pointer.1.checked_mul(T::guest_size()) {
Some(l) => l,
None => return Err(GuestError::PtrOverflow),
};
let ptr =
self.mem
.validate_size_align(self.pointer.0, T::guest_align(), len)? as *mut T;
let borrow = self.mem.shared_borrow(Region {
start: self.pointer.0,
len,
})?;
// Validate all elements in slice.
// SAFETY: ptr has been validated by self.mem.validate_size_align
for offs in 0..self.pointer.1 {
T::validate(unsafe { ptr.add(offs as usize) })?;
match self.as_unsafe_slice_mut()?.shared_borrow() {
UnsafeBorrowResult::Ok(slice) => Ok(Some(slice)),
UnsafeBorrowResult::Shared(_) => Ok(None),
UnsafeBorrowResult::Err(e) => Err(e),
}
// SAFETY: iff there are no overlapping mut borrows it is valid to construct a &[T]
let ptr = unsafe { slice::from_raw_parts(ptr, self.pointer.1 as usize) };
Ok(GuestSlice {
ptr,
mem: self.mem,
borrow,
})
}
/// Attempts to create a [`GuestSliceMut<'_, T>`] from this pointer, performing
/// bounds checks and type validation. The `GuestSliceMut` is a smart pointer
/// that can be used as a `&[T]` or a `&mut [T]` via the `Deref` and `DerefMut`
/// traits. The region of memory backing the slice will be marked as borrowed
/// by the [`GuestMemory`] until the `GuestSlice` is dropped.
/// Attempts to create a [`GuestSliceMut<'_, T>`] from this pointer,
/// performing bounds checks and type validation. The `GuestSliceMut` is a
/// smart pointer that can be used as a `&[T]` or a `&mut [T]` via the
/// `Deref` and `DerefMut` traits. The region of memory backing the slice
/// will be marked as borrowed by the [`GuestMemory`] until the `GuestSlice`
/// is dropped.
///
/// This function will return a `GuestSliceMut` into host memory if all checks
/// succeed (valid utf-8, valid pointers, memory is not borrowed, etc). If
/// any checks fail then `GuestError` will be returned.
pub fn as_slice_mut(&self) -> Result<GuestSliceMut<'a, T>, GuestError>
/// This function will return a `GuestSliceMut` into host memory if all
/// checks succeed (valid utf-8, valid pointers, memory is not borrowed,
/// etc). If any checks fail then `GuestError` will be returned.
///
/// Additionally, because it is `unsafe` to have a `GuestSliceMut` of shared
/// memory, this function will return `None` in this case.
pub fn as_slice_mut(&self) -> Result<Option<GuestSliceMut<'a, T>>, GuestError>
where
T: GuestTypeTransparent<'a>,
{
let len = match self.pointer.1.checked_mul(T::guest_size()) {
Some(l) => l,
None => return Err(GuestError::PtrOverflow),
};
match self.as_unsafe_slice_mut()?.mut_borrow() {
UnsafeBorrowResult::Ok(slice) => Ok(Some(slice)),
UnsafeBorrowResult::Shared(_) => Ok(None),
UnsafeBorrowResult::Err(e) => Err(e),
}
}
/// Similar to `as_slice_mut`, this function will attempt to create a smart
/// pointer to the WebAssembly linear memory. All validation and Wiggle
/// borrow checking is the same, but unlike `as_slice_mut`, the returned
/// `&mut` slice can point to WebAssembly shared memory. Though the Wiggle
/// borrow checker can guarantee no other Wiggle calls will access this
/// slice, it cannot guarantee that another thread is not modifying the
/// `&mut` slice in some other way. Thus, access to that slice is marked
/// `unsafe`.
pub fn as_unsafe_slice_mut(&self) -> Result<UnsafeGuestSlice<'a, T>, GuestError>
where
T: GuestTypeTransparent<'a>,
{
// Validate the bounds of the region in the original memory.
let len = self.checked_byte_len()?;
let ptr =
self.mem
.validate_size_align(self.pointer.0, T::guest_align(), len)? as *mut T;
let borrow = self.mem.mut_borrow(Region {
let region = Region {
start: self.pointer.0,
len,
})?;
};
// Validate all elements in slice.
// SAFETY: ptr has been validated by self.mem.validate_size_align
// Validate all elements in slice. `T::validate` is expected to be a
// noop for `GuestTypeTransparent` so this check may not be entirely
// necessary (TODO).
//
// SAFETY: `ptr` has been validated by `self.mem.validate_size_align`.
for offs in 0..self.pointer.1 {
T::validate(unsafe { ptr.add(offs as usize) })?;
}
// SAFETY: iff there are no overlapping borrows it is valid to construct a &mut [T]
let ptr = unsafe { slice::from_raw_parts_mut(ptr, self.pointer.1 as usize) };
Ok(GuestSliceMut {
Ok(UnsafeGuestSlice {
ptr,
len: self.pointer.1 as usize,
region,
mem: self.mem,
borrow,
})
}
/// Copies the data in the guest region into a [`Vec`].
///
/// This is useful when one cannot use [`GuestPtr::as_slice`], e.g., when
/// pointing to a region of WebAssembly shared memory.
pub fn to_vec(&self) -> Result<Vec<T>, GuestError>
where
T: GuestTypeTransparent<'a> + Copy + 'a,
{
let guest_slice = self.as_unsafe_slice_mut()?;
let mut vec = Vec::with_capacity(guest_slice.len);
for offs in 0..guest_slice.len {
let elem = self.get(offs as u32).expect("already validated the size");
vec.push(elem.read()?);
}
Ok(vec)
}
/// Copies the data pointed to by `slice` into this guest region.
///
/// This method is a *safe* method to copy data from the host to the guest.
@ -613,14 +631,25 @@ impl<'a, T> GuestPtr<'a, [T]> {
where
T: GuestTypeTransparent<'a> + Copy + 'a,
{
// bounds check ...
let mut self_slice = self.as_slice_mut()?;
// Retrieve the slice of memory to copy to, performing the necessary
// bounds checks ...
let guest_slice = self.as_unsafe_slice_mut()?;
// ... length check ...
if self_slice.len() != slice.len() {
if guest_slice.len != slice.len() {
return Err(GuestError::SliceLengthsDiffer);
}
// ... and copy!
self_slice.copy_from_slice(slice);
// ... and copy the bytes.
match guest_slice.mut_borrow() {
UnsafeBorrowResult::Ok(mut dst) => dst.copy_from_slice(slice),
UnsafeBorrowResult::Shared(guest_slice) => {
// SAFETY: in the shared memory case, we copy and accept that
// the guest data may be concurrently modified. TODO: audit that
// this use of `std::ptr::copy` is safe with shared memory
// (https://github.com/bytecodealliance/wasmtime/issues/4203)
unsafe { std::ptr::copy(slice.as_ptr(), guest_slice.ptr, guest_slice.len) };
}
UnsafeBorrowResult::Err(e) => return Err(e),
}
Ok(())
}
@ -664,6 +693,17 @@ impl<'a, T> GuestPtr<'a, [T]> {
None
}
}
/// Return the number of bytes necessary to represent the pointed-to value.
fn checked_byte_len(&self) -> Result<u32, GuestError>
where
T: GuestTypeTransparent<'a>,
{
match self.pointer.1.checked_mul(T::guest_size()) {
Some(l) => Ok(l),
None => Err(GuestError::PtrOverflow),
}
}
}
impl<'a> GuestPtr<'a, str> {
@ -780,6 +820,7 @@ impl<T: ?Sized + Pointee> fmt::Debug for GuestPtr<'_, T> {
}
/// A smart pointer to an shareable slice in guest memory.
///
/// Usable as a `&'a [T]` via [`std::ops::Deref`].
pub struct GuestSlice<'a, T> {
ptr: &'a [T],
@ -801,6 +842,7 @@ impl<'a, T> Drop for GuestSlice<'a, T> {
}
/// A smart pointer to a mutable slice in guest memory.
///
/// Usable as a `&'a [T]` via [`std::ops::Deref`] and as a `&'a mut [T]` via
/// [`std::ops::DerefMut`].
pub struct GuestSliceMut<'a, T> {
@ -828,6 +870,108 @@ impl<'a, T> Drop for GuestSliceMut<'a, T> {
}
}
/// A smart pointer to an `unsafe` slice in guest memory.
///
/// Accessing guest memory (e.g., WebAssembly linear memory) is inherently
/// `unsafe`. Even though this structure expects that we will have validated the
/// addresses, lengths, and alignment, we must be extra careful to maintain the
/// Rust borrowing guarantees if we hand out slices to the underlying memory.
/// This is done in two ways:
///
/// - with shared memory (i.e., memory that may be accessed concurrently by
/// multiple threads), we have no guarantee that the underlying data will not
/// be changed; thus, we can only hand out slices `unsafe`-ly (TODO:
/// eventually with `UnsafeGuestSlice::as_slice`,
/// `UnsafeGuestSlice::as_slice_mut`)
/// - with non-shared memory, we _can_ maintain the Rust slice guarantees, but
/// only by manually performing borrow-checking of the underlying regions that
/// are accessed; this kind of borrowing is wrapped up in the [`GuestSlice`]
/// and [`GuestSliceMut`] smart pointers (see
/// [`UnsafeGuestSlice::shared_borrow`], [`UnsafeGuestSlice::mut_borrow`]).
pub struct UnsafeGuestSlice<'a, T> {
/// A raw pointer to the bytes in memory.
ptr: *mut T,
/// The (validated) number of items in the slice.
len: usize,
/// The (validated) address bounds of the slice in memory.
region: Region,
/// The original memory.
mem: &'a dyn GuestMemory,
}
impl<'a, T> UnsafeGuestSlice<'a, T> {
/// Transform an `unsafe` guest slice to a [`GuestSliceMut`].
///
/// # Safety
///
/// This function is safe if and only if:
/// - the memory is not shared (it will return `None` in this case) and
/// - there are no overlapping mutable borrows for this region.
fn shared_borrow(self) -> UnsafeBorrowResult<GuestSlice<'a, T>, Self> {
if self.mem.is_shared_memory() {
UnsafeBorrowResult::Shared(self)
} else {
match self.mem.shared_borrow(self.region) {
Ok(borrow) => {
let ptr = unsafe { slice::from_raw_parts(self.ptr, self.len) };
UnsafeBorrowResult::Ok(GuestSlice {
ptr,
mem: self.mem,
borrow,
})
}
Err(e) => UnsafeBorrowResult::Err(e),
}
}
}
/// Transform an `unsafe` guest slice to a [`GuestSliceMut`].
///
/// # Safety
///
/// This function is safe if and only if:
/// - the memory is not shared (it will return `None` in this case) and
/// - there are no overlapping borrows of any kind (shared or mutable) for
/// this region.
fn mut_borrow(self) -> UnsafeBorrowResult<GuestSliceMut<'a, T>, Self> {
if self.mem.is_shared_memory() {
UnsafeBorrowResult::Shared(self)
} else {
match self.mem.mut_borrow(self.region) {
Ok(borrow) => {
let ptr = unsafe { slice::from_raw_parts_mut(self.ptr, self.len) };
UnsafeBorrowResult::Ok(GuestSliceMut {
ptr,
mem: self.mem,
borrow,
})
}
Err(e) => UnsafeBorrowResult::Err(e),
}
}
}
}
/// A three-way result type for expressing that borrowing from an
/// [`UnsafeGuestSlice`] could fail in multiple ways. Retaining the
/// [`UnsafeGuestSlice`] in the `Shared` case allows us to reuse it.
enum UnsafeBorrowResult<T, S> {
/// The borrow succeeded.
Ok(T),
/// The borrow failed because the underlying memory was shared--we cannot
/// safely borrow in this case and return the original unsafe slice.
Shared(S),
/// The borrow failed for some other reason, e.g., the region was already
/// borrowed.
Err(GuestError),
}
impl<T, S> From<GuestError> for UnsafeBorrowResult<T, S> {
fn from(e: GuestError) -> Self {
UnsafeBorrowResult::Err(e)
}
}
/// A smart pointer to an shareable `str` in guest memory.
/// Usable as a `&'a str` via [`std::ops::Deref`].
pub struct GuestStr<'a> {

5
crates/wiggle/tests/wasi.rs

@ -147,7 +147,10 @@ impl<'a> crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx<'a> {
let len: u32 = iov.buf_len;
let buf: GuestPtr<[u8]> = base.as_array(len);
// GuestSlice will remain borrowed until dropped:
let slice = buf.as_slice().expect("borrow slice from iovec");
let slice = buf
.as_slice()
.expect("borrow slice from iovec")
.expect("expected non-shared memory");
slices.push(slice);
}
println!("iovec slices: [");

Loading…
Cancel
Save