diff --git a/packages/std/src/exports.rs b/packages/std/src/exports.rs index 92c027dd61..3d9e445c3a 100644 --- a/packages/std/src/exports.rs +++ b/packages/std/src/exports.rs @@ -128,7 +128,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } /// do_execute should be wrapped in an external "C" export, containing a contract-specific function as arg @@ -158,7 +158,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } /// do_migrate should be wrapped in an external "C" export, containing a contract-specific function as arg @@ -186,7 +186,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } /// do_sudo should be wrapped in an external "C" export, containing a contract-specific function as arg @@ -214,7 +214,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } /// do_reply should be wrapped in an external "C" export, containing a contract-specific function as arg @@ -241,7 +241,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } /// do_query should be wrapped in an external "C" export, containing a contract-specific function as arg @@ -267,7 +267,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } /// do_ibc_channel_open is designed for use with #[entry_point] to make a "C" extern @@ -294,7 +294,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } /// do_ibc_channel_connect is designed for use with #[entry_point] to make a "C" extern @@ -323,7 +323,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } /// do_ibc_channel_close is designed for use with #[entry_point] to make a "C" extern @@ -352,7 +352,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } /// do_ibc_packet_receive is designed for use with #[entry_point] to make a "C" extern @@ -382,7 +382,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } /// do_ibc_packet_ack is designed for use with #[entry_point] to make a "C" extern @@ -412,7 +412,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } /// do_ibc_packet_timeout is designed for use with #[entry_point] to make a "C" extern @@ -443,7 +443,7 @@ where msg_ptr as *mut Region, ); let v = to_json_vec(&res).unwrap(); - Region::from_data(v).to_heap_ptr() as u32 + Region::from_vec(v).to_heap_ptr() as u32 } fn _do_instantiate( diff --git a/packages/std/src/imports.rs b/packages/std/src/imports.rs index 18c52e699c..c819c97a5b 100644 --- a/packages/std/src/imports.rs +++ b/packages/std/src/imports.rs @@ -106,7 +106,7 @@ impl ExternalStorage { impl Storage for ExternalStorage { fn get(&self, key: &[u8]) -> Option> { - let key = Region::from_data(key); + let key = Region::from_slice(key); let key_ptr = key.as_ptr() as u32; let read = unsafe { db_read(key_ptr) }; @@ -126,17 +126,17 @@ impl Storage for ExternalStorage { panic!("TL;DR: Value must not be empty in Storage::set but in most cases you can use Storage::remove instead. Long story: Getting empty values from storage is not well supported at the moment. Some of our internal interfaces cannot differentiate between a non-existent key and an empty value. Right now, you cannot rely on the behaviour of empty values. To protect you from trouble later on, we stop here. Sorry for the inconvenience! We highly welcome you to contribute to CosmWasm, making this more solid one way or the other."); } - let key = Region::from_data(key); + let key = Region::from_slice(key); let key_ptr = key.as_ptr() as u32; - let value = Region::from_data(value); + let value = Region::from_slice(value); let value_ptr = value.as_ptr() as u32; unsafe { db_write(key_ptr, value_ptr) }; } fn remove(&mut self, key: &[u8]) { - let key = Region::from_data(key); + let key = Region::from_slice(key); let key_ptr = key.as_ptr() as u32; unsafe { db_remove(key_ptr) }; @@ -189,8 +189,8 @@ impl Storage for ExternalStorage { fn create_iter(start: Option<&[u8]>, end: Option<&[u8]>, order: Order) -> u32 { // There is lots of gotchas on turning options into regions for FFI, thus this design // See: https://github.com/CosmWasm/cosmwasm/pull/509 - let start_region = start.map(Region::from_data); - let end_region = end.map(Region::from_data); + let start_region = start.map(Region::from_slice); + let end_region = end.map(Region::from_slice); let start_region_addr = get_optional_region_address(&start_region.as_ref()); let end_region_addr = get_optional_region_address(&end_region.as_ref()); unsafe { db_scan(start_region_addr, end_region_addr, order as i32) } @@ -313,7 +313,7 @@ impl Api for ExternalApi { // Stop here to allow handling the error in the contract. return Err(StdError::generic_err("input too long for addr_validate")); } - let source = Region::from_data(input_bytes); + let source = Region::from_slice(input_bytes); let source_ptr = source.as_ptr() as u32; let result = unsafe { addr_validate(source_ptr) }; @@ -339,7 +339,7 @@ impl Api for ExternalApi { "input too long for addr_canonicalize", )); } - let send = Region::from_data(input_bytes); + let send = Region::from_slice(input_bytes); let send_ptr = send.as_ptr() as u32; let canon = Region::with_capacity(CANONICAL_ADDRESS_BUFFER_LENGTH); @@ -357,7 +357,7 @@ impl Api for ExternalApi { } fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult { - let send = Region::from_data(canonical.as_slice()); + let send = Region::from_slice(canonical.as_slice()); let send_ptr = send.as_ptr() as u32; let human = Region::with_capacity(HUMAN_ADDRESS_BUFFER_LENGTH); @@ -383,11 +383,11 @@ impl Api for ExternalApi { signature: &[u8], public_key: &[u8], ) -> Result { - let hash_send = Region::from_data(message_hash); + let hash_send = Region::from_slice(message_hash); let hash_send_ptr = hash_send.as_ptr() as u32; - let sig_send = Region::from_data(signature); + let sig_send = Region::from_slice(signature); let sig_send_ptr = sig_send.as_ptr() as u32; - let pubkey_send = Region::from_data(public_key); + let pubkey_send = Region::from_slice(public_key); let pubkey_send_ptr = pubkey_send.as_ptr() as u32; let result = unsafe { secp256k1_verify(hash_send_ptr, sig_send_ptr, pubkey_send_ptr) }; @@ -409,9 +409,9 @@ impl Api for ExternalApi { signature: &[u8], recover_param: u8, ) -> Result, RecoverPubkeyError> { - let hash_send = Region::from_data(message_hash); + let hash_send = Region::from_slice(message_hash); let hash_send_ptr = hash_send.as_ptr() as u32; - let sig_send = Region::from_data(signature); + let sig_send = Region::from_slice(signature); let sig_send_ptr = sig_send.as_ptr() as u32; let result = @@ -439,11 +439,11 @@ impl Api for ExternalApi { signature: &[u8], public_key: &[u8], ) -> Result { - let hash_send = Region::from_data(message_hash); + let hash_send = Region::from_slice(message_hash); let hash_send_ptr = hash_send.as_ptr() as u32; - let sig_send = Region::from_data(signature); + let sig_send = Region::from_slice(signature); let sig_send_ptr = sig_send.as_ptr() as u32; - let pubkey_send = Region::from_data(public_key); + let pubkey_send = Region::from_slice(public_key); let pubkey_send_ptr = pubkey_send.as_ptr() as u32; let result = unsafe { secp256r1_verify(hash_send_ptr, sig_send_ptr, pubkey_send_ptr) }; @@ -466,9 +466,9 @@ impl Api for ExternalApi { signature: &[u8], recover_param: u8, ) -> Result, RecoverPubkeyError> { - let hash_send = Region::from_data(message_hash); + let hash_send = Region::from_slice(message_hash); let hash_send_ptr = hash_send.as_ptr() as u32; - let sig_send = Region::from_data(signature); + let sig_send = Region::from_slice(signature); let sig_send_ptr = sig_send.as_ptr() as u32; let result = @@ -495,11 +495,11 @@ impl Api for ExternalApi { signature: &[u8], public_key: &[u8], ) -> Result { - let msg_send = Region::from_data(message); + let msg_send = Region::from_slice(message); let msg_send_ptr = msg_send.as_ptr() as u32; - let sig_send = Region::from_data(signature); + let sig_send = Region::from_slice(signature); let sig_send_ptr = sig_send.as_ptr() as u32; - let pubkey_send = Region::from_data(public_key); + let pubkey_send = Region::from_slice(public_key); let pubkey_send_ptr = pubkey_send.as_ptr() as u32; let result = unsafe { ed25519_verify(msg_send_ptr, sig_send_ptr, pubkey_send_ptr) }; @@ -522,15 +522,15 @@ impl Api for ExternalApi { public_keys: &[&[u8]], ) -> Result { let msgs_encoded = encode_sections(messages); - let msgs_send = Region::from_data(msgs_encoded); + let msgs_send = Region::from_vec(msgs_encoded); let msgs_send_ptr = msgs_send.as_ptr() as u32; let sigs_encoded = encode_sections(signatures); - let sig_sends = Region::from_data(sigs_encoded); + let sig_sends = Region::from_vec(sigs_encoded); let sigs_send_ptr = sig_sends.as_ptr() as u32; let pubkeys_encoded = encode_sections(public_keys); - let pubkeys_send = Region::from_data(pubkeys_encoded); + let pubkeys_send = Region::from_vec(pubkeys_encoded); let pubkeys_send_ptr = pubkeys_send.as_ptr() as u32; let result = @@ -548,8 +548,8 @@ impl Api for ExternalApi { } fn debug(&self, message: &str) { - // keep the boxes in scope, so we free it at the end (don't cast to pointers same line as Region::from_data) - let region = Region::from_data(message.as_bytes()); + // keep the boxes in scope, so we free it at the end (don't cast to pointers same line as Region::from_slice) + let region = Region::from_slice(message.as_bytes()); let region_ptr = region.as_ptr() as u32; unsafe { debug(region_ptr) }; } @@ -574,7 +574,7 @@ impl ExternalQuerier { impl Querier for ExternalQuerier { fn raw_query(&self, bin_request: &[u8]) -> QuerierResult { - let req = Region::from_data(bin_request); + let req = Region::from_slice(bin_request); let request_ptr = req.as_ptr() as u32; let response_ptr = unsafe { query_chain(request_ptr) }; @@ -592,7 +592,7 @@ impl Querier for ExternalQuerier { #[cfg(feature = "abort")] pub fn handle_panic(message: &str) { - let region = Region::from_data(message.as_bytes()); + let region = Region::from_slice(message.as_bytes()); let region_ptr = region.as_ptr() as u32; unsafe { abort(region_ptr) }; } diff --git a/packages/std/src/memory.rs b/packages/std/src/memory.rs index c8f6fa6134..9f9ce02513 100644 --- a/packages/std/src/memory.rs +++ b/packages/std/src/memory.rs @@ -1,59 +1,6 @@ use alloc::vec::Vec; use core::{any::TypeId, marker::PhantomData, mem, ops::Deref, slice}; -/// Element that can be used to construct a new `Region` -/// -/// # Safety -/// -/// The following invariant must be upheld: -/// -/// - full allocated capacity == value returned by capacity -/// -/// This is important to uphold the safety invariant of the `dealloc` method, which requires us to pass the same Layout -/// into it as was used to allocate a memory region. -/// And since `size` is one of the parameters, it is important to pass in the exact same capacity. -/// -/// See: -pub unsafe trait RegionSource { - type Ownership: Ownership; - - fn ptr(&self) -> *const u8; - fn len(&self) -> usize; - fn capacity(&self) -> usize; -} - -unsafe impl RegionSource for &[u8] { - type Ownership = Borrowed; - - fn ptr(&self) -> *const u8 { - self.as_ptr() - } - - fn len(&self) -> usize { - (*self).len() - } - - fn capacity(&self) -> usize { - self.len() - } -} - -unsafe impl RegionSource for Vec { - type Ownership = Owned; - - fn ptr(&self) -> *const u8 { - self.as_ptr() - } - - fn len(&self) -> usize { - self.len() - } - - fn capacity(&self) -> usize { - self.capacity() - } -} - mod sealed { pub trait Sealed: 'static {} @@ -86,7 +33,20 @@ pub struct Region { _marker: PhantomData, } +impl Region { + pub fn from_slice(slice: &[u8]) -> Self { + unsafe { Self::from_parts(slice.as_ptr(), slice.len(), slice.len()) } + } +} + impl Region { + /// Construct a region from an existing vector + pub fn from_vec(vec: Vec) -> Self { + let region = unsafe { Self::from_parts(vec.as_ptr(), vec.capacity(), vec.len()) }; + mem::forget(vec); + region + } + /// Reconstruct a region from a raw pointer pointing to a `Box`. /// You'll want to use this when you received a region from the VM and want to dereference its contents. /// @@ -104,7 +64,7 @@ impl Region { /// Construct a new empty region with *at least* a capacity of what you passed in and a length of 0 pub fn with_capacity(cap: usize) -> Self { let data = Vec::with_capacity(cap); - let region = Self::from_data(data); + let region = Self::from_vec(data); region } @@ -121,37 +81,22 @@ impl Region { } } -impl Region +impl Region where - O: Ownership, + T: Ownership, { - /// Construct a new region from any kind of data that can be turned into a region - pub fn from_data(data: S) -> Self - where - S: RegionSource, - { + unsafe fn from_parts(ptr: *const u8, capacity: usize, length: usize) -> Self { // Well, this technically violates pointer provenance rules. // But there isn't a stable API for it, so that's the best we can do, I guess. - let region = Region { - offset: u32::try_from(data.ptr() as usize).expect("pointer doesn't fit in u32"), - capacity: u32::try_from(data.capacity()).expect("capacity doesn't fit in u32"), - length: u32::try_from(data.len()).expect("length doesn't fit in u32"), + Region { + offset: u32::try_from(ptr as usize).expect("pointer doesn't fit in u32"), + capacity: u32::try_from(capacity).expect("capacity doesn't fit in u32"), + length: u32::try_from(length).expect("length doesn't fit in u32"), _marker: PhantomData, - }; - - // We gonna forget this.. as a safety measure.. - // If we didn't do this and the `RegionSource` was a `Vec` we would deallocate it and that's BAD - mem::forget(data); - - region + } } -} -impl Region -where - T: Ownership, -{ /// Access the memory region this region points to in form of a byte slice pub fn as_bytes(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.offset as *const u8, self.length as usize) }