]> git.lizzy.rs Git - rust.git/blob - src/shims/time.rs
Use places instead of ptrs to write packed immtys
[rust.git] / src / shims / time.rs
1 use std::time::{Duration, SystemTime};
2
3 use rustc::ty::layout::TyLayout;
4
5 use crate::stacked_borrows::Tag;
6 use crate::*;
7
8 // Returns the time elapsed between now and the unix epoch as a `Duration` and the sign of the time
9 // interval
10 fn get_time<'tcx>() -> InterpResult<'tcx, Duration> {
11     SystemTime::now()
12         .duration_since(SystemTime::UNIX_EPOCH)
13         .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into())
14 }
15
16 fn int_to_immty_checked<'tcx>(
17     int: i128,
18     layout: TyLayout<'tcx>,
19 ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> {
20     // If `int` does not fit in `size` bits, we error instead of letting
21     // `ImmTy::from_int` panic.
22     let size = layout.size;
23     let truncated = truncate(int as u128, size);
24     if sign_extend(truncated, size) as i128 != int {
25         throw_unsup_format!(
26             "Signed value {:#x} does not fit in {} bits",
27             int,
28             size.bits()
29         )
30     }
31     Ok(ImmTy::from_int(int, layout))
32 }
33
34 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
35 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
36     // Foreign function used by linux
37     fn clock_gettime(
38         &mut self,
39         clk_id_op: OpTy<'tcx, Tag>,
40         tp_op: OpTy<'tcx, Tag>,
41     ) -> InterpResult<'tcx, i32> {
42         let this = self.eval_context_mut();
43
44         if !this.machine.communicate {
45             throw_unsup_format!("`clock_gettime` not available when isolation is enabled")
46         }
47
48         let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
49         if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? {
50             let einval = this.eval_libc("EINVAL")?;
51             this.set_last_error(einval)?;
52             return Ok(-1);
53         }
54
55         let tp = this.deref_operand(tp_op)?;
56
57         let duration = get_time()?;
58         let tv_sec = duration.as_secs() as i128;
59         let tv_nsec = duration.subsec_nanos() as i128;
60
61         let imms = [
62             int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
63             int_to_immty_checked(tv_nsec, this.libc_ty_layout("c_long")?)?,
64         ];
65
66         this.write_packed_immediates(&tp, &imms)?;
67
68         Ok(0)
69     }
70     // Foreign function used by generic unix (in particular macOS)
71     fn gettimeofday(
72         &mut self,
73         tv_op: OpTy<'tcx, Tag>,
74         tz_op: OpTy<'tcx, Tag>,
75     ) -> InterpResult<'tcx, i32> {
76         let this = self.eval_context_mut();
77
78         if !this.machine.communicate {
79             throw_unsup_format!("`gettimeofday` not available when isolation is enabled")
80         }
81         // Using tz is obsolete and should always be null
82         let tz = this.read_scalar(tz_op)?.not_undef()?;
83         if !this.is_null(tz)? {
84             let einval = this.eval_libc("EINVAL")?;
85             this.set_last_error(einval)?;
86             return Ok(-1);
87         }
88
89         let tv = this.deref_operand(tv_op)?;
90
91         let duration = get_time()?;
92         let tv_sec = duration.as_secs() as i128;
93         let tv_usec = duration.subsec_micros() as i128;
94
95         let imms = [
96             int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
97             int_to_immty_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?,
98         ];
99
100         this.write_packed_immediates(&tv, &imms)?;
101
102         Ok(0)
103     }
104 }