diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 9e3ec441..5b62d9e5 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -206,7 +206,7 @@ fn decode_bson(reader: &mut R, tag: u8, utf8_lossy: bool) -> D // The int64 is UTC milliseconds since the Unix epoch. let time = read_i64(reader)?; - match Utc.timestamp_opt(time / 1000, ((time % 1000) as u32).saturating_mul(1_000_000)) { + match Utc.timestamp_opt(time / 1000, ((time % 1000) as u32) * 1_000_000) { LocalResult::None => Err(DecoderError::InvalidTimestamp(time)), LocalResult::Ambiguous(..) => Err(DecoderError::AmbiguousTimestamp(time)), LocalResult::Single(t) => Ok(Bson::UtcDatetime(t)), diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index 83589a7c..b7c0673a 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -130,7 +130,7 @@ fn encode_bson(writer: &mut W, key: &str, val: &Bson) -> Enco writer.write_u8(From::from(subtype))?; writer.write_all(data).map_err(From::from) } - &Bson::UtcDatetime(ref v) => write_i64(writer, (v.timestamp() * 1000) + (v.nanosecond() / 1000000) as i64), + &Bson::UtcDatetime(ref v) => write_i64(writer, (v.timestamp() * 1000) + (v.nanosecond() / 1_000_000) as i64), &Bson::Null => Ok(()), &Bson::Symbol(ref v) => write_string(writer, &v), } diff --git a/tests/lib.rs b/tests/lib.rs index 0459225a..7d1f2b15 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,5 +1,6 @@ #[macro_use(bson, doc)] extern crate bson; +extern crate byteorder; extern crate chrono; extern crate hex; diff --git a/tests/modules/encoder_decoder.rs b/tests/modules/encoder_decoder.rs index 076d1177..b11c9e9e 100644 --- a/tests/modules/encoder_decoder.rs +++ b/tests/modules/encoder_decoder.rs @@ -1,9 +1,10 @@ -use bson::{decode_document, encode_document, Bson, decode_document_utf8_lossy}; use bson::oid::ObjectId; use bson::spec::BinarySubtype; -use chrono::Utc; +use bson::{decode_document, decode_document_utf8_lossy, encode_document, Bson}; +use byteorder::{LittleEndian, WriteBytesExt}; use chrono::offset::TimeZone; -use std::io::Cursor; +use chrono::Utc; +use std::io::{Cursor, Write}; #[test] fn test_encode_decode_floating_point() { @@ -277,3 +278,21 @@ fn test_encode_decode_symbol() { let decoded = decode_document(&mut Cursor::new(buf)).unwrap(); assert_eq!(decoded, doc); } + +#[test] +fn test_decode_utc_date_time_overflows() { + let t = 1530492218 * 1_000 + 999; + + let mut raw0 = vec![0x09, b'A', 0x00]; + raw0.write_i64::(t).unwrap(); + + let mut raw = vec![]; + raw.write_i32::((raw0.len() + 4 + 1) as i32).unwrap(); + raw.write_all(&raw0).unwrap(); + raw.write_u8(0).unwrap(); + + let decoded = decode_document(&mut Cursor::new(raw)).unwrap(); + + let expected = doc! { "A" => Utc.timestamp(1530492218, 999 * 1_000_000)}; + assert_eq!(decoded, expected); +}