Skip to content

Commit

Permalink
Fix overflow error when deserializing invalid Duration
Browse files Browse the repository at this point in the history
  • Loading branch information
5225225 committed Jan 8, 2022
1 parent 4fea079 commit 1f5aa1a
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/de/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
41 changes: 41 additions & 0 deletions tests/basic_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,44 @@ 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());

match result {
Ok(d) => panic!("did not expect to deserialize {:?}", d),
Err(e) => assert_eq!(
e,
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);
}

0 comments on commit 1f5aa1a

Please sign in to comment.