Skip to content

Commit 5d472ae

Browse files
committed
time: Fix Windows' SystemTime::checked_sub
The Windows implementation of `SystemTime::checked_sub` contains a bug, namely that it does not return `None` on values below 1601. This bug stems from the fact that internally, the time gets converted to an i64, with zero representing the anchor in 1601. Of course, performing checked subtraction on a signed integer generally works fine. However, the resulting value delivers undefined behavior on Windows systems. To mitigate this issue, we immediately convert the i64 to an u64, on which subtraction resulting in values below zero will obviously fail.
1 parent ac5c70a commit 5d472ae

File tree

1 file changed

+8
-2
lines changed
  • library/std/src/sys/pal/windows

1 file changed

+8
-2
lines changed

library/std/src/sys/pal/windows/time.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use core::hash::{Hash, Hasher};
22
use core::ops::Neg;
33

4-
use crate::cmp::Ordering;
4+
use crate::cmp::{Ord, Ordering};
55
use crate::ptr::null;
66
use crate::sys::c;
77
use crate::sys_common::IntoInner;
@@ -111,7 +111,13 @@ impl SystemTime {
111111
}
112112

113113
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
114-
let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?;
114+
// Windows does not support times before 1601, hence why we don't
115+
// support negatives. In order to tackle this, we simply try to convert
116+
// the resulting i64 into an u64, returning None on failure, following
117+
// an ordinary call to u64::checked_sub_signed, which will then
118+
// obviously use zero as the lower bound.
119+
let intervals: u64 = self.intervals.try_into().ok()?;
120+
let intervals = intervals.checked_sub_signed(checked_dur2intervals(other)?)?;
115121
Some(SystemTime::from_intervals(intervals))
116122
}
117123
}

0 commit comments

Comments
 (0)