+
+ fn read_scalar_at_offset(
+ &self,
+ op: OpTy<'tcx, Tag>,
+ offset: u64,
+ layout: TyAndLayout<'tcx>,
+ ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+ let this = self.eval_context_ref();
+ let op_place = this.deref_operand(op)?;
+ let offset = Size::from_bytes(offset);
+ // Ensure that the following read at an offset is within bounds
+ assert!(op_place.layout.size >= offset + layout.size);
+ let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?;
+ this.read_scalar(value_place.into())
+ }
+
+ fn write_scalar_at_offset(
+ &mut self,
+ op: OpTy<'tcx, Tag>,
+ offset: u64,
+ value: impl Into<ScalarMaybeUninit<Tag>>,
+ layout: TyAndLayout<'tcx>,
+ ) -> InterpResult<'tcx, ()> {
+ let this = self.eval_context_mut();
+ let op_place = this.deref_operand(op)?;
+ let offset = Size::from_bytes(offset);
+ // Ensure that the following read at an offset is within bounds
+ assert!(op_place.layout.size >= offset + layout.size);
+ let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?;
+ this.write_scalar(value, value_place.into())
+ }
+
+ /// 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, 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_scalar = this.read_scalar(seconds_place.into())?;
+ let seconds = seconds_scalar.to_machine_isize(this)?;
+ let nanoseconds_place = this.mplace_field(tp, 1)?;
+ let nanoseconds_scalar = this.read_scalar(nanoseconds_place.into())?;
+ let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?;
+
+ Ok(try {
+ // tv_sec must be non-negative.
+ let seconds: u64 = seconds.try_into().ok()?;
+ // tv_nsec must be non-negative.
+ let nanoseconds: u32 = nanoseconds.try_into().ok()?;
+ if nanoseconds >= 1_000_000_000 {
+ // tv_nsec must not be greater than 999,999,999.
+ None?
+ }
+ Duration::new(seconds, nanoseconds)
+ })
+ }
+}
+
+/// Check that the number of args is what we expect.
+pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]>
+ where &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]> {
+ if let Ok(ops) = args.try_into() {
+ return Ok(ops);
+ }
+ throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N)
+}
+
+pub fn isolation_error(name: &str) -> InterpResult<'static> {
+ throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
+ "{} not available when isolation is enabled",
+ name,
+ )))