Use Scalar consistently in foreign item emulation

This commit is contained in:
Oli Scherer 2024-07-30 13:18:16 +00:00
parent cf63c16269
commit 6fc1b69993
10 changed files with 239 additions and 245 deletions

View file

@ -93,7 +93,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(Scalar::from_i32(0))
}
fn gettimeofday(&mut self, tv_op: &OpTy<'tcx>, tz_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn gettimeofday(
&mut self,
tv_op: &OpTy<'tcx>,
tz_op: &OpTy<'tcx>,
) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
this.assert_target_os_is_unix("gettimeofday");
@ -106,7 +110,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if !this.ptr_is_null(tz)? {
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
let duration = system_time_to_duration(&SystemTime::now())?;
@ -115,7 +119,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &tv)?;
Ok(0)
Ok(Scalar::from_i32(0))
}
// The localtime() function shall convert the time in seconds since the Epoch pointed to by
@ -308,7 +312,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
&mut self,
req_op: &OpTy<'tcx>,
_rem: &OpTy<'tcx>, // Signal handlers are not supported, so rem will never be written to.
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
this.assert_target_os_is_unix("nanosleep");
@ -320,7 +324,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
None => {
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
};
@ -333,7 +337,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
@timeout = |_this| { Ok(()) }
),
);
Ok(0)
Ok(Scalar::from_i32(0))
}
#[allow(non_snake_case)]

View file

@ -148,7 +148,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(var_ptr.unwrap_or_else(Pointer::null))
}
fn setenv(&mut self, name_op: &OpTy<'tcx>, value_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn setenv(
&mut self,
name_op: &OpTy<'tcx>,
value_op: &OpTy<'tcx>,
) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
this.assert_target_os_is_unix("setenv");
@ -169,16 +173,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
}
this.update_environ()?;
Ok(0) // return zero on success
Ok(Scalar::from_i32(0)) // return zero on success
} else {
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
Ok(-1)
Ok(Scalar::from_i32(-1))
}
}
fn unsetenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn unsetenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
this.assert_target_os_is_unix("unsetenv");
@ -195,12 +199,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
}
this.update_environ()?;
Ok(0)
Ok(Scalar::from_i32(0))
} else {
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
Ok(-1)
Ok(Scalar::from_i32(-1))
}
}
@ -232,7 +236,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(Pointer::null())
}
fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
this.assert_target_os_is_unix("chdir");
@ -242,16 +246,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.reject_in_isolation("`chdir`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
match env::set_current_dir(path) {
Ok(()) => Ok(0),
Err(e) => {
this.set_last_error_from_io_error(e)?;
Ok(-1)
}
}
let result = env::set_current_dir(path).map(|()| 0);
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
}
/// Updates the `environ` static.
@ -270,18 +269,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(())
}
fn getpid(&mut self) -> InterpResult<'tcx, i32> {
fn getpid(&mut self) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
this.assert_target_os_is_unix("getpid");
// The reason we need to do this wacky of a conversion is because
// `libc::getpid` returns an i32, however, `std::process::id()` return an u32.
// So we un-do the conversion that stdlib does and turn it back into an i32.
#[allow(clippy::cast_possible_wrap)]
Ok(this.get_pid() as i32)
// In `Scalar` representation, these are the same, so we don't need to anything else.
Ok(Scalar::from_u32(this.get_pid()))
}
fn linux_gettid(&mut self) -> InterpResult<'tcx, i32> {
fn linux_gettid(&mut self) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_ref();
this.assert_target_os("linux", "gettid");
@ -290,7 +289,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Compute a TID for this thread, ensuring that the main thread has PID == TID.
let tid = this.get_pid().strict_add(index);
#[allow(clippy::cast_possible_wrap)]
Ok(tid as i32)
Ok(Scalar::from_u32(tid))
}
}

View file

@ -310,20 +310,20 @@ impl FdTable {
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, i32> {
fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
return this.fd_not_found();
return Ok(Scalar::from_i32(this.fd_not_found()?));
};
Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0))
Ok(Scalar::from_i32(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0)))
}
fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, i32> {
fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
return this.fd_not_found();
return Ok(Scalar::from_i32(this.fd_not_found()?));
};
if new_fd != old_fd {
// Close new_fd if it is previously opened.
@ -333,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
file_description.close(this.machine.communicate())?.ok();
}
}
Ok(new_fd)
Ok(Scalar::from_i32(new_fd))
}
fn flock(&mut self, fd: i32, op: i32) -> InterpResult<'tcx, Scalar> {
@ -370,7 +370,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
}
fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> {
fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
if args.len() < 2 {
@ -388,11 +388,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
// always sets this flag when opening a file. However we still need to check that the
// file itself is open.
if this.machine.fds.is_fd(fd) {
Ok(this.eval_libc_i32("FD_CLOEXEC"))
Ok(Scalar::from_i32(if this.machine.fds.is_fd(fd) {
this.eval_libc_i32("FD_CLOEXEC")
} else {
this.fd_not_found()
}
this.fd_not_found()?
}))
} else if cmd == this.eval_libc_i32("F_DUPFD")
|| cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")
{
@ -409,15 +409,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let start = this.read_scalar(&args[2])?.to_i32()?;
match this.machine.fds.dup(fd) {
Some(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, start)),
None => this.fd_not_found(),
Some(dup_fd) =>
Ok(Scalar::from_i32(this.machine.fds.insert_fd_with_min_fd(dup_fd, start))),
None => Ok(Scalar::from_i32(this.fd_not_found()?)),
}
} else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") {
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`fcntl`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
this.ffullsync_fd(fd)
@ -462,7 +463,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
buf: Pointer,
count: u64,
offset: Option<i128>,
) -> InterpResult<'tcx, i64> {
) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
// Isolation check is done via `FileDescriptor` trait.
@ -482,7 +483,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// We temporarily dup the FD to be able to retain mutable access to `this`.
let Some(fd) = this.machine.fds.dup(fd) else {
trace!("read: FD not found");
return this.fd_not_found();
return Ok(Scalar::from_target_isize(this.fd_not_found()?, this));
};
trace!("read: FD mapped to {fd:?}");
@ -496,7 +497,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let Ok(offset) = u64::try_from(offset) else {
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
return Ok(-1);
return Ok(Scalar::from_target_isize(-1, this));
};
fd.borrow_mut().pread(communicate, &mut bytes, offset, this)
}
@ -513,11 +514,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
buf,
bytes[..usize::try_from(read_bytes).unwrap()].iter().copied(),
)?;
Ok(read_bytes)
Ok(Scalar::from_target_isize(read_bytes, this))
}
Err(e) => {
this.set_last_error_from_io_error(e)?;
Ok(-1)
Ok(Scalar::from_target_isize(-1, this))
}
}
}
@ -528,7 +529,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
buf: Pointer,
count: u64,
offset: Option<i128>,
) -> InterpResult<'tcx, i64> {
) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
// Isolation check is done via `FileDescriptor` trait.
@ -546,7 +547,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?.to_owned();
// We temporarily dup the FD to be able to retain mutable access to `this`.
let Some(fd) = this.machine.fds.dup(fd) else {
return this.fd_not_found();
return Ok(Scalar::from_target_isize(this.fd_not_found()?, this));
};
let result = match offset {
@ -555,7 +556,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let Ok(offset) = u64::try_from(offset) else {
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
return Ok(-1);
return Ok(Scalar::from_target_isize(-1, this));
};
fd.borrow_mut().pwrite(communicate, &bytes, offset, this)
}
@ -563,7 +564,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
drop(fd);
let result = result?.map(|c| i64::try_from(c).unwrap());
this.try_unwrap_io_result(result)
Ok(Scalar::from_target_isize(this.try_unwrap_io_result(result)?, this))
}
}

View file

@ -62,13 +62,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"unsetenv" => {
let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.unsetenv(name)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"setenv" => {
let [name, value, overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.read_scalar(overwrite)?.to_i32()?;
let result = this.setenv(name, value)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"getcwd" => {
let [buf, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -78,12 +78,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"chdir" => {
let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.chdir(path)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"getpid" => {
let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?;
let result = this.getpid()?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
// File descriptors
@ -93,7 +93,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(count)?;
let result = this.read(fd, buf, count, None)?;
this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
this.write_scalar(result, dest)?;
}
"write" => {
let [fd, buf, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -103,7 +103,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
let result = this.write(fd, buf, count, None)?;
// Now, `result` is the value we return back to the program.
this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
this.write_scalar(result, dest)?;
}
"pread" => {
let [fd, buf, count, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -112,7 +112,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let count = this.read_target_usize(count)?;
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
let result = this.read(fd, buf, count, Some(offset))?;
this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
this.write_scalar(result, dest)?;
}
"pwrite" => {
let [fd, buf, n, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -123,7 +123,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
let result = this.write(fd, buf, count, Some(offset))?;
// Now, `result` is the value we return back to the program.
this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
this.write_scalar(result, dest)?;
}
"pread64" => {
let [fd, buf, count, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -132,7 +132,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let count = this.read_target_usize(count)?;
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
let result = this.read(fd, buf, count, Some(offset))?;
this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
this.write_scalar(result, dest)?;
}
"pwrite64" => {
let [fd, buf, n, offset] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -143,7 +143,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
let result = this.write(fd, buf, count, Some(offset))?;
// Now, `result` is the value we return back to the program.
this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
this.write_scalar(result, dest)?;
}
"close" => {
let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -155,20 +155,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// in `this.fcntl()`, so we do not use `check_shim` here.
this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
let result = this.fcntl(args)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"dup" => {
let [old_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let old_fd = this.read_scalar(old_fd)?.to_i32()?;
let new_fd = this.dup(old_fd)?;
this.write_scalar(Scalar::from_i32(new_fd), dest)?;
this.write_scalar(new_fd, dest)?;
}
"dup2" => {
let [old_fd, new_fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let old_fd = this.read_scalar(old_fd)?.to_i32()?;
let new_fd = this.read_scalar(new_fd)?.to_i32()?;
let result = this.dup2(old_fd, new_fd)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"flock" => {
let [fd, op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -183,32 +183,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
let result = this.open(args)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"unlink" => {
let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.unlink(path)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"symlink" => {
let [target, linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.symlink(target, linkpath)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"rename" => {
let [oldpath, newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.rename(oldpath, newpath)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"mkdir" => {
let [path, mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.mkdir(path, mode)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"rmdir" => {
let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.rmdir(path)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"opendir" => {
let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -218,7 +218,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"closedir" => {
let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.closedir(dirp)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"lseek64" => {
let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -255,12 +255,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"fsync" => {
let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.fsync(fd)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"fdatasync" => {
let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.fdatasync(fd)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"readlink" => {
let [pathname, buf, bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -285,7 +285,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"mkstemp" => {
let [template] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.mkstemp(template)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
// Sockets
@ -301,7 +301,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"gettimeofday" => {
let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.gettimeofday(tv, tz)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"localtime_r" => {
let [timep, result_op] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
@ -473,23 +473,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Synchronization primitives
"pthread_mutexattr_init" => {
let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_mutexattr_init(attr)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_mutexattr_init(attr)?;
this.write_null(dest)?;
}
"pthread_mutexattr_settype" => {
let [attr, kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_mutexattr_settype(attr, kind)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"pthread_mutexattr_destroy" => {
let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_mutexattr_destroy(attr)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_mutexattr_destroy(attr)?;
this.write_null(dest)?;
}
"pthread_mutex_init" => {
let [mutex, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_mutex_init(mutex, attr)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_mutex_init(mutex, attr)?;
this.write_null(dest)?;
}
"pthread_mutex_lock" => {
let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -498,17 +498,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"pthread_mutex_trylock" => {
let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_mutex_trylock(mutex)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"pthread_mutex_unlock" => {
let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_mutex_unlock(mutex)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"pthread_mutex_destroy" => {
let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_mutex_destroy(mutex)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_mutex_destroy(mutex)?;
this.write_int(0, dest)?;
}
"pthread_rwlock_rdlock" => {
let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -517,7 +517,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"pthread_rwlock_tryrdlock" => {
let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_rwlock_tryrdlock(rwlock)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"pthread_rwlock_wrlock" => {
let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -526,22 +526,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"pthread_rwlock_trywrlock" => {
let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_rwlock_trywrlock(rwlock)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"pthread_rwlock_unlock" => {
let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_rwlock_unlock(rwlock)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_rwlock_unlock(rwlock)?;
this.write_null(dest)?;
}
"pthread_rwlock_destroy" => {
let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_rwlock_destroy(rwlock)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_rwlock_destroy(rwlock)?;
this.write_null(dest)?;
}
"pthread_condattr_init" => {
let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_condattr_init(attr)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_condattr_init(attr)?;
this.write_null(dest)?;
}
"pthread_condattr_setclock" => {
let [attr, clock_id] =
@ -552,28 +552,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"pthread_condattr_getclock" => {
let [attr, clock_id] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_condattr_getclock(attr, clock_id)?;
this.write_scalar(result, dest)?;
this.pthread_condattr_getclock(attr, clock_id)?;
this.write_null(dest)?;
}
"pthread_condattr_destroy" => {
let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_condattr_destroy(attr)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_condattr_destroy(attr)?;
this.write_null(dest)?;
}
"pthread_cond_init" => {
let [cond, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_cond_init(cond, attr)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_cond_init(cond, attr)?;
this.write_null(dest)?;
}
"pthread_cond_signal" => {
let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_cond_signal(cond)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_cond_signal(cond)?;
this.write_null(dest)?;
}
"pthread_cond_broadcast" => {
let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_cond_broadcast(cond)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_cond_broadcast(cond)?;
this.write_null(dest)?;
}
"pthread_cond_wait" => {
let [cond, mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -585,25 +585,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"pthread_cond_destroy" => {
let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_cond_destroy(cond)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_cond_destroy(cond)?;
this.write_null(dest)?;
}
// Threading
"pthread_create" => {
let [thread, attr, start, arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_create(thread, attr, start, arg)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_create(thread, attr, start, arg)?;
this.write_null(dest)?;
}
"pthread_join" => {
let [thread, retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_join(thread, retval)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_join(thread, retval)?;
this.write_null(dest)?;
}
"pthread_detach" => {
let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_detach(thread)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.pthread_detach(thread)?;
this.write_null(dest)?;
}
"pthread_self" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -612,13 +612,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"sched_yield" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.sched_yield()?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.sched_yield()?;
this.write_null(dest)?;
}
"nanosleep" => {
let [req, rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.nanosleep(req, rem)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"sched_getaffinity" => {
// Currently this function does not exist on all Unixes, e.g. on macOS.
@ -647,23 +647,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if this.ptr_is_null(mask)? {
let einval = this.eval_libc("EFAULT");
this.set_last_error(einval)?;
this.write_scalar(Scalar::from_i32(-1), dest)?;
this.write_int(-1, dest)?;
} else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
// we only copy whole chunks of size_of::<c_ulong>()
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
this.write_scalar(Scalar::from_i32(-1), dest)?;
this.write_int(-1, dest)?;
} else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
let cpuset = cpuset.clone();
// we only copy whole chunks of size_of::<c_ulong>()
let byte_count = Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
this.write_scalar(Scalar::from_i32(0), dest)?;
this.write_null(dest)?;
} else {
// The thread whose ID is pid could not be found
let einval = this.eval_libc("ESRCH");
this.set_last_error(einval)?;
this.write_scalar(Scalar::from_i32(-1), dest)?;
this.write_int(-1, dest)?;
}
}
"sched_setaffinity" => {
@ -690,7 +690,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if this.ptr_is_null(mask)? {
let einval = this.eval_libc("EFAULT");
this.set_last_error(einval)?;
this.write_scalar(Scalar::from_i32(-1), dest)?;
this.write_int(-1, dest)?;
} else {
// NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
// Any unspecified bytes are treated as zero here (none of the CPUs are configured).
@ -702,13 +702,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
match CpuAffinityMask::from_array(this, this.machine.num_cpus, bits_array) {
Some(cpuset) => {
this.machine.thread_cpu_affinity.insert(thread_id, cpuset);
this.write_scalar(Scalar::from_i32(0), dest)?;
this.write_null(dest)?;
}
None => {
// The intersection between the mask and the available CPUs was empty.
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
this.write_scalar(Scalar::from_i32(-1), dest)?;
this.write_int(-1, dest)?;
}
}
}
@ -766,10 +766,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if bufsize > 256 {
let err = this.eval_libc("EIO");
this.set_last_error(err)?;
this.write_scalar(Scalar::from_i32(-1), dest)?;
this.write_int(-1, dest)?;
} else {
this.gen_random(buf, bufsize)?;
this.write_scalar(Scalar::from_i32(0), dest)?;
this.write_null(dest)?;
}
}
"getrandom" => {

View file

@ -395,7 +395,7 @@ fn maybe_sync_file(
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> {
fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
if args.len() < 2 {
throw_ub_format!(
"incorrect number of arguments for `open`: got {}, expected at least 2",
@ -503,7 +503,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// if the flag contains `O_TMPFILE` then we return a graceful error
let eopnotsupp = this.eval_libc("EOPNOTSUPP");
this.set_last_error(eopnotsupp)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
}
@ -524,7 +524,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if path.is_symlink() {
let eloop = this.eval_libc("ELOOP");
this.set_last_error(eloop)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
}
mirror |= o_nofollow;
@ -540,14 +540,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`open`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
let fd = options
.open(path)
.map(|file| this.machine.fds.insert_fd(FileHandle { file, writable }));
this.try_unwrap_io_result(fd)
Ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?))
}
fn lseek64(&mut self, fd: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> {
@ -588,7 +588,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(Scalar::from_i64(result))
}
fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;
@ -597,18 +597,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`unlink`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
let result = remove_file(path).map(|_| 0);
this.try_unwrap_io_result(result)
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
}
fn symlink(
&mut self,
target_op: &OpTy<'tcx>,
linkpath_op: &OpTy<'tcx>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar> {
#[cfg(unix)]
fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> {
std::os::unix::fs::symlink(src, dst)
@ -628,11 +628,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`symlink`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
let result = create_link(&target, &linkpath).map(|_| 0);
this.try_unwrap_io_result(result)
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
}
fn macos_fbsd_stat(
@ -731,7 +731,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
flags_op: &OpTy<'tcx>, // Should be an `int`
mask_op: &OpTy<'tcx>, // Should be an `unsigned int`
statxbuf_op: &OpTy<'tcx>, // Should be a `struct statx *`
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
this.assert_target_os("linux", "statx");
@ -746,7 +746,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? {
let efault = this.eval_libc("EFAULT");
this.set_last_error(efault)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?;
@ -788,7 +788,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.eval_libc("EBADF")
};
this.set_last_error(ecode)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
// the `_mask_op` parameter specifies the file information that the caller requested.
@ -810,7 +810,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
};
let metadata = match metadata {
Some(metadata) => metadata,
None => return Ok(-1),
None => return Ok(Scalar::from_i32(-1)),
};
// The `mode` field specifies the type of the file and the permissions over the file for
@ -903,14 +903,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
&this.project_field_named(&statxbuf, "stx_mtime")?,
)?;
Ok(0)
Ok(Scalar::from_i32(0))
}
fn rename(
&mut self,
oldpath_op: &OpTy<'tcx>,
newpath_op: &OpTy<'tcx>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let oldpath_ptr = this.read_pointer(oldpath_op)?;
@ -919,7 +919,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? {
let efault = this.eval_libc("EFAULT");
this.set_last_error(efault)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
let oldpath = this.read_path_from_c_str(oldpath_ptr)?;
@ -929,15 +929,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`rename`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
let result = rename(oldpath, newpath).map(|_| 0);
this.try_unwrap_io_result(result)
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
}
fn mkdir(&mut self, path_op: &OpTy<'tcx>, mode_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn mkdir(&mut self, path_op: &OpTy<'tcx>, mode_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
#[cfg_attr(not(unix), allow(unused_variables))]
@ -953,7 +953,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`mkdir`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
#[cfg_attr(not(unix), allow(unused_mut))]
@ -969,10 +969,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let result = builder.create(path).map(|_| 0i32);
this.try_unwrap_io_result(result)
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
}
fn rmdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn rmdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?;
@ -981,12 +981,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`rmdir`", reject_with)?;
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
let result = remove_dir(path).map(|_| 0i32);
this.try_unwrap_io_result(result)
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
}
fn opendir(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@ -1236,27 +1236,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}))
}
fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let dirp = this.read_target_usize(dirp_op)?;
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
Ok(Scalar::from_i32(if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`closedir`", reject_with)?;
// Set error code as "EBADF" (bad fd)
return this.fd_not_found();
}
if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
this.fd_not_found()?
} else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
if let Some(entry) = open_dir.entry {
this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
}
drop(open_dir);
Ok(0)
0
} else {
this.fd_not_found()
}
this.fd_not_found()?
}))
}
fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar> {
@ -1300,7 +1297,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
}
fn fsync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn fsync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
// On macOS, `fsync` (unlike `fcntl(F_FULLFSYNC)`) does not wait for the
// underlying disk to finish writing. In the interest of host compatibility,
// we conservatively implement this with `sync_all`, which
@ -1314,16 +1311,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`fsync`", reject_with)?;
// Set error code as "EBADF" (bad fd)
return this.fd_not_found();
return Ok(Scalar::from_i32(this.fd_not_found()?));
}
return self.ffullsync_fd(fd);
self.ffullsync_fd(fd)
}
fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, i32> {
fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let Some(file_description) = this.machine.fds.get(fd) else {
return Ok(this.fd_not_found()?);
return Ok(Scalar::from_i32(this.fd_not_found()?));
};
// Only regular files support synchronization.
let FileHandle { file, writable } =
@ -1332,10 +1329,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
})?;
let io_result = maybe_sync_file(file, *writable, File::sync_all);
drop(file_description);
this.try_unwrap_io_result(io_result)
Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
}
fn fdatasync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn fdatasync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let fd = this.read_scalar(fd_op)?.to_i32()?;
@ -1344,11 +1341,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`fdatasync`", reject_with)?;
// Set error code as "EBADF" (bad fd)
return this.fd_not_found();
return Ok(Scalar::from_i32(this.fd_not_found()?));
}
let Some(file_description) = this.machine.fds.get(fd) else {
return Ok(this.fd_not_found()?);
return Ok(Scalar::from_i32(this.fd_not_found()?));
};
// Only regular files support synchronization.
let FileHandle { file, writable } =
@ -1357,7 +1354,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
})?;
let io_result = maybe_sync_file(file, *writable, File::sync_data);
drop(file_description);
this.try_unwrap_io_result(io_result)
Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
}
fn sync_file_range(
@ -1534,7 +1531,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
}
}
fn mkstemp(&mut self, template_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn mkstemp(&mut self, template_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
use rand::seq::SliceRandom;
// POSIX defines the template string.
@ -1565,7 +1562,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.reject_in_isolation("`mkstemp`", reject_with)?;
let eacc = this.eval_libc("EACCES");
this.set_last_error(eacc)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
// Get the bytes of the suffix we expect in _target_ encoding.
@ -1583,7 +1580,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if last_six_char_bytes != suffix_bytes {
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
// At this point we know we have 6 ASCII 'X' characters as a suffix.
@ -1638,7 +1635,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
match file {
Ok(f) => {
let fd = this.machine.fds.insert_fd(FileHandle { file: f, writable: true });
return Ok(fd);
return Ok(Scalar::from_i32(fd));
}
Err(e) =>
match e.kind() {
@ -1649,7 +1646,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// "On error, -1 is returned, and errno is set to
// indicate the error"
this.set_last_error_from_io_error(e)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
},
}
@ -1658,7 +1655,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// We ran out of attempts to create the file, return an error.
let eexist = this.eval_libc("EEXIST");
this.set_last_error(eexist)?;
Ok(-1)
Ok(Scalar::from_i32(-1))
}
}

View file

@ -44,7 +44,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let [dirfd, pathname, flags, mask, statxbuf] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
// epoll, eventfd
@ -97,7 +97,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"gettid" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.linux_gettid()?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
// Dynamically invoked syscalls
@ -176,12 +176,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"__libc_current_sigrtmin" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.write_scalar(Scalar::from_i32(SIGRTMIN), dest)?;
this.write_int(SIGRTMIN, dest)?;
}
"__libc_current_sigrtmax" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.write_scalar(Scalar::from_i32(SIGRTMAX), dest)?;
this.write_int(SIGRTMAX, dest)?;
}
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.

View file

@ -363,20 +363,20 @@ fn cond_set_clock_id<'tcx>(
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let default_kind = this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT");
mutexattr_set_kind(this, attr_op, default_kind)?;
Ok(0)
Ok(())
}
fn pthread_mutexattr_settype(
&mut self,
attr_op: &OpTy<'tcx>,
kind_op: &OpTy<'tcx>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let kind = this.read_scalar(kind_op)?.to_i32()?;
@ -407,13 +407,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
mutexattr_set_kind(this, attr_op, kind)?;
} else {
let einval = this.eval_libc_i32("EINVAL");
return Ok(einval);
return Ok(Scalar::from_i32(einval));
}
Ok(0)
Ok(Scalar::from_i32(0))
}
fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
// Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit.
@ -435,14 +435,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
&this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_mutexattr_t"))?,
)?;
Ok(0)
Ok(())
}
fn pthread_mutex_init(
&mut self,
mutex_op: &OpTy<'tcx>,
attr_op: &OpTy<'tcx>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let attr = this.read_pointer(attr_op)?;
@ -457,7 +457,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
mutex_set_kind(this, mutex_op, kind)?;
Ok(0)
Ok(())
}
fn pthread_mutex_lock(
@ -501,25 +501,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(())
}
fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let kind = mutex_get_kind(this, mutex_op)?;
let id = mutex_get_id(this, mutex_op)?;
if this.mutex_is_locked(id) {
Ok(Scalar::from_i32(if this.mutex_is_locked(id) {
let owner_thread = this.mutex_get_owner(id);
if owner_thread != this.active_thread() {
Ok(this.eval_libc_i32("EBUSY"))
this.eval_libc_i32("EBUSY")
} else {
if is_mutex_kind_default(this, kind)?
|| is_mutex_kind_normal(this, kind)?
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
{
Ok(this.eval_libc_i32("EBUSY"))
this.eval_libc_i32("EBUSY")
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") {
this.mutex_lock(id);
Ok(0)
0
} else {
throw_unsup_format!(
"called pthread_mutex_trylock on an unsupported type of mutex"
@ -529,11 +529,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
} else {
// The mutex is unlocked. Let's lock it.
this.mutex_lock(id);
Ok(0)
}
0
}))
}
fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let kind = mutex_get_kind(this, mutex_op)?;
@ -541,7 +541,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if let Some(_old_locked_count) = this.mutex_unlock(id)? {
// The mutex was locked by the current thread.
Ok(0)
Ok(Scalar::from_i32(0))
} else {
// The mutex was locked by another thread or not locked at all. See
// the “Unlock When Not Owner” column in
@ -557,14 +557,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")
{
Ok(this.eval_libc_i32("EPERM"))
Ok(Scalar::from_i32(this.eval_libc_i32("EPERM")))
} else {
throw_unsup_format!("called pthread_mutex_unlock on an unsupported type of mutex");
}
}
}
fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let id = mutex_get_id(this, mutex_op)?;
@ -583,7 +583,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
)?;
// FIXME: delete interpreter state associated with this mutex.
Ok(0)
Ok(())
}
fn pthread_rwlock_rdlock(
@ -605,16 +605,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(())
}
fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let id = rwlock_get_id(this, rwlock_op)?;
if this.rwlock_is_write_locked(id) {
Ok(this.eval_libc_i32("EBUSY"))
Ok(Scalar::from_i32(this.eval_libc_i32("EBUSY")))
} else {
this.rwlock_reader_lock(id);
Ok(0)
Ok(Scalar::from_i32(0))
}
}
@ -649,35 +649,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(())
}
fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let id = rwlock_get_id(this, rwlock_op)?;
if this.rwlock_is_locked(id) {
Ok(this.eval_libc_i32("EBUSY"))
Ok(Scalar::from_i32(this.eval_libc_i32("EBUSY")))
} else {
this.rwlock_writer_lock(id);
Ok(0)
Ok(Scalar::from_i32(0))
}
}
fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let id = rwlock_get_id(this, rwlock_op)?;
#[allow(clippy::if_same_then_else)]
if this.rwlock_reader_unlock(id)? {
Ok(0)
} else if this.rwlock_writer_unlock(id)? {
Ok(0)
if this.rwlock_reader_unlock(id)? || this.rwlock_writer_unlock(id)? {
Ok(())
} else {
throw_ub_format!("unlocked an rwlock that was not locked by the active thread");
}
}
fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let id = rwlock_get_id(this, rwlock_op)?;
@ -695,10 +693,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
)?;
// FIXME: delete interpreter state associated with this rwlock.
Ok(0)
Ok(())
}
fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
// no clock attribute on macOS
@ -710,7 +708,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
condattr_set_clock_id(this, attr_op, default_clock_id)?;
}
Ok(0)
Ok(())
}
fn pthread_condattr_setclock(
@ -737,16 +735,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
&mut self,
attr_op: &OpTy<'tcx>,
clk_id_op: &OpTy<'tcx>,
) -> InterpResult<'tcx, Scalar> {
) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let clock_id = condattr_get_clock_id(this, attr_op)?;
this.write_scalar(Scalar::from_i32(clock_id), &this.deref_pointer(clk_id_op)?)?;
Ok(Scalar::from_i32(0))
Ok(())
}
fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
// Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit.
@ -761,14 +759,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
&this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_condattr_t"))?,
)?;
Ok(0)
Ok(())
}
fn pthread_cond_init(
&mut self,
cond_op: &OpTy<'tcx>,
attr_op: &OpTy<'tcx>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let attr = this.read_pointer(attr_op)?;
@ -784,21 +782,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
cond_set_clock_id(this, cond_op, clock_id)?;
Ok(0)
Ok(())
}
fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let id = cond_get_id(this, cond_op)?;
this.condvar_signal(id)?;
Ok(0)
Ok(())
}
fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let id = cond_get_id(this, cond_op)?;
while this.condvar_signal(id)? {}
Ok(0)
Ok(())
}
fn pthread_cond_wait(
@ -869,7 +867,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(())
}
fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let id = cond_get_id(this, cond_op)?;
@ -885,6 +883,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_uninit(&this.deref_pointer_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?;
// FIXME: delete interpreter state associated with this condvar.
Ok(0)
Ok(())
}
}

View file

@ -10,7 +10,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
_attr: &OpTy<'tcx>,
start_routine: &OpTy<'tcx>,
arg: &OpTy<'tcx>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let thread_info_place = this.deref_pointer_as(thread, this.libc_ty_layout("pthread_t"))?;
@ -27,14 +27,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.layout_of(this.tcx.types.usize)?,
)?;
Ok(0)
Ok(())
}
fn pthread_join(
&mut self,
thread: &OpTy<'tcx>,
retval: &OpTy<'tcx>,
) -> InterpResult<'tcx, i32> {
fn pthread_join(&mut self, thread: &OpTy<'tcx>, retval: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
if !this.ptr_is_null(this.read_pointer(retval)?)? {
@ -45,10 +41,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
this.join_thread_exclusive(thread_id.try_into().expect("thread ID should fit in u32"))?;
Ok(0)
Ok(())
}
fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?;
@ -57,7 +53,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
/*allow_terminated_joined*/ false,
)?;
Ok(0)
Ok(())
}
fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> {
@ -113,11 +109,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(if success { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") })
}
fn sched_yield(&mut self) -> InterpResult<'tcx, i32> {
fn sched_yield(&mut self) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
this.yield_active_thread();
Ok(0)
Ok(())
}
}

View file

@ -197,11 +197,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
#[allow(non_snake_case)]
fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, u32> {
fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
this.assert_target_os("windows", "GetCurrentProcessId");
Ok(this.get_pid())
Ok(Scalar::from_u32(this.get_pid()))
}
#[allow(non_snake_case)]

View file

@ -141,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"GetCurrentProcessId" => {
let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let result = this.GetCurrentProcessId()?;
this.write_int(result, dest)?;
this.write_scalar(result, dest)?;
}
// File related shims
@ -372,7 +372,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
// Return success (`1`).
this.write_scalar(Scalar::from_i32(1), dest)?;
this.write_int(1, dest)?;
}
// Access to command-line arguments
@ -563,7 +563,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let ptr = this.read_pointer(ptr)?;
let len = this.read_target_usize(len)?;
this.gen_random(ptr, len)?;
this.write_scalar(Scalar::from_i32(1), dest)?;
this.write_int(1, dest)?;
}
"BCryptGenRandom" => {
// used by getrandom 0.2
@ -627,7 +627,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.CloseHandle(handle)?;
this.write_scalar(Scalar::from_u32(1), dest)?;
this.write_int(1, dest)?;
}
"GetModuleFileNameW" => {
let [handle, filename, size] =