From 69cb28ce0ccdc94a0ab3809f7a279993d0156e33 Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Fri, 22 Jan 2021 15:35:20 -0800 Subject: [PATCH 1/5] usize hack to quickly see wasmer perf, do not merge --- borsh/src/de/mod.rs | 54 +++++++++++++++----------------------------- borsh/src/ser/mod.rs | 22 ++++++++---------- 2 files changed, 28 insertions(+), 48 deletions(-) diff --git a/borsh/src/de/mod.rs b/borsh/src/de/mod.rs index 0116383ee..fb25dea00 100644 --- a/borsh/src/de/mod.rs +++ b/borsh/src/de/mod.rs @@ -50,10 +50,7 @@ impl BorshDeserialize for u8 { #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.is_empty() { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); + return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); } let res = buf[0]; *buf = &buf[1..]; @@ -95,6 +92,13 @@ impl_for_integer!(u32); impl_for_integer!(u64); impl_for_integer!(u128); +impl BorshDeserialize for usize { + fn deserialize(buf: &mut &[u8]) -> Result { + let u: u64 = BorshDeserialize::deserialize(buf)?; + Ok(u as usize) + } +} + // Note NaNs have a portability issue. Specifically, signalling NaNs on MIPS are quiet NaNs on x86, // and vice-versa. We disallow NaNs to avoid this issue. macro_rules! impl_for_float { @@ -131,10 +135,7 @@ impl BorshDeserialize for bool { #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.is_empty() { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); + return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); } let b = buf[0]; *buf = &buf[1..]; @@ -157,10 +158,7 @@ where #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.is_empty() { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); + return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); } let flag = buf[0]; *buf = &buf[1..]; @@ -169,10 +167,8 @@ where } else if flag == 1 { Ok(Some(T::deserialize(buf)?)) } else { - let msg = format!( - "Invalid Option representation: {}. The first byte must be 0 or 1", - flag - ); + let msg = + format!("Invalid Option representation: {}. The first byte must be 0 or 1", flag); Err(Error::new(ErrorKind::InvalidInput, msg)) } @@ -187,10 +183,7 @@ where #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.is_empty() { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); + return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); } let flag = buf[0]; *buf = &buf[1..]; @@ -199,10 +192,8 @@ where } else if flag == 1 { Ok(Ok(T::deserialize(buf)?)) } else { - let msg = format!( - "Invalid Result representation: {}. The first byte must be 0 or 1", - flag - ); + let msg = + format!("Invalid Result representation: {}. The first byte must be 0 or 1", flag); Err(Error::new(ErrorKind::InvalidInput, msg)) } @@ -231,10 +222,7 @@ where } else if T::is_u8() && size_of::() == size_of::() { let len = len.try_into().map_err(|_| ErrorKind::InvalidInput)?; if buf.len() < len { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); + return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); } let result = buf[..len].to_vec(); *buf = &buf[len..]; @@ -423,10 +411,7 @@ impl BorshDeserialize for std::net::Ipv4Addr { #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.len() < 4 { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); + return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); } let bytes: [u8; 4] = buf[..4].try_into().unwrap(); let res = std::net::Ipv4Addr::from(bytes); @@ -440,10 +425,7 @@ impl BorshDeserialize for std::net::Ipv6Addr { #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.len() < 16 { - return Err(Error::new( - ErrorKind::InvalidInput, - ERROR_UNEXPECTED_LENGTH_OF_INPUT, - )); + return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); } let bytes: [u8; 16] = buf[..16].try_into().unwrap(); let res = std::net::Ipv6Addr::from(bytes); diff --git a/borsh/src/ser/mod.rs b/borsh/src/ser/mod.rs index 35e65796b..ee06db98d 100644 --- a/borsh/src/ser/mod.rs +++ b/borsh/src/ser/mod.rs @@ -68,6 +68,12 @@ impl_for_integer!(u32); impl_for_integer!(u64); impl_for_integer!(u128); +impl BorshSerialize for usize { + fn serialize(&self, writer: &mut W) -> Result<()> { + BorshSerialize::serialize(&(*self as u64), writer) + } +} + // Note NaNs have a portability issue. Specifically, signalling NaNs on MIPS are quiet NaNs on x86, // and vice-versa. We disallow NaNs to avoid this issue. macro_rules! impl_for_float { @@ -262,9 +268,7 @@ where fn serialize(&self, writer: &mut W) -> Result<()> { let mut vec = self.iter().collect::>(); vec.sort_by(|(a, _), (b, _)| a.partial_cmp(b).unwrap()); - u32::try_from(vec.len()) - .map_err(|_| ErrorKind::InvalidInput)? - .serialize(writer)?; + u32::try_from(vec.len()).map_err(|_| ErrorKind::InvalidInput)?.serialize(writer)?; for (key, value) in vec { key.serialize(writer)?; value.serialize(writer)?; @@ -281,9 +285,7 @@ where fn serialize(&self, writer: &mut W) -> Result<()> { let mut vec = self.iter().collect::>(); vec.sort_by(|a, b| a.partial_cmp(b).unwrap()); - u32::try_from(vec.len()) - .map_err(|_| ErrorKind::InvalidInput)? - .serialize(writer)?; + u32::try_from(vec.len()).map_err(|_| ErrorKind::InvalidInput)?.serialize(writer)?; for item in vec { item.serialize(writer)?; } @@ -301,9 +303,7 @@ where // NOTE: BTreeMap iterates over the entries that are sorted by key, so the serialization // result will be consistent without a need to sort the entries as we do for HashMap // serialization. - u32::try_from(self.len()) - .map_err(|_| ErrorKind::InvalidInput)? - .serialize(writer)?; + u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidInput)?.serialize(writer)?; for (key, value) in self { key.serialize(writer)?; value.serialize(writer)?; @@ -320,9 +320,7 @@ where fn serialize(&self, writer: &mut W) -> Result<()> { // NOTE: BTreeSet iterates over the items that are sorted, so the serialization result will // be consistent without a need to sort the entries as we do for HashSet serialization. - u32::try_from(self.len()) - .map_err(|_| ErrorKind::InvalidInput)? - .serialize(writer)?; + u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidInput)?.serialize(writer)?; for item in self { item.serialize(writer)?; } From e75f28e7877c9ef390106e4211d885c5d0246441 Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Mon, 25 Jan 2021 09:57:23 -0800 Subject: [PATCH 2/5] handle overflow error to make it not a hack --- borsh/src/de/mod.rs | 58 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/borsh/src/de/mod.rs b/borsh/src/de/mod.rs index fb25dea00..264a89d06 100644 --- a/borsh/src/de/mod.rs +++ b/borsh/src/de/mod.rs @@ -1,5 +1,5 @@ use core::{ - convert::TryInto, + convert::{TryFrom, TryInto}, hash::Hash, mem::{forget, size_of}, }; @@ -18,6 +18,7 @@ mod hint; const ERROR_NOT_ALL_BYTES_READ: &str = "Not all bytes read"; const ERROR_UNEXPECTED_LENGTH_OF_INPUT: &str = "Unexpected length of input"; +const ERROR_USIZE_OVERFLOW_IN_32_BIT_MACHINE: &str = "Deserialize usize overflow in 32 bit machine"; /// A data-structure that can be de-serialized from binary format by NBOR. pub trait BorshDeserialize: Sized { @@ -50,7 +51,10 @@ impl BorshDeserialize for u8 { #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.is_empty() { - return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); + return Err(Error::new( + ErrorKind::InvalidInput, + ERROR_UNEXPECTED_LENGTH_OF_INPUT, + )); } let res = buf[0]; *buf = &buf[1..]; @@ -95,7 +99,13 @@ impl_for_integer!(u128); impl BorshDeserialize for usize { fn deserialize(buf: &mut &[u8]) -> Result { let u: u64 = BorshDeserialize::deserialize(buf)?; - Ok(u as usize) + let u = usize::try_from(u).map_err(|_| { + Error::new( + ErrorKind::InvalidInput, + ERROR_USIZE_OVERFLOW_IN_32_BIT_MACHINE, + ) + })?; + Ok(u) } } @@ -135,7 +145,10 @@ impl BorshDeserialize for bool { #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.is_empty() { - return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); + return Err(Error::new( + ErrorKind::InvalidInput, + ERROR_UNEXPECTED_LENGTH_OF_INPUT, + )); } let b = buf[0]; *buf = &buf[1..]; @@ -158,7 +171,10 @@ where #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.is_empty() { - return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); + return Err(Error::new( + ErrorKind::InvalidInput, + ERROR_UNEXPECTED_LENGTH_OF_INPUT, + )); } let flag = buf[0]; *buf = &buf[1..]; @@ -167,8 +183,10 @@ where } else if flag == 1 { Ok(Some(T::deserialize(buf)?)) } else { - let msg = - format!("Invalid Option representation: {}. The first byte must be 0 or 1", flag); + let msg = format!( + "Invalid Option representation: {}. The first byte must be 0 or 1", + flag + ); Err(Error::new(ErrorKind::InvalidInput, msg)) } @@ -183,7 +201,10 @@ where #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.is_empty() { - return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); + return Err(Error::new( + ErrorKind::InvalidInput, + ERROR_UNEXPECTED_LENGTH_OF_INPUT, + )); } let flag = buf[0]; *buf = &buf[1..]; @@ -192,8 +213,10 @@ where } else if flag == 1 { Ok(Ok(T::deserialize(buf)?)) } else { - let msg = - format!("Invalid Result representation: {}. The first byte must be 0 or 1", flag); + let msg = format!( + "Invalid Result representation: {}. The first byte must be 0 or 1", + flag + ); Err(Error::new(ErrorKind::InvalidInput, msg)) } @@ -222,7 +245,10 @@ where } else if T::is_u8() && size_of::() == size_of::() { let len = len.try_into().map_err(|_| ErrorKind::InvalidInput)?; if buf.len() < len { - return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); + return Err(Error::new( + ErrorKind::InvalidInput, + ERROR_UNEXPECTED_LENGTH_OF_INPUT, + )); } let result = buf[..len].to_vec(); *buf = &buf[len..]; @@ -411,7 +437,10 @@ impl BorshDeserialize for std::net::Ipv4Addr { #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.len() < 4 { - return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); + return Err(Error::new( + ErrorKind::InvalidInput, + ERROR_UNEXPECTED_LENGTH_OF_INPUT, + )); } let bytes: [u8; 4] = buf[..4].try_into().unwrap(); let res = std::net::Ipv4Addr::from(bytes); @@ -425,7 +454,10 @@ impl BorshDeserialize for std::net::Ipv6Addr { #[inline] fn deserialize(buf: &mut &[u8]) -> Result { if buf.len() < 16 { - return Err(Error::new(ErrorKind::InvalidInput, ERROR_UNEXPECTED_LENGTH_OF_INPUT)); + return Err(Error::new( + ErrorKind::InvalidInput, + ERROR_UNEXPECTED_LENGTH_OF_INPUT, + )); } let bytes: [u8; 16] = buf[..16].try_into().unwrap(); let res = std::net::Ipv6Addr::from(bytes); From bc9b8952011393855ae101bd0f572dc786f60d89 Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Mon, 25 Jan 2021 09:57:53 -0800 Subject: [PATCH 3/5] cargo fmt --- borsh/src/ser/mod.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/borsh/src/ser/mod.rs b/borsh/src/ser/mod.rs index ee06db98d..3192c9378 100644 --- a/borsh/src/ser/mod.rs +++ b/borsh/src/ser/mod.rs @@ -268,7 +268,9 @@ where fn serialize(&self, writer: &mut W) -> Result<()> { let mut vec = self.iter().collect::>(); vec.sort_by(|(a, _), (b, _)| a.partial_cmp(b).unwrap()); - u32::try_from(vec.len()).map_err(|_| ErrorKind::InvalidInput)?.serialize(writer)?; + u32::try_from(vec.len()) + .map_err(|_| ErrorKind::InvalidInput)? + .serialize(writer)?; for (key, value) in vec { key.serialize(writer)?; value.serialize(writer)?; @@ -285,7 +287,9 @@ where fn serialize(&self, writer: &mut W) -> Result<()> { let mut vec = self.iter().collect::>(); vec.sort_by(|a, b| a.partial_cmp(b).unwrap()); - u32::try_from(vec.len()).map_err(|_| ErrorKind::InvalidInput)?.serialize(writer)?; + u32::try_from(vec.len()) + .map_err(|_| ErrorKind::InvalidInput)? + .serialize(writer)?; for item in vec { item.serialize(writer)?; } @@ -303,7 +307,9 @@ where // NOTE: BTreeMap iterates over the entries that are sorted by key, so the serialization // result will be consistent without a need to sort the entries as we do for HashMap // serialization. - u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidInput)?.serialize(writer)?; + u32::try_from(self.len()) + .map_err(|_| ErrorKind::InvalidInput)? + .serialize(writer)?; for (key, value) in self { key.serialize(writer)?; value.serialize(writer)?; @@ -320,7 +326,9 @@ where fn serialize(&self, writer: &mut W) -> Result<()> { // NOTE: BTreeSet iterates over the items that are sorted, so the serialization result will // be consistent without a need to sort the entries as we do for HashSet serialization. - u32::try_from(self.len()).map_err(|_| ErrorKind::InvalidInput)?.serialize(writer)?; + u32::try_from(self.len()) + .map_err(|_| ErrorKind::InvalidInput)? + .serialize(writer)?; for item in self { item.serialize(writer)?; } From c83da1b4254aafe4f2cdd30509b5359a15f9251e Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Mon, 25 Jan 2021 11:00:54 -0800 Subject: [PATCH 4/5] better wording --- borsh/src/de/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/borsh/src/de/mod.rs b/borsh/src/de/mod.rs index 264a89d06..bf9ee3bf4 100644 --- a/borsh/src/de/mod.rs +++ b/borsh/src/de/mod.rs @@ -18,7 +18,7 @@ mod hint; const ERROR_NOT_ALL_BYTES_READ: &str = "Not all bytes read"; const ERROR_UNEXPECTED_LENGTH_OF_INPUT: &str = "Unexpected length of input"; -const ERROR_USIZE_OVERFLOW_IN_32_BIT_MACHINE: &str = "Deserialize usize overflow in 32 bit machine"; +const ERROR_OVERFLOW_ON_MACHINE_WITH_32_BIT_USIZE: &str = "Overflow on machine with 32 bit usize"; /// A data-structure that can be de-serialized from binary format by NBOR. pub trait BorshDeserialize: Sized { From 89d91c4c38d416252f073f82ca1b7b9c1d68d527 Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Mon, 25 Jan 2021 12:59:34 -0800 Subject: [PATCH 5/5] typo --- borsh/src/de/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/borsh/src/de/mod.rs b/borsh/src/de/mod.rs index bf9ee3bf4..10e07f67a 100644 --- a/borsh/src/de/mod.rs +++ b/borsh/src/de/mod.rs @@ -102,7 +102,7 @@ impl BorshDeserialize for usize { let u = usize::try_from(u).map_err(|_| { Error::new( ErrorKind::InvalidInput, - ERROR_USIZE_OVERFLOW_IN_32_BIT_MACHINE, + ERROR_OVERFLOW_ON_MACHINE_WITH_32_BIT_USIZE, ) })?; Ok(u)