move a bunch of type information into the respective shim

This commit is contained in:
Ralf Jung 2022-08-11 19:27:15 -04:00
parent 38a495346f
commit 96049ef88e
6 changed files with 106 additions and 97 deletions

View File

@ -15,7 +15,7 @@ fn clock_gettime(
&mut self,
clk_id_op: &OpTy<'tcx, Provenance>,
tp_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
// This clock support is deliberately minimal because a lot of clock types have fiddly
// properties (is it possible for Miri to be suspended independently of the host?). If you
// have a use for another clock type, please open an issue.
@ -46,7 +46,7 @@ fn clock_gettime(
} else {
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
};
let tv_sec = duration.as_secs();
@ -54,7 +54,7 @@ fn clock_gettime(
this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &this.deref_operand(tp_op)?)?;
Ok(0)
Ok(Scalar::from_i32(0))
}
fn gettimeofday(
@ -160,7 +160,7 @@ fn QueryPerformanceFrequency(
Ok(-1) // Return non-zero on success
}
fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> {
fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_ref();
this.assert_target_os("macos", "mach_absolute_time");
@ -169,13 +169,16 @@ fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> {
// This returns a u64, with time units determined dynamically by `mach_timebase_info`.
// We return plain nanoseconds.
let duration = Instant::now().duration_since(this.machine.time_anchor);
u64::try_from(duration.as_nanos()).map_err(|_| {
let res = u64::try_from(duration.as_nanos()).map_err(|_| {
err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported")
.into()
})
})?;
Ok(Scalar::from_u64(res))
}
fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> {
fn mach_timebase_info(
&mut self,
info_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
this.assert_target_os("macos", "mach_timebase_info");
@ -188,7 +191,7 @@ fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Provenance>) -> InterpResu
let (numer, denom) = (1, 1);
this.write_int_fields(&[numer.into(), denom.into()], &info)?;
Ok(0) // KERN_SUCCESS
Ok(Scalar::from_i32(0)) // KERN_SUCCESS
}
fn nanosleep(

View File

@ -63,7 +63,7 @@ fn emulate_foreign_item_by_name(
"close" => {
let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.close(fd)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"fcntl" => {
// `fcntl` is variadic. The argument count is checked based on the first argument
@ -128,13 +128,13 @@ fn emulate_foreign_item_by_name(
"lseek64" => {
let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.lseek64(fd, offset, whence)?;
this.write_scalar(Scalar::from_i64(result), dest)?;
this.write_scalar(result, dest)?;
}
"ftruncate64" => {
let [fd, length] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.ftruncate64(fd, length)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"fsync" => {
let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -164,7 +164,7 @@ fn emulate_foreign_item_by_name(
"realpath" => {
let [path, resolved_path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.realpath(path, resolved_path)?;
this.write_pointer(result, dest)?;
this.write_scalar(result, dest)?;
}
"mkstemp" => {
let [template] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;

View File

@ -664,17 +664,19 @@ fn fcntl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32>
}
}
fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> {
fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
let fd = this.read_scalar(fd_op)?.to_i32()?;
if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) {
let result = file_descriptor.close(this.machine.communicate())?;
this.try_unwrap_io_result(result)
} else {
this.handle_not_found()
}
Ok(Scalar::from_i32(
if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) {
let result = file_descriptor.close(this.machine.communicate())?;
this.try_unwrap_io_result(result)?
} else {
this.handle_not_found()?
},
))
}
fn read(
@ -772,7 +774,7 @@ fn lseek64(
fd_op: &OpTy<'tcx, Provenance>,
offset_op: &OpTy<'tcx, Provenance>,
whence_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i64> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
// Isolation check is done via `FileDescriptor` trait.
@ -790,18 +792,20 @@ fn lseek64(
} else {
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
return Ok(-1);
return Ok(Scalar::from_i64(-1));
};
let communicate = this.machine.communicate();
if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) {
let result = file_descriptor
.seek(communicate, seek_from)?
.map(|offset| i64::try_from(offset).unwrap());
this.try_unwrap_io_result(result)
} else {
this.handle_not_found()
}
Ok(Scalar::from_i64(
if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) {
let result = file_descriptor
.seek(communicate, seek_from)?
.map(|offset| i64::try_from(offset).unwrap());
this.try_unwrap_io_result(result)?
} else {
this.handle_not_found()?
},
))
}
fn unlink(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> {
@ -855,7 +859,7 @@ fn macos_stat(
&mut self,
path_op: &OpTy<'tcx, Provenance>,
buf_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
this.assert_target_os("macos", "stat");
@ -867,16 +871,16 @@ fn macos_stat(
this.reject_in_isolation("`stat`", reject_with)?;
let eacc = this.eval_libc("EACCES")?;
this.set_last_error(eacc)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
// `stat` always follows symlinks.
let metadata = match FileMetadata::from_path(this, &path, true)? {
Some(metadata) => metadata,
None => return Ok(-1),
None => return Ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
};
this.macos_stat_write_buf(metadata, buf_op)
Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
}
// `lstat` is used to get symlink metadata.
@ -884,7 +888,7 @@ fn macos_lstat(
&mut self,
path_op: &OpTy<'tcx, Provenance>,
buf_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
this.assert_target_os("macos", "lstat");
@ -896,22 +900,22 @@ fn macos_lstat(
this.reject_in_isolation("`lstat`", reject_with)?;
let eacc = this.eval_libc("EACCES")?;
this.set_last_error(eacc)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
let metadata = match FileMetadata::from_path(this, &path, false)? {
Some(metadata) => metadata,
None => return Ok(-1),
None => return Ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
};
this.macos_stat_write_buf(metadata, buf_op)
Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
}
fn macos_fstat(
&mut self,
fd_op: &OpTy<'tcx, Provenance>,
buf_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
this.assert_target_os("macos", "fstat");
@ -922,14 +926,14 @@ fn macos_fstat(
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`fstat`", reject_with)?;
// Set error code as "EBADF" (bad fd)
return this.handle_not_found();
return Ok(Scalar::from_i32(this.handle_not_found()?));
}
let metadata = match FileMetadata::from_fd(this, fd)? {
Some(metadata) => metadata,
None => return Ok(-1),
None => return Ok(Scalar::from_i32(-1)),
};
this.macos_stat_write_buf(metadata, buf_op)
Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
}
fn linux_statx(
@ -1343,7 +1347,7 @@ fn macos_readdir_r(
dirp_op: &OpTy<'tcx, Provenance>,
entry_op: &OpTy<'tcx, Provenance>,
result_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
this.assert_target_os("macos", "readdir_r");
@ -1354,13 +1358,13 @@ fn macos_readdir_r(
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`readdir_r`", reject_with)?;
// Set error code as "EBADF" (bad fd)
return this.handle_not_found();
return Ok(Scalar::from_i32(this.handle_not_found()?));
}
let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| {
err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir")
})?;
match open_dir.read_dir.next() {
Ok(Scalar::from_i32(match open_dir.read_dir.next() {
Some(Ok(dir_entry)) => {
// Write into entry, write pointer to result, return 0 on success.
// The name is written with write_os_str_to_c_str, while the rest of the
@ -1417,17 +1421,17 @@ fn macos_readdir_r(
let result_place = this.deref_operand(result_op)?;
this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?;
Ok(0)
0
}
None => {
// end of stream: return 0, assign *result=NULL
this.write_null(&this.deref_operand(result_op)?.into())?;
Ok(0)
0
}
Some(Err(e)) =>
match e.raw_os_error() {
// return positive error number on error
Some(error) => Ok(error),
Some(error) => error,
None => {
throw_unsup_format!(
"the error {} couldn't be converted to a return value",
@ -1435,7 +1439,7 @@ fn macos_readdir_r(
)
}
},
}
}))
}
fn closedir(&mut self, dirp_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> {
@ -1463,7 +1467,7 @@ fn ftruncate64(
&mut self,
fd_op: &OpTy<'tcx, Provenance>,
length_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
let fd = this.read_scalar(fd_op)?.to_i32()?;
@ -1473,30 +1477,32 @@ fn ftruncate64(
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`ftruncate64`", reject_with)?;
// Set error code as "EBADF" (bad fd)
return this.handle_not_found();
return Ok(Scalar::from_i32(this.handle_not_found()?));
}
if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) {
// FIXME: Support ftruncate64 for all FDs
let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
if *writable {
if let Ok(length) = length.try_into() {
let result = file.set_len(length);
this.try_unwrap_io_result(result.map(|_| 0i32))
Ok(Scalar::from_i32(
if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) {
// FIXME: Support ftruncate64 for all FDs
let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
if *writable {
if let Ok(length) = length.try_into() {
let result = file.set_len(length);
this.try_unwrap_io_result(result.map(|_| 0i32))?
} else {
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
-1
}
} else {
// The file is not writable
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
Ok(-1)
-1
}
} else {
// The file is not writable
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
Ok(-1)
}
} else {
this.handle_not_found()
}
this.handle_not_found()?
},
))
}
fn fsync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> {
@ -1554,7 +1560,7 @@ fn sync_file_range(
offset_op: &OpTy<'tcx, Provenance>,
nbytes_op: &OpTy<'tcx, Provenance>,
flags_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
let fd = this.read_scalar(fd_op)?.to_i32()?;
@ -1565,7 +1571,7 @@ fn sync_file_range(
if offset < 0 || nbytes < 0 {
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE")?
| this.eval_libc_i32("SYNC_FILE_RANGE_WRITE")?
@ -1573,23 +1579,23 @@ fn sync_file_range(
if flags & allowed_flags != flags {
let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?;
return Ok(-1);
return Ok(Scalar::from_i32(-1));
}
// Reject if isolation is enabled.
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
this.reject_in_isolation("`sync_file_range`", reject_with)?;
// Set error code as "EBADF" (bad fd)
return this.handle_not_found();
return Ok(Scalar::from_i32(this.handle_not_found()?));
}
if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
// FIXME: Support sync_data_range for all FDs
let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
let io_result = maybe_sync_file(file, *writable, File::sync_data);
this.try_unwrap_io_result(io_result)
Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
} else {
this.handle_not_found()
Ok(Scalar::from_i32(this.handle_not_found()?))
}
}
@ -1674,7 +1680,7 @@ fn realpath(
&mut self,
path_op: &OpTy<'tcx, Provenance>,
processed_path_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
this.assert_target_os_is_unix("realpath");
@ -1686,7 +1692,7 @@ fn realpath(
this.reject_in_isolation("`realpath`", reject_with)?;
let eacc = this.eval_libc("EACCES")?;
this.set_last_error(eacc)?;
return Ok(Pointer::null());
return Ok(Scalar::from_machine_usize(0, this));
}
let result = std::fs::canonicalize(pathname);
@ -1717,16 +1723,16 @@ fn realpath(
// seems like a bit of a mess anyway: <https://eklitzke.org/path-max-is-tricky>.
let enametoolong = this.eval_libc("ENAMETOOLONG")?;
this.set_last_error(enametoolong)?;
return Ok(Pointer::null());
return Ok(Scalar::from_machine_usize(0, this));
}
processed_ptr
};
Ok(dest)
Ok(Scalar::from_maybe_pointer(dest, this))
}
Err(e) => {
this.set_last_error_from_io_error(e.kind())?;
Ok(Pointer::null())
Ok(Scalar::from_machine_usize(0, this))
}
}
}

View File

@ -38,7 +38,7 @@ fn emulate_foreign_item_by_name(
let [fd, offset, nbytes, flags] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.sync_file_range(fd, offset, nbytes, flags)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
// Time related shims
@ -47,7 +47,7 @@ fn emulate_foreign_item_by_name(
let [clk_id, tp] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.clock_gettime(clk_id, tp)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
// Threading
@ -55,13 +55,13 @@ fn emulate_foreign_item_by_name(
let [attr, clock_id] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.pthread_condattr_setclock(attr, clock_id)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"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(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"pthread_setname_np" => {
let [thread, name] =

View File

@ -29,24 +29,24 @@ fn emulate_foreign_item_by_name(
"close$NOCANCEL" => {
let [result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.close(result)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"stat" | "stat64" | "stat$INODE64" => {
let [path, buf] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_stat(path, buf)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"lstat" | "lstat64" | "lstat$INODE64" => {
let [path, buf] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_lstat(path, buf)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat64" | "fstat$INODE64" => {
let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_fstat(fd, buf)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"opendir$INODE64" => {
let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@ -57,27 +57,27 @@ fn emulate_foreign_item_by_name(
let [dirp, entry, result] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_readdir_r(dirp, entry, result)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"lseek" => {
let [fd, offset, whence] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
// macOS is 64bit-only, so this is lseek64
let result = this.lseek64(fd, offset, whence)?;
this.write_scalar(Scalar::from_i64(result), dest)?;
this.write_scalar(result, dest)?;
}
"ftruncate" => {
let [fd, length] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
// macOS is 64bit-only, so this is ftruncate64
let result = this.ftruncate64(fd, length)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
"realpath$DARWIN_EXTSN" => {
let [path, resolved_path] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.realpath(path, resolved_path)?;
this.write_pointer(result, dest)?;
this.write_scalar(result, dest)?;
}
// Environment related shims
@ -93,13 +93,13 @@ fn emulate_foreign_item_by_name(
"mach_absolute_time" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.mach_absolute_time()?;
this.write_scalar(Scalar::from_u64(result), dest)?;
this.write_scalar(result, dest)?;
}
"mach_timebase_info" => {
let [info] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.mach_timebase_info(info)?;
this.write_scalar(Scalar::from_i32(result), dest)?;
this.write_scalar(result, dest)?;
}
// Access to command-line arguments

View File

@ -723,7 +723,7 @@ fn pthread_condattr_setclock(
&mut self,
attr_op: &OpTy<'tcx, Provenance>,
clock_id_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
let clock_id = this.read_scalar(clock_id_op)?.check_init()?;
@ -733,23 +733,23 @@ fn pthread_condattr_setclock(
condattr_set_clock_id(this, attr_op, clock_id)?;
} 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_condattr_getclock(
&mut self,
attr_op: &OpTy<'tcx, Provenance>,
clk_id_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
let clock_id = condattr_get_clock_id(this, attr_op)?;
this.write_scalar(clock_id, &this.deref_operand(clk_id_op)?.into())?;
Ok(0)
Ok(Scalar::from_i32(0))
}
fn pthread_condattr_destroy(