about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKonstantinos Andrikopoulos <andrikopoulos@google.com>2024-07-20 11:28:48 +0200
committerKonstantinos Andrikopoulos <andrikopoulos@google.com>2024-07-24 12:10:05 +0200
commita0088d7a813a1f63e5af4d6edc5d2c50a0b3702e (patch)
tree3b682c3656192d814d8aca44da9b7c7e8b97c1e6
parent0b22f0c13d3151622200c62726600f1a805ac37e (diff)
Allow getpid in isolation mode, add gettid support
In order to support gettid when isolation is enabled and when it is
disabled, and satisfy its requirement that:

   In a single-threaded process, the thread ID is equal to the process ID
   (PID, as returned by getpid(2)).

we define the thread ID to be getpid() + <miri internal thread id>.
Since the internal thread id of the main thread is zero, this will
satisfy that requirement.

However, getpid for now was only supported when isolation was disabled.
To support getpid in isolation mode, we return a hardcoded value (1000)
and return that instead of the real PID.
-rw-r--r--src/tools/miri/src/shims/env.rs5
-rw-r--r--src/tools/miri/src/shims/unix/env.rs17
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs5
-rw-r--r--src/tools/miri/src/shims/windows/env.rs3
-rw-r--r--src/tools/miri/tests/pass-dep/libc/gettid.rs22
-rw-r--r--src/tools/miri/tests/pass/getpid.rs15
6 files changed, 60 insertions, 7 deletions
diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs
index 7ad395cccb7..6586ea8e48c 100644
--- a/src/tools/miri/src/shims/env.rs
+++ b/src/tools/miri/src/shims/env.rs
@@ -108,4 +108,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             EnvVars::Windows(vars) => vars.get(name),
         }
     }
+
+    fn get_pid(&self) -> u32 {
+        let this = self.eval_context_ref();
+        if this.machine.communicate() { std::process::id() } else { 1000 }
+    }
 }
diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs
index 405431f4327..3b8ad65195b 100644
--- a/src/tools/miri/src/shims/unix/env.rs
+++ b/src/tools/miri/src/shims/unix/env.rs
@@ -274,12 +274,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         this.assert_target_os_is_unix("getpid");
 
-        this.check_no_isolation("`getpid`")?;
-
         // The reason we need to do this wacky of a conversion is because
         // `libc::getpid` returns an i32, however, `std::process::id()` return an u32.
         // So we un-do the conversion that stdlib does and turn it back into an i32.
         #[allow(clippy::cast_possible_wrap)]
-        Ok(std::process::id() as i32)
+        Ok(this.get_pid() as i32)
+    }
+
+    fn linux_gettid(&mut self) -> InterpResult<'tcx, i32> {
+        let this = self.eval_context_ref();
+        this.assert_target_os("linux", "gettid");
+
+        let index = this.machine.threads.active_thread().to_u32();
+
+        // Compute a TID for this thread, ensuring that the main thread has PID == TID.
+        let tid = this.get_pid().strict_add(index);
+
+        #[allow(clippy::cast_possible_wrap)]
+        Ok(tid as i32)
     }
 }
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index 95bee38cd78..20c6a234794 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -94,6 +94,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 )?;
                 this.write_scalar(res, dest)?;
             }
+            "gettid" => {
+                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let result = this.linux_gettid()?;
+                this.write_scalar(Scalar::from_i32(result), dest)?;
+            }
 
             // Dynamically invoked syscalls
             "syscall" => {
diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs
index ed3eb697986..77ae06bd5c2 100644
--- a/src/tools/miri/src/shims/windows/env.rs
+++ b/src/tools/miri/src/shims/windows/env.rs
@@ -200,9 +200,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, u32> {
         let this = self.eval_context_mut();
         this.assert_target_os("windows", "GetCurrentProcessId");
-        this.check_no_isolation("`GetCurrentProcessId`")?;
 
-        Ok(std::process::id())
+        Ok(this.get_pid())
     }
 
     #[allow(non_snake_case)]
diff --git a/src/tools/miri/tests/pass-dep/libc/gettid.rs b/src/tools/miri/tests/pass-dep/libc/gettid.rs
new file mode 100644
index 00000000000..87405b02ac3
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/gettid.rs
@@ -0,0 +1,22 @@
+//@only-target-linux
+//@revisions: with_isolation without_isolation
+//@[without_isolation] compile-flags: -Zmiri-disable-isolation
+
+use libc::{getpid, gettid};
+use std::thread;
+
+fn main() {
+    thread::spawn(|| {
+        // Test that in isolation mode a deterministic value will be returned.
+        // The value 1001 is not important, we only care that whatever the value
+        // is, won't change from execution to execution.
+        #[cfg(with_isolation)]
+        assert_eq!(unsafe { gettid() }, 1001);
+
+        assert_ne!(unsafe { gettid() }, unsafe { getpid() });
+    });
+
+    // Test that the thread ID of the main thread is the same as the process
+    // ID.
+    assert_eq!(unsafe { gettid() }, unsafe { getpid() });
+}
diff --git a/src/tools/miri/tests/pass/getpid.rs b/src/tools/miri/tests/pass/getpid.rs
index 733545462eb..f350fafff4a 100644
--- a/src/tools/miri/tests/pass/getpid.rs
+++ b/src/tools/miri/tests/pass/getpid.rs
@@ -1,9 +1,20 @@
-//@compile-flags: -Zmiri-disable-isolation
+//@revisions: with_isolation without_isolation
+//@[without_isolation] compile-flags: -Zmiri-disable-isolation
 
 fn getpid() -> u32 {
     std::process::id()
 }
 
 fn main() {
-    getpid();
+    let pid = getpid();
+
+    std::thread::spawn(move || {
+        assert_eq!(getpid(), pid);
+    });
+
+    // Test that in isolation mode a deterministic value will be returned.
+    // The value 1000 is not important, we only care that whatever the value
+    // is, won't change from execution to execution.
+    #[cfg(with_isolation)]
+    assert_eq!(pid, 1000);
 }