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`
This commit is contained in:
@@ -468,12 +468,14 @@ 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()
|
||||
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()?)
|
||||
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>>()?;
|
||||
|
||||
@@ -497,12 +499,14 @@ 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()
|
||||
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()?)
|
||||
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>>()?;
|
||||
|
||||
@@ -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>>()?;
|
||||
|
||||
|
||||
@@ -521,12 +521,14 @@ 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()
|
||||
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()?)
|
||||
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>>()?;
|
||||
|
||||
@@ -550,12 +552,14 @@ 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()
|
||||
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()?)
|
||||
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>>()?;
|
||||
|
||||
@@ -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,12 +1294,15 @@ 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
|
||||
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()?)
|
||||
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>>()?;
|
||||
|
||||
@@ -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>>()?;
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)?,
|
||||
|
||||
@@ -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)?)
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
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) })?;
|
||||
}
|
||||
|
||||
// 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.
|
||||
///
|
||||
/// 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>
|
||||
/// 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),
|
||||
};
|
||||
match self.as_unsafe_slice_mut()?.shared_borrow() {
|
||||
UnsafeBorrowResult::Ok(slice) => Ok(Some(slice)),
|
||||
UnsafeBorrowResult::Shared(_) => Ok(None),
|
||||
UnsafeBorrowResult::Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// 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>,
|
||||
{
|
||||
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> {
|
||||
|
||||
@@ -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: [");
|
||||
|
||||
Reference in New Issue
Block a user