about summary refs log tree commit diff
path: root/src/libstd/sys/unix
diff options
context:
space:
mode:
authorSebastian Geisler <sebastian@blockstream.io>2018-10-30 22:24:33 -0700
committerSebastian Geisler <sebastian@blockstream.io>2018-11-15 22:55:24 -0800
commit6d40b7232eaa00ab5c060582011f350725703a1e (patch)
treef2e1c25c92d32bb635a8df1792e96c32cec199bb /src/libstd/sys/unix
parente8aef7cae14bc7a56859408c90253e9bcc07fcff (diff)
downloadrust-6d40b7232eaa00ab5c060582011f350725703a1e.tar.gz
rust-6d40b7232eaa00ab5c060582011f350725703a1e.zip
Implement checked_add_duration for SystemTime
Since SystemTime is opaque there is no way to check if the result
of an addition will be in bounds. That makes the Add<Duration>
trait completely unusable with untrusted data. This is a big problem
because adding a Duration to UNIX_EPOCH is the standard way of
constructing a SystemTime from a unix timestamp.

This commit implements checked_add_duration(&self, &Duration) -> Option<SystemTime>
for std::time::SystemTime and as a prerequisite also for all platform
specific time structs. This also led to the refactoring of many
add_duration(&self, &Duration) -> SystemTime functions to avoid
redundancy (they now unwrap the result of checked_add_duration).

Some basic unit tests for the newly introduced function were added
too.
Diffstat (limited to 'src/libstd/sys/unix')
-rw-r--r--src/libstd/sys/unix/time.rs29
1 files changed, 23 insertions, 6 deletions
diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs
index 0b1fb726357..50c3c00382e 100644
--- a/src/libstd/sys/unix/time.rs
+++ b/src/libstd/sys/unix/time.rs
@@ -43,27 +43,36 @@ impl Timespec {
     }
 
     fn add_duration(&self, other: &Duration) -> Timespec {
-        let mut secs = other
+        self.checked_add_duration(other).expect("overflow when adding duration to time")
+    }
+
+    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
+        let mut secs = match 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");
+        {
+            Some(ts) => ts,
+            None => return None,
+        };
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
         let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
         if nsec >= NSEC_PER_SEC as u32 {
             nsec -= NSEC_PER_SEC as u32;
-            secs = secs.checked_add(1).expect("overflow when adding \
-                                               duration to time");
+            secs = match secs.checked_add(1) {
+                Some(ts) => ts,
+                None => return None,
+            }
         }
-        Timespec {
+        Some(Timespec {
             t: libc::timespec {
                 tv_sec: secs,
                 tv_nsec: nsec as _,
             },
-        }
+        })
     }
 
     fn sub_duration(&self, other: &Duration) -> Timespec {
@@ -201,6 +210,10 @@ mod inner {
             SystemTime { t: self.t.add_duration(other) }
         }
 
+        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+            self.t.checked_add_duration(other).map(|t| SystemTime { t })
+        }
+
         pub fn sub_duration(&self, other: &Duration) -> SystemTime {
             SystemTime { t: self.t.sub_duration(other) }
         }
@@ -325,6 +338,10 @@ mod inner {
             SystemTime { t: self.t.add_duration(other) }
         }
 
+        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+            self.t.checked_add_duration(other).map(|t| SystemTime { t })
+        }
+
         pub fn sub_duration(&self, other: &Duration) -> SystemTime {
             SystemTime { t: self.t.sub_duration(other) }
         }