})
}
-/// This error indicates that the value in a `timespec` C struct was invalid.
-pub struct TimespecError;
-
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
/// Gets an instance for a path.
fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> {
this.write_scalar(value, value_place.into())
}
- /// Parse a `timespec` struct and return it as a `std::time::Duration`. The outer `Result` is
- /// for interpreter errors encountered while reading memory, and the inner `Result` indicates
- /// whether the value in the `timespec` struct is invalid. Some libc functions will return
- /// `EINVAL` if the struct's value is invalid.
+ /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None`
+ /// if the value in the `timespec` struct is invalid. Some libc functions will return
+ /// `EINVAL` in this case.
fn read_timespec(
&mut self,
timespec_ptr_op: OpTy<'tcx, Tag>,
- ) -> InterpResult<'tcx, Result<Duration, TimespecError>> {
+ ) -> InterpResult<'tcx, Option<Duration>> {
let this = self.eval_context_mut();
let tp = this.deref_operand(timespec_ptr_op)?;
let seconds_place = this.mplace_field(tp, 0)?;
let seconds: u64 = if let Ok(s) = seconds.try_into() {
s
} else {
- return Ok(Err(TimespecError));
+ // tv_sec must be non-negative.
+ return Ok(None);
};
let nanoseconds: u32 = if let Ok(ns) = nanoseconds.try_into() {
if ns >= 1_000_000_000 {
- return Ok(Err(TimespecError));
+ // tv_nsec must not be greater than 999,999,999.
+ return Ok(None);
}
ns
} else {
- return Ok(Err(TimespecError));
+ // tv_nsec must be non-negative.
+ return Ok(None);
};
- Ok(Ok(Duration::new(seconds, nanoseconds)))
+ Ok(Some(Duration::new(seconds, nanoseconds)))
}
}
use std::time::SystemTime;
use crate::*;
-use helpers::TimespecError;
use stacked_borrows::Tag;
use thread::Time;
// Extract the timeout.
let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?;
let duration = match this.read_timespec(abstime_op)? {
- Ok(duration) => duration,
- Err(TimespecError) => {
+ Some(duration) => duration,
+ None => {
let einval = this.eval_libc("EINVAL")?;
this.write_scalar(einval, dest)?;
return Ok(());
use crate::stacked_borrows::Tag;
use crate::*;
-use helpers::{immty_from_int_checked, immty_from_uint_checked, TimespecError};
+use helpers::{immty_from_int_checked, immty_from_uint_checked};
use thread::Time;
/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
this.check_no_isolation("nanosleep")?;
let duration = match this.read_timespec(req_op)? {
- Ok(duration) => duration,
- Err(TimespecError) => {
+ Some(duration) => duration,
+ None => {
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
return Ok(-1);
}
};
- let timeout_time = Time::RealTime(SystemTime::now().checked_add(duration).unwrap());
+ let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap());
let active_thread = this.get_active_thread();
this.block_thread(active_thread);
let elapsed_time = current_time.elapsed().as_millis();
assert!(900 <= elapsed_time && elapsed_time <= 1300);
+ // Test that invalid nanosecond values (above 10^9 or negative) are rejected with the
+ // correct error code.
let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 };
assert_eq!(
libc::pthread_cond_timedwait(
),
libc::EINVAL
);
+ // Test that invalid second values (negative) are rejected with the correct error code.
+ let invalid_timeout_3 = libc::timespec { tv_sec: -1, tv_nsec: 0 };
+ assert_eq!(
+ libc::pthread_cond_timedwait(
+ &mut cond as *mut _,
+ &mut mutex as *mut _,
+ &invalid_timeout_3
+ ),
+ libc::EINVAL
+ );
assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
assert!(diff.as_millis() < 500);
}
+// Thus far, only `libc::nanosleep`, is implemented, not `c::Sleep`.
#[cfg(unix)]
fn test_sleep() {
let before = Instant::now();