]> git.lizzy.rs Git - rust.git/commitdiff
Properly detect overflow in Instance +/- Duration.
authorkennytm <kennytm@gmail.com>
Thu, 31 Aug 2017 17:16:24 +0000 (01:16 +0800)
committerkennytm <kennytm@gmail.com>
Thu, 7 Sep 2017 09:14:27 +0000 (17:14 +0800)
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
src/libstd/sys/unix/time.rs
src/libstd/sys/windows/time.rs
src/test/run-fail/issue-44216-add.rs [new file with mode: 0644]
src/test/run-fail/issue-44216-sub.rs [new file with mode: 0644]

index dea406efe6ca963d9788c01114fd81c053de0c21..6c071afd42d05a142108ee598f263e2d367abedf 100644 (file)
@@ -12,6 +12,7 @@
 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 @@ fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
     }
 
     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 @@ fn add_duration(&self, other: &Duration) -> 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 @@ fn sub_duration(&self, other: &Duration) -> Timespec {
         }
         Timespec {
             t: syscall::TimeSpec {
-                tv_sec: secs as i64,
+                tv_sec: secs,
                 tv_nsec: nsec as i32,
             },
         }
index a1ad94872de5c1ae366dee9d9fe84c1eeaf89259..c1bea95ce91abb0135ab2507f0807f19dbb92597 100644 (file)
@@ -13,6 +13,7 @@
 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 @@ fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
     }
 
     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 @@ fn add_duration(&self, other: &Duration) -> 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 @@ fn sub_duration(&self, other: &Duration) -> Timespec {
         }
         Timespec {
             t: libc::timespec {
-                tv_sec: secs as libc::time_t,
+                tv_sec: secs,
                 tv_nsec: nsec as libc::c_long,
             },
         }
index ef8ed606526da30ca0a784b4815a4340bf32ffa6..1be29b5139a557145ca14b7f5dd771cb3476fa41 100644 (file)
@@ -16,6 +16,7 @@
 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 @@ fn from(t: c::FILETIME) -> 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 (file)
index 0000000..18bacd0
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 (file)
index 0000000..551401c
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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());
+}