diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index 89a427ab88ba9..978bd45114e1a 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -28,7 +28,7 @@ impl Timespec { #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] const fn sub_timespec(&self, other: &Timespec) -> Result { // FIXME: const PartialOrd - let mut cmp = self.t.tv_sec - other.t.tv_sec; + let mut cmp = self.t.tv_sec.saturating_sub(other.t.tv_sec); if cmp == 0 { cmp = self.t.tv_nsec as i64 - other.t.tv_nsec as i64; } @@ -36,12 +36,12 @@ impl Timespec { if cmp >= 0 { Ok(if self.t.tv_nsec >= other.t.tv_nsec { Duration::new( - (self.t.tv_sec - other.t.tv_sec) as u64, + self.t.tv_sec.wrapping_sub(other.t.tv_sec) as u64, (self.t.tv_nsec - other.t.tv_nsec) as u32, ) } else { Duration::new( - (self.t.tv_sec - 1 - other.t.tv_sec) as u64, + self.t.tv_sec.wrapping_sub(other.t.tv_sec) as u64 - 1_u64, (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32, ) }) diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index 36ce3f7ef962e..91dcc2211aa9e 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -95,7 +95,7 @@ impl SystemTime { // Check if can be represented in UEFI // FIXME: const PartialOrd - let mut cmp = temp.as_secs() - MAX_UEFI_TIME.0.as_secs(); + let mut cmp = temp.as_secs().saturating_sub(MAX_UEFI_TIME.0.as_secs()); if cmp == 0 { cmp = temp.subsec_nanos() as u64 - MAX_UEFI_TIME.0.subsec_nanos() as u64; } diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 328fe0bc9603f..6956deca6d35e 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -139,7 +139,7 @@ impl Timespec { #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] pub const fn sub_timespec(&self, other: &Timespec) -> Result { // FIXME: const PartialOrd - let mut cmp = self.tv_sec - other.tv_sec; + let mut cmp = self.tv_sec.saturating_sub(other.tv_sec); if cmp == 0 { cmp = self.tv_nsec.as_inner() as i64 - other.tv_nsec.as_inner() as i64; } @@ -160,12 +160,12 @@ impl Timespec { // directly expresses the lower-cost behavior we want from it. let (secs, nsec) = if self.tv_nsec.as_inner() >= other.tv_nsec.as_inner() { ( - (self.tv_sec - other.tv_sec) as u64, + self.tv_sec.wrapping_sub(other.tv_sec) as u64, self.tv_nsec.as_inner() - other.tv_nsec.as_inner(), ) } else { ( - (self.tv_sec - other.tv_sec - 1) as u64, + self.tv_sec.wrapping_sub(other.tv_sec) as u64 - 1_u64, self.tv_nsec.as_inner() + (NSEC_PER_SEC as u32) - other.tv_nsec.as_inner(), ) }; diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index 40709eae37cfc..e8aee25f6de43 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -227,3 +227,29 @@ fn big_math() { check(instant.checked_add(Duration::from_secs(100)), Instant::checked_sub); check(instant.checked_add(Duration::from_secs(i64::MAX as _)), Instant::checked_sub); } + +#[test] +#[cfg(unix)] +fn system_time_extreme_values_regression() { + // Test for regression in SystemTime comparison with extreme values + // This test covers the bug introduced in PR #144519 where integer overflow + // in the comparison logic caused incorrect results when dealing with times + // near i64::MIN and i64::MAX. + // + // This is the exact test case from GitHub issue #146228 + let t = SystemTime::UNIX_EPOCH; + let early = t - (Duration::from_secs(i64::MAX as u64 + 1)); + let later = t + (Duration::from_secs(i64::MAX as u64) + Duration::from_nanos(999_999_999)); + + // This should succeed and not return a SystemTimeError due to incorrect comparison overflow + let delta = + later.duration_since(early).expect("duration_since should work with extreme values"); + + // Verify that the delta calculation is reasonable + // early is at approximately -i64::MAX-1 seconds from epoch + // later is at approximately i64::MAX seconds + 999_999_999 nanoseconds from epoch + // So delta should be approximately (i64::MAX + i64::MAX + 1) seconds + 999_999_999 nanoseconds + let expected_secs = (i64::MAX as u64) * 2 + 1; + let expected = Duration::new(expected_secs, 999_999_999); + assert_eq!(delta, expected, "Duration calculation should be correct for extreme values"); +}