about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/miri/src/clock.rs25
-rw-r--r--src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs16
2 files changed, 34 insertions, 7 deletions
diff --git a/src/tools/miri/src/clock.rs b/src/tools/miri/src/clock.rs
index fd0c121626b..c18e1bc7a9e 100644
--- a/src/tools/miri/src/clock.rs
+++ b/src/tools/miri/src/clock.rs
@@ -6,7 +6,7 @@ use std::time::{Duration, Instant as StdInstant};
 /// This number is pretty random, but it has been shown to approximately cause
 /// some sample programs to run within an order of magnitude of real time on desktop CPUs.
 /// (See `tests/pass/shims/time-with-isolation*.rs`.)
-const NANOSECONDS_PER_BASIC_BLOCK: u64 = 5000;
+const NANOSECONDS_PER_BASIC_BLOCK: u128 = 5000;
 
 #[derive(Debug)]
 pub struct Instant {
@@ -16,7 +16,7 @@ pub struct Instant {
 #[derive(Debug)]
 enum InstantKind {
     Host(StdInstant),
-    Virtual { nanoseconds: u64 },
+    Virtual { nanoseconds: u128 },
 }
 
 impl Instant {
@@ -25,9 +25,8 @@ impl Instant {
             InstantKind::Host(instant) =>
                 instant.checked_add(duration).map(|i| Instant { kind: InstantKind::Host(i) }),
             InstantKind::Virtual { nanoseconds } =>
-                u128::from(nanoseconds)
+                nanoseconds
                     .checked_add(duration.as_nanos())
-                    .and_then(|n| u64::try_from(n).ok())
                     .map(|nanoseconds| Instant { kind: InstantKind::Virtual { nanoseconds } }),
         }
     }
@@ -39,7 +38,19 @@ impl Instant {
             (
                 InstantKind::Virtual { nanoseconds },
                 InstantKind::Virtual { nanoseconds: earlier },
-            ) => Duration::from_nanos(nanoseconds.saturating_sub(earlier)),
+            ) => {
+                // Trade some nanosecond precision to prevent as much overflow as possible.
+                let duration = match u64::try_from(
+                    // Manually convert from nanosecond to millisecond.
+                    // If it exceeded u64::MAX millisecond, we will just use u64::MAX millisecond,
+                    // Duration can't take in more than u64::MAX millisecond.
+                    nanoseconds.saturating_sub(earlier).saturating_div(1_000_000),
+                ) {
+                    Ok(millisecond) => Duration::from_millis(millisecond),
+                    _ => Duration::from_millis(u64::MAX),
+                };
+                Duration::new(duration.as_secs(), duration.subsec_nanos())
+            }
             _ => panic!("all `Instant` must be of the same kind"),
         }
     }
@@ -59,7 +70,7 @@ enum ClockKind {
     },
     Virtual {
         /// The "current virtual time".
-        nanoseconds: Cell<u64>,
+        nanoseconds: Cell<u128>,
     },
 }
 
@@ -93,7 +104,7 @@ impl Clock {
             ClockKind::Host { .. } => std::thread::sleep(duration),
             ClockKind::Virtual { nanoseconds } => {
                 // Just pretend that we have slept for some time.
-                let nanos: u64 = duration.as_nanos().try_into().unwrap();
+                let nanos: u128 = duration.as_nanos().try_into().unwrap();
                 nanoseconds.update(|x| x + nanos);
             }
         }
diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
index d21f953672d..59319b93748 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs
@@ -280,7 +280,23 @@ fn concurrent_wait_wake() {
     assert!(woken > 0 && woken < rounds);
 }
 
+// Reproduce of https://github.com/rust-lang/miri/issues/3647.
+fn large_timeout() {
+    let futex: i32 = 123;
+
+    unsafe {
+        libc::syscall(
+            libc::SYS_futex,
+            addr_of!(futex),
+            libc::FUTEX_WAIT,
+            123,
+            &libc::timespec { tv_sec: 184467440839020, tv_nsec: 117558982 },
+        );
+    }
+}
+
 fn main() {
+    large_timeout();
     wake_nobody();
     wake_dangling();
     wait_wrong_val();