diff --git a/soroban-sdk/src/address.rs b/soroban-sdk/src/address.rs index 9559d59ab..f2fd31f22 100644 --- a/soroban-sdk/src/address.rs +++ b/soroban-sdk/src/address.rs @@ -265,7 +265,7 @@ impl Address { pub(crate) fn contract_id(&self) -> BytesN<32> { match self.try_contract_id() { Some(contract_id) => contract_id, - None => panic!("Address is not a Contract ID"), + None => sdk_panic!("Address is not a Contract ID"), } } diff --git a/soroban-sdk/src/bytes.rs b/soroban-sdk/src/bytes.rs index 2df83df8e..c4e97487d 100644 --- a/soroban-sdk/src/bytes.rs +++ b/soroban-sdk/src/bytes.rs @@ -561,11 +561,15 @@ impl Bytes { /// Copy the bytes into the given slice. /// - /// The minimum number of bytes are copied to either exhaust [Bytes] or fill - /// slice. + /// ### Panics + /// + /// If the output slice and bytes are of different lengths. #[inline(always)] pub fn copy_into_slice(&self, slice: &mut [u8]) { let env = self.env(); + if self.len() as usize != slice.len() { + sdk_panic!("Bytes::copy_into_slice with mismatched slice length") + } env.bytes_copy_to_slice(self.to_object(), Val::U32_ZERO, slice) .unwrap_optimized(); } @@ -1013,11 +1017,8 @@ impl BytesN { } /// Copy the bytes into the given slice. - /// - /// The minimum number of bytes are copied to either exhaust [BytesN] or fill - /// slice. #[inline(always)] - pub fn copy_into_slice(&self, slice: &mut [u8]) { + pub fn copy_into_slice(&self, slice: &mut [u8; N]) { let env = self.env(); env.bytes_copy_to_slice(self.to_object(), Val::U32_ZERO, slice) .unwrap_optimized(); @@ -1127,6 +1128,24 @@ mod test { assert_eq!([1, 2, 3, 4], out); } + #[test] + #[should_panic] + fn bytes_to_short_slice() { + let env = Env::default(); + let b = Bytes::from_slice(&env, &[1, 2, 3, 4]); + let mut out = [0u8; 3]; + b.copy_into_slice(&mut out); + } + + #[test] + #[should_panic] + fn bytes_to_long_slice() { + let env = Env::default(); + let b = Bytes::from_slice(&env, &[1, 2, 3, 4]); + let mut out = [0u8; 5]; + b.copy_into_slice(&mut out); + } + #[test] fn macro_bytes() { let env = Env::default(); diff --git a/soroban-sdk/src/lib.rs b/soroban-sdk/src/lib.rs index 40acbe870..809411af7 100644 --- a/soroban-sdk/src/lib.rs +++ b/soroban-sdk/src/lib.rs @@ -672,6 +672,27 @@ macro_rules! panic_error { }}; } +/// An internal panic! variant that avoids including the string +/// when building for wasm (since it's just pointless baggage). +#[cfg(target_family = "wasm")] +macro_rules! sdk_panic { + ($_msg:literal) => { + panic!() + }; + () => { + panic!() + }; +} +#[cfg(not(target_family = "wasm"))] +macro_rules! sdk_panic { + ($msg:literal) => { + panic!($msg) + }; + () => { + panic!() + }; +} + /// Assert a condition and panic with the given error if it is false. /// /// The first argument in the list must be a reference to an [Env]. diff --git a/soroban-sdk/src/string.rs b/soroban-sdk/src/string.rs index 147afb21e..be78b88c9 100644 --- a/soroban-sdk/src/string.rs +++ b/soroban-sdk/src/string.rs @@ -211,11 +211,15 @@ impl String { /// Copy the bytes in [String] into the given slice. /// - /// The minimum number of bytes are copied to either exhaust [String] or fill - /// slice. + /// ### Panics + /// + /// If the output slice and string are of different lengths. #[inline(always)] pub fn copy_into_slice(&self, slice: &mut [u8]) { let env = self.env(); + if self.len() as usize != slice.len() { + sdk_panic!("String::copy_into_slice with mismatched slice length") + } env.string_copy_to_slice(self.to_object(), Val::U32_ZERO, slice) .unwrap_optimized(); } @@ -235,4 +239,24 @@ mod test { s.copy_into_slice(&mut out); assert_eq!(msg.as_bytes(), out) } + + #[test] + #[should_panic] + fn string_to_short_slice() { + let env = Env::default(); + let msg = "a message"; + let s = String::from_slice(&env, msg); + let mut out = [0u8; 8]; + s.copy_into_slice(&mut out); + } + + #[test] + #[should_panic] + fn string_to_long_slice() { + let env = Env::default(); + let msg = "a message"; + let s = String::from_slice(&env, msg); + let mut out = [0u8; 10]; + s.copy_into_slice(&mut out); + } }