Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use bytes for reading Region from wasm memory #2005

Merged
merged 4 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ and this project adheres to
- cosmwasm-vm: Upgrade Wasmer to 4.2.5; Bump `MODULE_SERIALIZATION_VERSION` to
"v9". ([#1992])
- cosmwasm-std: Rename `GovMsg::vote` to `GovMsg::option` ([#1999])
- cosmwasm-vm: Read `Region` from Wasm memory as bytes and convert to `Region`
afterwards ([#2005])

[#1874]: https://github.com/CosmWasm/cosmwasm/pull/1874
[#1876]: https://github.com/CosmWasm/cosmwasm/pull/1876
Expand All @@ -119,6 +121,7 @@ and this project adheres to
[#1977]: https://github.com/CosmWasm/cosmwasm/pull/1977
[#1992]: https://github.com/CosmWasm/cosmwasm/pull/1992
[#1999]: https://github.com/CosmWasm/cosmwasm/pull/1999
[#2005]: https://github.com/CosmWasm/cosmwasm/pull/2005

### Removed

Expand Down
57 changes: 49 additions & 8 deletions packages/vm/src/memory.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::mem::MaybeUninit;
use std::mem::{size_of, MaybeUninit};

use wasmer::{ValueType, WasmPtr};

Expand Down Expand Up @@ -26,6 +26,37 @@ pub struct Region {
pub length: u32,
}

/// Byte representation of a [Region] struct in Wasm memory.
type RegionBytes = [u8; size_of::<Region>()];

chipshort marked this conversation as resolved.
Show resolved Hide resolved
impl Region {
fn from_wasm_bytes(bytes: RegionBytes) -> Self {
let offset = u32::from_le_bytes(bytes[0..4].try_into().unwrap());
let capacity = u32::from_le_bytes(bytes[4..8].try_into().unwrap());
chipshort marked this conversation as resolved.
Show resolved Hide resolved
let length = u32::from_le_bytes(bytes[8..12].try_into().unwrap());
Region {
offset,
capacity,
length,
}
}

fn into_wasm_bytes(self) -> RegionBytes {
let Region {
offset,
capacity,
length,
} = self;

let mut bytes = [0u8; 12];
// wasm is little endian
bytes[0..4].copy_from_slice(&offset.to_le_bytes());
bytes[4..8].copy_from_slice(&capacity.to_le_bytes());
bytes[8..12].copy_from_slice(&length.to_le_bytes());
bytes
}
}

unsafe impl ValueType for Region {
fn zero_padding_bytes(&self, _bytes: &mut [MaybeUninit<u8>]) {
// The size of Region is exactly 3x4=12 bytes with no padding.
Expand All @@ -34,6 +65,14 @@ unsafe impl ValueType for Region {
}
}

// Wasm is little endian, and we want to be able to just reinterpret slices of
// wasm memory as a Region struct, so we only support little endian systems.
// If we ever need to support big endian systems, we can use more fine-grained checks
// in the places where we read/write the Region struct
// (and possibly other interactions between Wasm and host).
#[cfg(target_endian = "big")]
compile_error!("big endian systems are not supported");

/// Expects a (fixed size) Region struct at ptr, which is read. This links to the
/// memory region, which is copied in the second step.
/// Errors if the length of the region exceeds `max_length`.
Expand Down Expand Up @@ -91,10 +130,10 @@ pub fn write_region(memory: &wasmer::MemoryView, ptr: u32, data: &[u8]) -> VmRes

/// Reads in a Region at offset in Wasm memory and returns a copy of it
fn get_region(memory: &wasmer::MemoryView, offset: u32) -> CommunicationResult<Region> {
let wptr = WasmPtr::<Region>::new(offset);
let region = wptr.deref(memory).read().map_err(|_err| {
let wptr = WasmPtr::<RegionBytes>::new(offset);
let region = Region::from_wasm_bytes(wptr.deref(memory).read().map_err(|_err| {
CommunicationError::deref_err(offset, "Could not dereference this pointer to a Region")
})?;
})?);
validate_region(&region)?;
Ok(region)
}
Expand Down Expand Up @@ -122,10 +161,12 @@ fn validate_region(region: &Region) -> RegionValidationResult<()> {

/// Overrides a Region at offset in Wasm memory
fn set_region(memory: &wasmer::MemoryView, offset: u32, data: Region) -> CommunicationResult<()> {
let wptr = WasmPtr::<Region>::new(offset);
wptr.deref(memory).write(data).map_err(|_err| {
CommunicationError::deref_err(offset, "Could not dereference this pointer to a Region")
})?;
let wptr = WasmPtr::<RegionBytes>::new(offset);
wptr.deref(memory)
.write(data.into_wasm_bytes())
.map_err(|_err| {
CommunicationError::deref_err(offset, "Could not dereference this pointer to a Region")
})?;
Ok(())
}

Expand Down
Loading