• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /// Test that `Timespec` and `Secs` support a 64-bit number of seconds,
2 /// avoiding the y2038 bug.
3 ///
4 /// The Rust Musl target and libc crate are currently using Musl 1.1. It is
5 /// expected to update to Musl 1.2 at some point, at which point it'll gain a
6 /// 64-bit `time_t`.
7 ///
8 /// 32-bit Android is [not y2038 compatible]. In theory we could use
9 /// `libc::syscall` and call the new syscalls ourselves, however that doesn't
10 /// seem worth the effort on a platform that will likely never support add
11 /// such support itself.
12 ///
13 /// [not y2038 compatible]: https://android.googlesource.com/platform/bionic/+/refs/heads/master/docs/32-bit-abi.md#is-32_bit-on-lp32-y2038
14 #[cfg(not(all(target_env = "musl", target_pointer_width = "32")))]
15 #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
16 #[cfg(not(all(target_os = "emscripten", target_pointer_width = "32")))]
17 #[cfg(not(all(target_os = "linux", target_arch = "sparc")))]
18 #[test]
test_y2038()19 fn test_y2038() {
20     use rustix::time::{Secs, Timespec};
21 
22     let tv_sec: i64 = 0;
23     let _ = Timespec { tv_sec, tv_nsec: 0 };
24     let _: Secs = tv_sec;
25 
26     #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
27     {
28         use rustix::time::Itimerspec;
29 
30         let _ = Itimerspec {
31             it_interval: Timespec { tv_sec, tv_nsec: 0 },
32             it_value: Timespec { tv_sec, tv_nsec: 0 },
33         };
34     }
35 }
36 
37 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
38 #[test]
test_y2038_with_timerfd()39 fn test_y2038_with_timerfd() {
40     use rustix::time::{
41         timerfd_create, timerfd_gettime, timerfd_settime, Itimerspec, TimerfdClockId, TimerfdFlags,
42         TimerfdTimerFlags, Timespec,
43     };
44 
45     let fd = timerfd_create(TimerfdClockId::Monotonic, TimerfdFlags::CLOEXEC).unwrap();
46 
47     let set = Itimerspec {
48         it_interval: Timespec {
49             tv_sec: (1_u64 << 32) as _,
50             tv_nsec: 20,
51         },
52         it_value: Timespec {
53             tv_sec: (1_u64 << 32) as _,
54             tv_nsec: 21,
55         },
56     };
57     let _old: Itimerspec = match timerfd_settime(&fd, TimerfdTimerFlags::ABSTIME, &set) {
58         Ok(i) => i,
59 
60         // On 32-bit and mips64 platforms, accept `EOVERFLOW`, meaning that
61         // y2038 support in `timerfd` APIs is not available on this platform
62         // or this version of the platform.
63         #[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
64         Err(rustix::io::Errno::OVERFLOW) => return,
65 
66         Err(err) => panic!("unexpected error: {:?}", err),
67     };
68 
69     let new = timerfd_gettime(&fd).unwrap();
70 
71     // The timer counts down.
72     assert_eq!(set.it_interval.tv_sec, new.it_interval.tv_sec);
73     assert_eq!(set.it_interval.tv_nsec, new.it_interval.tv_nsec);
74     assert!(new.it_value.tv_sec <= set.it_value.tv_sec);
75     assert!(
76         new.it_value.tv_nsec < set.it_value.tv_nsec || new.it_value.tv_sec < set.it_value.tv_sec
77     );
78 }
79