Auto merge of #3756 - Mandragorian:gettid_support, r=RalfJung

Add `gettid` support

Add support for `gettid` in miri.

To ensure that the requirement that  `getpid() == gettdi()` for the main thread, we use the value returned by `getpid` and add to it the internal thread index.

Since `getpid` is only supported when isolation is disabled, and we want `gettid` to be used both in isolated and non-isolated executions, we modify `getpid` to return a hardcoded value (1000) when running in isolation mode.

Fixes #3730
This commit is contained in:
bors 2024-07-24 10:17:55 +00:00
commit 12cb742e82
6 changed files with 60 additions and 7 deletions

View file

@ -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 }
}
}

View file

@ -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)
}
}

View file

@ -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" => {

View file

@ -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)]

View file

@ -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() });
}

View file

@ -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);
}