diff --git a/src/tools/miri/src/concurrency/blocking_io.rs b/src/tools/miri/src/concurrency/blocking_io.rs index ba1e52cd3971..35d7474347ab 100644 --- a/src/tools/miri/src/concurrency/blocking_io.rs +++ b/src/tools/miri/src/concurrency/blocking_io.rs @@ -219,7 +219,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); this.machine.blocking_io.register( source_fd, - InterestReceiver::UnblockThread(this.machine.threads.active_thread()), + InterestReceiver::UnblockThread(this.active_thread()), interests, ); this.block_thread(BlockReason::IO, timeout, callback); diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 7af081fc9c76..cfc94abb6898 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -1,3 +1,4 @@ +use std::assert_matches; use std::ffi::{OsStr, OsString}; use rustc_data_structures::fx::FxHashMap; @@ -108,32 +109,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if this.machine.communicate() { std::process::id() } else { 1000 } } - /// Get an "OS" thread ID for the current thread. - fn get_current_tid(&self) -> u32 { + /// Get an "OS" thread ID for any thread. + fn get_tid(&self, thread: ThreadId) -> u32 { let this = self.eval_context_ref(); - self.get_tid(this.machine.threads.active_thread()) + assert!(this.target_os_is_unix()); + // On Linux, the main thread has PID == TID so we uphold this. For simplicity we do it + // everywhere. That also ensures this ID is different from what is returned by + // `pthread_self`. + this.get_pid().strict_add(thread.to_u32()) } /// Convert TID back to a `ThreadId`, or `None` if it is invalid or the thread has terminated. fn get_thread_id_from_linux_tid(&self, tid: u32) -> Option { let this = self.eval_context_ref(); - debug_assert!(matches!(this.tcx.sess.target.os, Os::Linux | Os::Android)); + assert_matches!(this.tcx.sess.target.os, Os::Linux | Os::Android); // TID = PID + thread_index => index = TID - PID. let id = tid.checked_sub(this.get_pid())?; this.machine.threads.thread_id_try_from(id).ok() } - - /// Get an "OS" thread ID for any thread. - fn get_tid(&self, thread: ThreadId) -> u32 { - let this = self.eval_context_ref(); - let index = thread.to_u32(); - let target_os = &this.tcx.sess.target.os; - if matches!(target_os, Os::Linux | Os::Android) { - // On Linux, the main thread has PID == TID so we uphold this. - this.get_pid().strict_add(index) - } else { - // Other platforms do not display any relationship between PID and TID. - index - } - } } diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 488d82f2109a..97cc0d8eacf5 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -269,7 +269,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // For most platforms the return type is an `i32`, but some are unsigned. The TID // will always be positive so we don't need to differentiate. - interp_ok(Scalar::from_u32(this.get_current_tid())) + interp_ok(Scalar::from_u32(this.get_tid(this.active_thread()))) } /// `fields_size`, if present, says how large each field of the struct is. @@ -323,7 +323,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// allows querying the ID for arbitrary threads, identified by their pthread_t. /// /// API documentation: . - fn apple_pthread_threadip_np( + fn apple_pthread_threadid_np( &mut self, thread_op: &OpTy<'tcx>, tid_op: &OpTy<'tcx>, @@ -349,6 +349,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { thread }; + // This returns an `int`, not a `pthread_t`, so we treat it like we treat `gettid` on Linux. let tid = this.get_tid(thread); let tid_dest = this.deref_pointer_as(tid_op, this.machine.layouts.u64)?; this.write_int(tid, &tid_dest)?; diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 4b40ce0f6eff..dc2ce5da2828 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -180,6 +180,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &[Os::Linux, Os::Android, Os::MacOs, Os::Solaris, Os::Illumos], link_name, )?; + let [uname] = this.check_shim_sig( shim_sig!(extern "C" fn(*mut _) -> i32), link_name, @@ -296,6 +297,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "flock" => { // Currently this function does not exist on all Unixes, e.g. on Solaris. this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::MacOs, Os::Illumos], link_name)?; + let [fd, op] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, i32) -> i32), link_name, @@ -495,6 +497,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &[Os::Linux, Os::FreeBsd, Os::Solaris, Os::Illumos, Os::Android], link_name, )?; + let [fd, offset, len] = this.check_shim_sig( shim_sig!(extern "C" fn(i32, libc::off_t, libc::off_t) -> i32), link_name, @@ -560,6 +563,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &[Os::Linux, Os::Android, Os::FreeBsd, Os::Solaris, Os::Illumos], link_name, )?; + let [pipefd, flags] = this.check_shim_sig( shim_sig!(extern "C" fn(*mut _, i32) -> i32), link_name, @@ -743,6 +747,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "reallocarray" => { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?; + let [ptr, nmemb, size] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; @@ -1020,6 +1025,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &[Os::FreeBsd, Os::Linux, Os::Android, Os::Solaris, Os::Illumos], link_name, )?; + let [clock_id, flags, req, rem] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let result = this.clock_nanosleep(clock_id, flags, req, rem)?; @@ -1028,6 +1034,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "sched_getaffinity" => { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?; + let [pid, cpusetsize, mask] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let pid = this.read_scalar(pid)?.to_u32()?; @@ -1072,6 +1079,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "sched_setaffinity" => { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?; + let [pid, cpusetsize, mask] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let pid = this.read_scalar(pid)?.to_u32()?; @@ -1140,6 +1148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &[Os::Linux, Os::MacOs, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android], link_name, )?; + let [buf, bufsize] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let buf = this.read_pointer(buf)?; @@ -1172,6 +1181,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android], link_name, )?; + let [ptr, len, flags] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; @@ -1185,6 +1195,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This function is non-standard but exists with the same signature and // same behavior (eg never fails) on FreeBSD and Solaris/Illumos. this.check_target_os(&[Os::FreeBsd, Os::Illumos, Os::Solaris], link_name)?; + let [ptr, len] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; @@ -1208,6 +1219,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &[Os::Linux, Os::FreeBsd, Os::Illumos, Os::Solaris, Os::Android, Os::MacOs], link_name, )?; + // This function looks and behaves exactly like miri_start_unwind. let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; this.handle_miri_start_unwind(payload)?; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index ac56ffef8f8f..a979c88def78 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -244,7 +244,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "pthread_threadid_np" => { let [thread, tid_ptr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let res = this.apple_pthread_threadip_np(thread, tid_ptr)?; + let res = this.apple_pthread_threadid_np(thread, tid_ptr)?; this.write_scalar(res, dest)?; } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 16e269c68880..c378312633f2 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -953,8 +953,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(), _ => this.invalid_handle("GetThreadDescription")?, }; - let tid = this.get_tid(thread); - this.write_scalar(Scalar::from_u32(tid), dest)?; + this.write_scalar(Scalar::from_u32(thread.to_u32()), dest)?; } "GetCurrentThreadId" => { let [] = this.check_shim_sig( @@ -963,9 +962,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { abi, args, )?; - let thread = this.active_thread(); - let tid = this.get_tid(thread); - this.write_scalar(Scalar::from_u32(tid), dest)?; + this.write_scalar(Scalar::from_u32(this.active_thread().to_u32()), dest)?; } // Miscellaneous diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 4389e37577f0..9a032151a543 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -184,7 +184,8 @@ impl Handle { match Self::from_packed(handle) { Some(Self::Thread(thread)) => { - // Validate the thread id. Windows handles remain valid even after thread termination + // Validate the thread id. Windows handles remain valid even after thread + // termination. use crate::concurrency::thread::ThreadLookupError; match cx.machine.threads.thread_id_try_from(thread.to_u32()) { Ok(id) | Err(ThreadLookupError::Terminated(id)) => diff --git a/src/tools/miri/tests/pass-dep/shims/gettid.rs b/src/tools/miri/tests/pass-dep/shims/gettid.rs index 9d5ff0dc5dae..0dce7bdc0c52 100644 --- a/src/tools/miri/tests/pass-dep/shims/gettid.rs +++ b/src/tools/miri/tests/pass-dep/shims/gettid.rs @@ -165,8 +165,13 @@ fn main() { // The value is not important, we only care that whatever the value is, // won't change from execution to execution. if cfg!(with_isolation) { - if cfg!(any(target_os = "linux", target_os = "android")) { - // Linux starts the TID at the PID, which is 1000. + if cfg!(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "macos" + )) { + // On these OSes we start the TID at the PID, which is 1000. assert_eq!(tid, 1000); } else { // Other platforms start counting from 0. @@ -174,7 +179,7 @@ fn main() { } } - // On Linux, the first TID is the PID. + // On Linux, the main thread TID is the PID. #[cfg(any(target_os = "linux", target_os = "android"))] assert_eq!(tid, unsafe { libc::getpid() } as u64);