From 8410ca663258423cd16b0741f7a053b320e13da0 Mon Sep 17 00:00:00 2001 From: kennytm Date: Fri, 1 Sep 2017 01:16:24 +0800 Subject: [PATCH 1/4] Properly detect overflow in Instance +/- Duration. Avoid unchecked cast from `u64` to `i64`. Use `try_into()` for checked cast. (On Unix, cast to `time_t` instead of `i64`.) --- src/libstd/sys/redox/time.rs | 22 +++++++++++++++------- src/libstd/sys/unix/time.rs | 22 +++++++++++++++------- src/libstd/sys/windows/time.rs | 9 ++++++--- src/test/run-fail/issue-44216-add.rs | 18 ++++++++++++++++++ src/test/run-fail/issue-44216-sub.rs | 18 ++++++++++++++++++ 5 files changed, 72 insertions(+), 17 deletions(-) create mode 100644 src/test/run-fail/issue-44216-add.rs create mode 100644 src/test/run-fail/issue-44216-sub.rs diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs index dea406efe6ca9..6c071afd42d05 100644 --- a/src/libstd/sys/redox/time.rs +++ b/src/libstd/sys/redox/time.rs @@ -12,6 +12,7 @@ use cmp::Ordering; use fmt; use sys::{cvt, syscall}; use time::Duration; +use convert::TryInto; const NSEC_PER_SEC: u64 = 1_000_000_000; @@ -40,8 +41,12 @@ impl Timespec { } fn add_duration(&self, other: &Duration) -> Timespec { - let secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64); - let mut secs = secs.expect("overflow when adding duration to time"); + let mut secs = other + .as_secs() + .try_into() // <- target type would be `i64` + .ok() + .and_then(|secs| self.t.tv_sec.checked_add(secs)) + .expect("overflow when adding duration to time"); // Nano calculations can't overflow because nanos are <1B which fit // in a u32. @@ -53,16 +58,19 @@ impl Timespec { } Timespec { t: syscall::TimeSpec { - tv_sec: secs as i64, + tv_sec: secs, tv_nsec: nsec as i32, }, } } fn sub_duration(&self, other: &Duration) -> Timespec { - let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64); - let mut secs = secs.expect("overflow when subtracting duration \ - from time"); + let mut secs = other + .as_secs() + .try_into() // <- target type would be `i64` + .ok() + .and_then(|secs| self.t.tv_sec.checked_sub(secs)) + .expect("overflow when subtracting duration from time"); // Similar to above, nanos can't overflow. let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; @@ -73,7 +81,7 @@ impl Timespec { } Timespec { t: syscall::TimeSpec { - tv_sec: secs as i64, + tv_sec: secs, tv_nsec: nsec as i32, }, } diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index a1ad94872de5c..c1bea95ce91ab 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -13,6 +13,7 @@ use libc; use time::Duration; pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; +use convert::TryInto; const NSEC_PER_SEC: u64 = 1_000_000_000; @@ -41,8 +42,12 @@ impl Timespec { } fn add_duration(&self, other: &Duration) -> Timespec { - let secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64); - let mut secs = secs.expect("overflow when adding duration to time"); + let mut secs = other + .as_secs() + .try_into() // <- target type would be `libc::time_t` + .ok() + .and_then(|secs| self.t.tv_sec.checked_add(secs)) + .expect("overflow when adding duration to time"); // Nano calculations can't overflow because nanos are <1B which fit // in a u32. @@ -54,16 +59,19 @@ impl Timespec { } Timespec { t: libc::timespec { - tv_sec: secs as libc::time_t, + tv_sec: secs, tv_nsec: nsec as libc::c_long, }, } } fn sub_duration(&self, other: &Duration) -> Timespec { - let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64); - let mut secs = secs.expect("overflow when subtracting duration \ - from time"); + let mut secs = other + .as_secs() + .try_into() // <- target type would be `libc::time_t` + .ok() + .and_then(|secs| self.t.tv_sec.checked_sub(secs)) + .expect("overflow when subtracting duration from time"); // Similar to above, nanos can't overflow. let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; @@ -74,7 +82,7 @@ impl Timespec { } Timespec { t: libc::timespec { - tv_sec: secs as libc::time_t, + tv_sec: secs, tv_nsec: nsec as libc::c_long, }, } diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index ef8ed606526da..1be29b5139a55 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -16,6 +16,7 @@ use sys::c; use sys::cvt; use sys_common::mul_div_u64; use time::Duration; +use convert::TryInto; const NANOS_PER_SEC: u64 = 1_000_000_000; const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100; @@ -173,9 +174,11 @@ impl From for SystemTime { } fn dur2intervals(d: &Duration) -> i64 { - d.as_secs().checked_mul(INTERVALS_PER_SEC).and_then(|i| { - i.checked_add(d.subsec_nanos() as u64 / 100) - }).expect("overflow when converting duration to intervals") as i64 + d.as_secs() + .checked_mul(INTERVALS_PER_SEC) + .and_then(|i| i.checked_add(d.subsec_nanos() as u64 / 100)) + .and_then(|i| i.try_into().ok()) + .expect("overflow when converting duration to intervals") } fn intervals2dur(intervals: u64) -> Duration { diff --git a/src/test/run-fail/issue-44216-add.rs b/src/test/run-fail/issue-44216-add.rs new file mode 100644 index 0000000000000..18bacd0459b2d --- /dev/null +++ b/src/test/run-fail/issue-44216-add.rs @@ -0,0 +1,18 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:overflow when + +use std::time::{Instant, Duration}; + +fn main() { + let now = Instant::now(); + let _ = now + Duration::from_secs(u64::max_value()); +} diff --git a/src/test/run-fail/issue-44216-sub.rs b/src/test/run-fail/issue-44216-sub.rs new file mode 100644 index 0000000000000..551401c51bbec --- /dev/null +++ b/src/test/run-fail/issue-44216-sub.rs @@ -0,0 +1,18 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:overflow when + +use std::time::{Instant, Duration}; + +fn main() { + let now = Instant::now(); + let _ = now - Duration::from_secs(u64::max_value()); +} From 756026563d82f8d339f7d66c4ca5f5974e210f82 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 3 Sep 2017 17:31:43 +0800 Subject: [PATCH 2/4] Fix incorrect test in `time::tests::system_time_math`. --- src/libstd/time/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs index e0dd8cfe62e6f..291def3e64661 100644 --- a/src/libstd/time/mod.rs +++ b/src/libstd/time/mod.rs @@ -509,7 +509,7 @@ mod tests { let dur = dur.duration(); assert!(a > b); assert_almost_eq!(b + dur, a); - assert_almost_eq!(b - dur, a); + assert_almost_eq!(a - dur, b); } } From 83d14bda7fe87b37b61904417cfb53f6351b5f3a Mon Sep 17 00:00:00 2001 From: kennytm Date: Thu, 7 Sep 2017 13:09:18 +0800 Subject: [PATCH 3/4] Disable the 80-year-difference test on 32-bit-time_t platforms. --- src/libstd/time/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs index 291def3e64661..d4993ded843dd 100644 --- a/src/libstd/time/mod.rs +++ b/src/libstd/time/mod.rs @@ -520,9 +520,12 @@ mod tests { assert_almost_eq!(a - second + second, a); - let eighty_years = second * 60 * 60 * 24 * 365 * 80; - assert_almost_eq!(a - eighty_years + eighty_years, a); - assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a); + // A difference of 80 and 800 years cannot fit inside a 32-bit time_t + if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) { + let eighty_years = second * 60 * 60 * 24 * 365 * 80; + assert_almost_eq!(a - eighty_years + eighty_years, a); + assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a); + } let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000) From 4962f9d72528602f70c7017d95063ef93a3c8967 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 10 Sep 2017 01:48:43 +0800 Subject: [PATCH 4/4] Relaxed error pattern, and add test for SystemTime as well. --- ...44216-add.rs => issue-44216-add-instant.rs} | 2 +- .../run-fail/issue-44216-add-system-time.rs | 18 ++++++++++++++++++ ...44216-sub.rs => issue-44216-sub-instant.rs} | 2 +- .../run-fail/issue-44216-sub-system-time.rs | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) rename src/test/run-fail/{issue-44216-add.rs => issue-44216-add-instant.rs} (95%) create mode 100644 src/test/run-fail/issue-44216-add-system-time.rs rename src/test/run-fail/{issue-44216-sub.rs => issue-44216-sub-instant.rs} (95%) create mode 100644 src/test/run-fail/issue-44216-sub-system-time.rs diff --git a/src/test/run-fail/issue-44216-add.rs b/src/test/run-fail/issue-44216-add-instant.rs similarity index 95% rename from src/test/run-fail/issue-44216-add.rs rename to src/test/run-fail/issue-44216-add-instant.rs index 18bacd0459b2d..e17d23d925a8b 100644 --- a/src/test/run-fail/issue-44216-add.rs +++ b/src/test/run-fail/issue-44216-add-instant.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:overflow when +// error-pattern:overflow use std::time::{Instant, Duration}; diff --git a/src/test/run-fail/issue-44216-add-system-time.rs b/src/test/run-fail/issue-44216-add-system-time.rs new file mode 100644 index 0000000000000..4a0c9c7d65e9e --- /dev/null +++ b/src/test/run-fail/issue-44216-add-system-time.rs @@ -0,0 +1,18 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:overflow + +use std::time::{Duration, SystemTime}; + +fn main() { + let now = SystemTime::now(); + let _ = now + Duration::from_secs(u64::max_value()); +} diff --git a/src/test/run-fail/issue-44216-sub.rs b/src/test/run-fail/issue-44216-sub-instant.rs similarity index 95% rename from src/test/run-fail/issue-44216-sub.rs rename to src/test/run-fail/issue-44216-sub-instant.rs index 551401c51bbec..6cc38cfec8319 100644 --- a/src/test/run-fail/issue-44216-sub.rs +++ b/src/test/run-fail/issue-44216-sub-instant.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:overflow when +// error-pattern:overflow use std::time::{Instant, Duration}; diff --git a/src/test/run-fail/issue-44216-sub-system-time.rs b/src/test/run-fail/issue-44216-sub-system-time.rs new file mode 100644 index 0000000000000..bcf60126f0f23 --- /dev/null +++ b/src/test/run-fail/issue-44216-sub-system-time.rs @@ -0,0 +1,18 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:overflow + +use std::time::{Duration, SystemTime}; + +fn main() { + let now = SystemTime::now(); + let _ = now - Duration::from_secs(u64::max_value()); +}