+ 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)
+ })
+ }
+
+ fn read_c_str<'a>(&'a self, sptr: Scalar<Tag>) -> InterpResult<'tcx, &'a [u8]>
+ where
+ 'tcx: 'a,
+ 'mir: 'a,
+ {
+ let this = self.eval_context_ref();
+ let size1 = Size::from_bytes(1);
+ let ptr = this.force_ptr(sptr)?; // We need to read at least 1 byte, so we can eagerly get a ptr.
+
+ // Step 1: determine the length.
+ let mut len = Size::ZERO;
+ loop {
+ // FIXME: We are re-getting the allocation each time around the loop.
+ // Would be nice if we could somehow "extend" an existing AllocRange.
+ let alloc = this.memory.get(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result
+ let byte = alloc.read_scalar(alloc_range(Size::ZERO, size1))?.to_u8()?;
+ if byte == 0 {
+ break;
+ } else {
+ len = len + size1;
+ }
+ }
+
+ // Step 2: get the bytes.
+ this.memory.read_bytes(ptr.into(), len)
+ }
+
+ fn read_wide_str(&self, sptr: Scalar<Tag>) -> InterpResult<'tcx, Vec<u16>> {
+ let this = self.eval_context_ref();
+ let size2 = Size::from_bytes(2);
+ let align2 = Align::from_bytes(2).unwrap();
+
+ let mut ptr = this.force_ptr(sptr)?; // We need to read at least 1 wchar, so we can eagerly get a ptr.
+ let mut wchars = Vec::new();
+ loop {
+ // FIXME: We are re-getting the allocation each time around the loop.
+ // Would be nice if we could somehow "extend" an existing AllocRange.
+ let alloc = this.memory.get(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result
+ let wchar = alloc.read_scalar(alloc_range(Size::ZERO, size2))?.to_u16()?;
+ if wchar == 0 {
+ break;
+ } else {
+ wchars.push(wchar);
+ ptr = ptr.offset(size2, this)?;
+ }
+ }
+
+ Ok(wchars)
+ }
+
+ /// Check that the ABI is what we expect.
+ fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
+ if self.eval_context_ref().machine.enforce_abi && abi != exp_abi {
+ throw_ub_format!(
+ "calling a function with ABI {} using caller ABI {}",
+ exp_abi.name(),
+ abi.name()
+ )
+ }
+ Ok(())
+ }
+
+ fn in_std(&self) -> bool {
+ let this = self.eval_context_ref();
+ this.tcx.def_path(this.frame().instance.def_id()).krate
+ == this.tcx.def_path(this.tcx.lang_items().start_fn().unwrap()).krate