]> git.lizzy.rs Git - rust.git/blob - src/shims/time.rs
Fix sign when number of seconds is zero
[rust.git] / src / shims / time.rs
1 use crate::stacked_borrows::Tag;
2 use crate::*;
3
4 use std::time::{Duration, SystemTime};
5
6 fn get_time() -> (Duration, i128) {
7     let mut sign = 1;
8     let duration = SystemTime::now()
9         .duration_since(SystemTime::UNIX_EPOCH)
10         .unwrap_or_else(|e| {
11             sign = -1;
12             e.duration()
13         });
14     (duration, sign)
15 }
16
17 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
18 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
19     // Foreign function used by linux
20     fn clock_gettime(
21         &mut self,
22         clk_id_op: OpTy<'tcx, Tag>,
23         tp_op: OpTy<'tcx, Tag>,
24     ) -> InterpResult<'tcx, i32> {
25         let this = self.eval_context_mut();
26
27         if !this.machine.communicate {
28             throw_unsup_format!("`clock_gettime` not available when isolation is enabled")
29         }
30
31         let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
32         if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? {
33             let einval = this.eval_libc("EINVAL")?;
34             this.set_last_error(einval)?;
35             return Ok(-1);
36         }
37
38         let tp = this.force_ptr(this.read_scalar(tp_op)?.not_undef()?)?;
39
40         let (duration, sign) = get_time();
41         let tv_sec = sign * (duration.as_secs() as i128);
42         let mut tv_nsec = duration.subsec_nanos() as i128;
43         // If the number of seconds is zero, we need to put the sign into the second's fraction.
44         if tv_sec == 0 && sign < 0 {
45             tv_nsec *= sign;
46         }
47
48         this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?;
49
50         Ok(0)
51     }
52     // Foreign function used by generic unix
53     fn gettimeofday(
54         &mut self,
55         tv_op: OpTy<'tcx, Tag>,
56         tz_op: OpTy<'tcx, Tag>,
57     ) -> InterpResult<'tcx, i32> {
58         let this = self.eval_context_mut();
59
60         if !this.machine.communicate {
61             throw_unsup_format!("`gettimeofday` not available when isolation is enabled")
62         }
63         // Using tz is obsolete and should always be null
64         let tz = this.read_scalar(tz_op)?.not_undef()?;
65         if !this.is_null(tz)? {
66             let einval = this.eval_libc("EINVAL")?;
67             this.set_last_error(einval)?;
68             return Ok(-1);
69         }
70
71         let tv = this.force_ptr(this.read_scalar(tv_op)?.not_undef()?)?;
72
73         let (duration, sign) = get_time();
74         let tv_sec = sign * (duration.as_secs() as i128);
75         let mut tv_usec = duration.subsec_micros() as i128;
76         // If the number of seconds is zero, we need to put the sign into the second's fraction.
77         if tv_sec == 0 && sign < 0 {
78             tv_usec *= sign;
79         }
80
81         this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?;
82
83         Ok(0)
84     }
85 }