Skip to content

Commit

Permalink
Make {String,Bytes,BytesN}::copy_into_slice strict about length.
Browse files Browse the repository at this point in the history
  • Loading branch information
graydon committed Aug 24, 2023
1 parent 9506a86 commit f27e88f
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 9 deletions.
2 changes: 1 addition & 1 deletion soroban-sdk/src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
}
}

Expand Down
31 changes: 25 additions & 6 deletions soroban-sdk/src/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -1013,11 +1017,8 @@ impl<const N: usize> BytesN<N> {
}

/// 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();
Expand Down Expand Up @@ -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();
Expand Down
21 changes: 21 additions & 0 deletions soroban-sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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].
Expand Down
28 changes: 26 additions & 2 deletions soroban-sdk/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand All @@ -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);
}
}

0 comments on commit f27e88f

Please sign in to comment.