From 23cd7b863ff0ca4fba9e28402a067f3f75772d26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Aug 2022 19:01:19 -0400 Subject: [PATCH 1/3] rustup for pthread_setname_np on Linux --- rust-version | 2 +- src/shims/unix/foreign_items.rs | 3 ++- src/shims/unix/linux/foreign_items.rs | 9 +++++++ src/shims/unix/macos/foreign_items.rs | 4 ++-- src/shims/unix/thread.rs | 34 ++++++++++++++++----------- src/thread.rs | 25 ++++++++------------ 6 files changed, 44 insertions(+), 33 deletions(-) diff --git a/rust-version b/rust-version index 71d06eff494..0bcadc0a366 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1603a70f82240ba2d27f72f964e36614d7620ad3 +20ffea6938b5839c390252e07940b99e3b6a889a diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 6ea10de0b8a..0ca838b2103 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -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)?; diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index bae3780b460..817bfc7d1cc 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -69,6 +69,15 @@ fn emulate_foreign_item_by_name( let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(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 "syscall" => { diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 35751d5818a..da8e8a63bfe 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -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. diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 1a8531e8804..22114eae672 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -84,11 +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> { 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 pthread_setname_np( + &mut self, + thread: Scalar, + name: Scalar, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + 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_thread_name(thread, name); + + Ok(Scalar::from_u32(0)) } fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { @@ -117,7 +133,7 @@ fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> // 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); + this.set_thread_name(this.get_active_thread(), name); } else if option == this.eval_libc_i32("PR_GET_NAME")? { if args.len() < 2 { throw_ub_format!( @@ -127,7 +143,7 @@ fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> } let address = this.read_pointer(&args[1])?; - let mut name = this.get_active_thread_name().to_vec(); + let mut name = this.get_thread_name(this.get_active_thread()).to_vec(); name.push(0u8); assert!(name.len() <= 16); this.write_bytes_ptr(address, name)?; @@ -138,16 +154,6 @@ fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> Ok(0) } - fn pthread_setname_np(&mut self, name: Pointer>) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - this.assert_target_os("macos", "pthread_setname_np"); - - let name = this.read_c_str(name)?.to_owned(); - this.set_active_thread_name(name); - - Ok(()) - } - fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/src/thread.rs b/src/thread.rs index 683694f482e..6f394fa42fc 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -69,9 +69,9 @@ fn from(id: u32) -> Self { } } -impl ThreadId { - pub fn to_u32_scalar(&self) -> Scalar { - Scalar::from_u32(self.0) +impl From 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) { - 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) { + 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) { + fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec) { 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] From 38a495346f89b04653b552e0aaff201065bd8038 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Aug 2022 19:04:44 -0400 Subject: [PATCH 2/3] remove prctl, now that std does not use it any more it is a terrible variadic function... --- src/shims/unix/linux/foreign_items.rs | 6 --- src/shims/unix/thread.rs | 47 ----------------------- tests/pass/libc.rs | 55 --------------------------- 3 files changed, 108 deletions(-) diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 817bfc7d1cc..8c569fb34bb 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -51,12 +51,6 @@ fn emulate_foreign_item_by_name( } // 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)?; diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 22114eae672..0df70543fac 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -107,53 +107,6 @@ fn pthread_setname_np( Ok(Scalar::from_u32(0)) } - fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { - 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_thread_name(this.get_active_thread(), 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_thread_name(this.get_active_thread()).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 sched_yield(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index b5848560214..f3aaccd5741 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -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"\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"))] From 96049ef88eb38af624134ee465d87eb91717b903 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Aug 2022 19:27:15 -0400 Subject: [PATCH 3/3] move a bunch of type information into the respective shim --- src/shims/time.rs | 21 ++-- src/shims/unix/foreign_items.rs | 8 +- src/shims/unix/fs.rs | 136 ++++++++++++++------------ src/shims/unix/linux/foreign_items.rs | 8 +- src/shims/unix/macos/foreign_items.rs | 20 ++-- src/shims/unix/sync.rs | 10 +- 6 files changed, 106 insertions(+), 97 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index d9edbe3d7bd..c3eb0161c21 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -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> { // 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> { 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> { 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( diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 0ca838b2103..3dea8f203bb 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -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)?; diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 951ddae2c14..2a6499ce999 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -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> { 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> { 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> { 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> { 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> { 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> { 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> { 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> { 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>> { + ) -> InterpResult<'tcx, Scalar> { 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: . 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)) } } } diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 8c569fb34bb..6881d829c15 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -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] = diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index da8e8a63bfe..fd7d5fb763e 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -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 diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 18226c2b8cf..69e632915b1 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -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> { 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> { 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(