Function holochain_wasmer_host::guest::write_bytes
source · pub fn write_bytes(
store_mut: &mut StoreMut<'_>,
memory: &Memory,
guest_ptr: GuestPtr,
slice: &[u8]
) -> Result<(), RuntimeError>
Expand description
Write a slice of bytes to the guest in a safe-ish way.
A naive approach would look like this:
let view: MemoryView<u8> = ctx.memory(0).view();
unsafe {
std::ptr::copy_nonoverlapping(
slice.as_ptr(),
view.as_ptr().add(guest_ptr) as *mut u8,
slice.len(),
);
}
The guest memory is part of the host memory, so we get the host’s pointer to the start of the
guest’s memory with view.as_ptr()
, then we add the guest’s pointer to where it wants to see the
written bytes, then copy the slice directly across.
The problem with this approach is that the guest_ptr
typically needs to be provided by the
allocator in the guest wasm in order to be safe for the guest’s consumption, but a malicious
guest could provide bogus guest_ptr
values that point outside the bounds of the guest memory.
The naive host would then corrupt its own memory by copying bytes… wherever, basically.
A better approach is to use wasmer’s WasmPtr
abstraction, which checks against the memory
bounds of the guest based on the input type and can be dereferenced to a [Cell] slice that we
can write to more safely.
@see https://docs.rs/wasmer-runtime-core/0.17.0/src/wasmer_runtime_core/memory/ptr.rs.html#120
This is still not completely safe in the face of shared memory and threads, etc.
The guest needs to provide a pointer to a pre-allocated (e.g. by leaking a Vec
It is the host’s responsibility to tell the guest the length of the allocation that is needed and the guest’s responsibility to correctly reserve an allocation to be written into.
write_bytes()
takes a slice of bytes and writes it to the position at the guest pointer.
The guest and the host negotiate the length of the bytes separately.
@see read_bytes()