diff options
| author | Sebastian Geisler <sebastian@blockstream.io> | 2018-10-30 22:24:33 -0700 |
|---|---|---|
| committer | Sebastian Geisler <sebastian@blockstream.io> | 2018-11-15 22:55:24 -0800 |
| commit | 6d40b7232eaa00ab5c060582011f350725703a1e (patch) | |
| tree | f2e1c25c92d32bb635a8df1792e96c32cec199bb /src/libstd/sys/unix | |
| parent | e8aef7cae14bc7a56859408c90253e9bcc07fcff (diff) | |
| download | rust-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.rs | 29 |
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) } } |
