diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs index fd77ddf1f..7f0b5d907 100644 --- a/serde/src/de/impls.rs +++ b/serde/src/de/impls.rs @@ -1849,6 +1849,17 @@ impl<'de> Deserialize<'de> for Duration { } } + fn check_overflow(secs: u64, nanos: u32) -> Result<(), E> + where + E: Error, + { + static NANOS_PER_SEC: u32 = 1_000_000_000; + match secs.checked_add((nanos / NANOS_PER_SEC) as u64) { + Some(_) => Ok(()), + None => Err(E::custom("overflow deserializing Duration")), + } + } + struct DurationVisitor; impl<'de> Visitor<'de> for DurationVisitor { @@ -1874,6 +1885,7 @@ impl<'de> Deserialize<'de> for Duration { return Err(Error::invalid_length(1, &self)); } }; + try!(check_overflow(secs, nanos)); Ok(Duration::new(secs, nanos)) } @@ -1907,6 +1919,7 @@ impl<'de> Deserialize<'de> for Duration { Some(nanos) => nanos, None => return Err(::missing_field("nanos")), }; + try!(check_overflow(secs, nanos)); Ok(Duration::new(secs, nanos)) } } diff --git a/test_suite/tests/test_de.rs b/test_suite/tests/test_de.rs index 025d87b09..a0261bd35 100644 --- a/test_suite/tests/test_de.rs +++ b/test_suite/tests/test_de.rs @@ -1452,4 +1452,25 @@ declare_error_tests! { ], "invalid value: integer `65536`, expected u16", } + test_duration_overflow_seq { + &[ + Token::Seq { len: Some(2) }, + Token::U64(u64::max_value()), + Token::U32(1_000_000_000), + Token::SeqEnd, + ], + "overflow deserializing Duration", + } + test_duration_overflow_struct { + &[ + Token::Struct { name: "Duration", len: 2 }, + Token::Str("secs"), + Token::U64(u64::max_value()), + + Token::Str("nanos"), + Token::U32(1_000_000_000), + Token::StructEnd, + ], + "overflow deserializing Duration", + } }