Fix overflow error when deserializing invalid Duration (#465)

* Fix overflow error when deserializing invalid Duration

* Use unwrap_err instead of match in test
This commit is contained in:
5225225 2022-01-08 21:54:04 +00:00 committed by GitHub
parent a08e528cc7
commit 236d350f13
3 changed files with 54 additions and 2 deletions

View File

@ -548,8 +548,12 @@ where
impl Decode for Duration {
fn decode<D: Decoder>(mut decoder: D) -> Result<Self, DecodeError> {
let secs = Decode::decode(&mut decoder)?;
let nanos = Decode::decode(&mut decoder)?;
const NANOS_PER_SEC: u64 = 1_000_000_000;
let secs: u64 = Decode::decode(&mut decoder)?;
let nanos: u32 = Decode::decode(&mut decoder)?;
if secs.checked_add(u64::from(nanos) / NANOS_PER_SEC).is_none() {
return Err(DecodeError::InvalidDuration { secs, nanos });
}
Ok(Duration::new(secs, nanos))
}
}

View File

@ -122,6 +122,16 @@ pub enum DecodeError {
type_name: &'static str,
},
/// The decoder tried to decode a Duration and overflowed the number of seconds.
InvalidDuration {
/// The number of seconds in the duration.
secs: u64,
/// The number of nanoseconds in the duration, which when converted to seconds and added to
/// `secs`, overflows a `u64`.
nanos: u32,
},
/// The decoder tried to decode a `CStr` or `CString`, but the incoming data contained a 0 byte
#[cfg(feature = "std")]
CStrNulError {

View File

@ -219,3 +219,41 @@ fn test_array() {
assert_eq!(input, output);
assert_eq!(len, 10);
}
#[test]
fn test_duration_out_of_range() {
let mut input = [0u8; 14];
bincode::encode_into_slice(&(u64::MAX, u32::MAX), &mut input, Configuration::standard())
.unwrap();
let result: Result<(std::time::Duration, usize), _> =
bincode::decode_from_slice(&mut input, Configuration::standard());
assert_eq!(
result.unwrap_err(),
bincode::error::DecodeError::InvalidDuration {
secs: u64::MAX,
nanos: u32::MAX
}
);
}
#[test]
fn test_duration_wrapping() {
let mut input = [0u8; 14];
bincode::encode_into_slice(
&(u64::MAX - 4, u32::MAX),
&mut input,
Configuration::standard(),
)
.unwrap();
let (result, _): (std::time::Duration, _) =
bincode::decode_from_slice(&mut input, Configuration::standard()).unwrap();
assert_eq!(result.as_secs(), u64::MAX);
assert_eq!(result.subsec_nanos(), 294967295);
}