commit
403b3f94bb
@ -1 +1 @@
|
||||
1603a70f82240ba2d27f72f964e36614d7620ad3
|
||||
20ffea6938b5839c390252e07940b99e3b6a889a
|
||||
|
@ -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(
|
||||
|
@ -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)?;
|
||||
@ -437,7 +437,8 @@ fn emulate_foreign_item_by_name(
|
||||
}
|
||||
"pthread_self" => {
|
||||
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.pthread_self(dest)?;
|
||||
let res = this.pthread_self()?;
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
"sched_yield" => {
|
||||
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
|
@ -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()?;
|
||||
|
||||
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)
|
||||
this.try_unwrap_io_result(result)?
|
||||
} else {
|
||||
this.handle_not_found()
|
||||
}
|
||||
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();
|
||||
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)
|
||||
this.try_unwrap_io_result(result)?
|
||||
} else {
|
||||
this.handle_not_found()
|
||||
}
|
||||
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()?));
|
||||
}
|
||||
|
||||
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))
|
||||
this.try_unwrap_io_result(result.map(|_| 0i32))?
|
||||
} else {
|
||||
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)
|
||||
-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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,27 +47,30 @@ 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
|
||||
"prctl" => {
|
||||
// prctl is variadic. (It is not documented like that in the manpage, but defined like that in the libc crate.)
|
||||
this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
|
||||
let result = this.prctl(args)?;
|
||||
this.write_scalar(Scalar::from_i32(result), dest)?;
|
||||
}
|
||||
"pthread_condattr_setclock" => {
|
||||
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] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let res = this.pthread_setname_np(
|
||||
this.read_scalar(thread)?.check_init()?,
|
||||
this.read_scalar(name)?.check_init()?,
|
||||
)?;
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
|
||||
// Dynamically invoked syscalls
|
||||
|
@ -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
|
||||
@ -173,8 +173,8 @@ fn emulate_foreign_item_by_name(
|
||||
// Threading
|
||||
"pthread_setname_np" => {
|
||||
let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let name = this.read_pointer(name)?;
|
||||
this.pthread_setname_np(name)?;
|
||||
let thread = this.pthread_self()?;
|
||||
this.pthread_setname_np(thread, this.read_scalar(name)?.check_init()?)?;
|
||||
}
|
||||
|
||||
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
|
||||
|
@ -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(
|
||||
|
@ -84,68 +84,27 @@ fn pthread_detach(&mut self, thread: &OpTy<'tcx, Provenance>) -> InterpResult<'t
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn pthread_self(&mut self, dest: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||
fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let thread_id = this.get_active_thread();
|
||||
this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest)
|
||||
Ok(Scalar::from_machine_usize(thread_id.into(), this))
|
||||
}
|
||||
|
||||
fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> {
|
||||
fn pthread_setname_np(
|
||||
&mut self,
|
||||
thread: Scalar<Provenance>,
|
||||
name: Scalar<Provenance>,
|
||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
let this = self.eval_context_mut();
|
||||
this.assert_target_os("linux", "prctl");
|
||||
|
||||
if args.is_empty() {
|
||||
throw_ub_format!(
|
||||
"incorrect number of arguments for `prctl`: got {}, expected at least 1",
|
||||
args.len()
|
||||
);
|
||||
}
|
||||
|
||||
let option = this.read_scalar(&args[0])?.to_i32()?;
|
||||
if option == this.eval_libc_i32("PR_SET_NAME")? {
|
||||
if args.len() < 2 {
|
||||
throw_ub_format!(
|
||||
"incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2",
|
||||
args.len()
|
||||
);
|
||||
}
|
||||
|
||||
let address = this.read_pointer(&args[1])?;
|
||||
let mut name = this.read_c_str(address)?.to_owned();
|
||||
// The name should be no more than 16 bytes, including the null
|
||||
// byte. Since `read_c_str` returns the string without the null
|
||||
// byte, we need to truncate to 15.
|
||||
name.truncate(15);
|
||||
this.set_active_thread_name(name);
|
||||
} else if option == this.eval_libc_i32("PR_GET_NAME")? {
|
||||
if args.len() < 2 {
|
||||
throw_ub_format!(
|
||||
"incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2",
|
||||
args.len()
|
||||
);
|
||||
}
|
||||
|
||||
let address = this.read_pointer(&args[1])?;
|
||||
let mut name = this.get_active_thread_name().to_vec();
|
||||
name.push(0u8);
|
||||
assert!(name.len() <= 16);
|
||||
this.write_bytes_ptr(address, name)?;
|
||||
} else {
|
||||
throw_unsup_format!("unsupported prctl option {}", option);
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn pthread_setname_np(&mut self, name: Pointer<Option<Provenance>>) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
this.assert_target_os("macos", "pthread_setname_np");
|
||||
let thread = ThreadId::try_from(thread.to_machine_usize(this)?).unwrap();
|
||||
let name = name.to_pointer(this)?;
|
||||
|
||||
let name = this.read_c_str(name)?.to_owned();
|
||||
this.set_active_thread_name(name);
|
||||
this.set_thread_name(thread, name);
|
||||
|
||||
Ok(())
|
||||
Ok(Scalar::from_u32(0))
|
||||
}
|
||||
|
||||
fn sched_yield(&mut self) -> InterpResult<'tcx, i32> {
|
||||
|
@ -69,9 +69,9 @@ fn from(id: u32) -> Self {
|
||||
}
|
||||
}
|
||||
|
||||
impl ThreadId {
|
||||
pub fn to_u32_scalar(&self) -> Scalar<Provenance> {
|
||||
Scalar::from_u32(self.0)
|
||||
impl From<ThreadId> for u64 {
|
||||
fn from(t: ThreadId) -> Self {
|
||||
t.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,14 +394,9 @@ fn join_thread(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the name of the active thread.
|
||||
fn set_active_thread_name(&mut self, new_thread_name: Vec<u8>) {
|
||||
self.active_thread_mut().thread_name = Some(new_thread_name);
|
||||
}
|
||||
|
||||
/// Get the name of the active thread.
|
||||
pub fn get_active_thread_name(&self) -> &[u8] {
|
||||
self.active_thread_ref().thread_name()
|
||||
/// Set the name of the given thread.
|
||||
pub fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec<u8>) {
|
||||
self.threads[thread].thread_name = Some(new_thread_name);
|
||||
}
|
||||
|
||||
/// Get the name of the given thread.
|
||||
@ -704,18 +699,18 @@ fn active_thread_stack_mut(
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_active_thread_name(&mut self, new_thread_name: Vec<u8>) {
|
||||
fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec<u8>) {
|
||||
let this = self.eval_context_mut();
|
||||
this.machine.threads.set_active_thread_name(new_thread_name);
|
||||
this.machine.threads.set_thread_name(thread, new_thread_name);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_active_thread_name<'c>(&'c self) -> &'c [u8]
|
||||
fn get_thread_name<'c>(&'c self, thread: ThreadId) -> &'c [u8]
|
||||
where
|
||||
'mir: 'c,
|
||||
{
|
||||
let this = self.eval_context_ref();
|
||||
this.machine.threads.get_active_thread_name()
|
||||
this.machine.threads.get_thread_name(thread)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -277,58 +277,6 @@ fn test_rwlock_libc_static_initializer() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Test whether the `prctl` shim correctly sets the thread name.
|
||||
///
|
||||
/// Note: `prctl` exists only on Linux.
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
fn test_prctl_thread_name() {
|
||||
use libc::c_long;
|
||||
use std::ffi::CString;
|
||||
unsafe {
|
||||
let mut buf = [255; 10];
|
||||
assert_eq!(
|
||||
libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long),
|
||||
0,
|
||||
);
|
||||
// Rust runtime might set thread name, so we allow two options here.
|
||||
assert!(&buf[..10] == b"<unnamed>\0" || &buf[..5] == b"main\0");
|
||||
let thread_name = CString::new("hello").expect("CString::new failed");
|
||||
assert_eq!(
|
||||
libc::prctl(
|
||||
libc::PR_SET_NAME,
|
||||
thread_name.as_ptr(),
|
||||
0 as c_long,
|
||||
0 as c_long,
|
||||
0 as c_long,
|
||||
),
|
||||
0,
|
||||
);
|
||||
let mut buf = [255; 6];
|
||||
assert_eq!(
|
||||
libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long),
|
||||
0,
|
||||
);
|
||||
assert_eq!(b"hello\0", &buf);
|
||||
let long_thread_name = CString::new("01234567890123456789").expect("CString::new failed");
|
||||
assert_eq!(
|
||||
libc::prctl(
|
||||
libc::PR_SET_NAME,
|
||||
long_thread_name.as_ptr(),
|
||||
0 as c_long,
|
||||
0 as c_long,
|
||||
0 as c_long,
|
||||
),
|
||||
0,
|
||||
);
|
||||
let mut buf = [255; 16];
|
||||
assert_eq!(
|
||||
libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long),
|
||||
0,
|
||||
);
|
||||
assert_eq!(b"012345678901234\0", &buf);
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests whether each thread has its own `__errno_location`.
|
||||
fn test_thread_local_errno() {
|
||||
#[cfg(target_os = "linux")]
|
||||
@ -473,9 +421,6 @@ fn main() {
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
test_mutex_libc_static_initializer_recursive();
|
||||
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
test_prctl_thread_name();
|
||||
|
||||
test_thread_local_errno();
|
||||
|
||||
#[cfg(any(target_os = "linux"))]
|
||||
|
Loading…
Reference in New Issue
Block a user