Skip to content

Commit ec18aad

Browse files
authored
Merge pull request #4004 from YohDeadfall/thread-name-ice-fix
Get/set thread name shims return errors for invalid handles
2 parents b9aecc8 + 2a696cc commit ec18aad

File tree

12 files changed

+192
-109
lines changed

12 files changed

+192
-109
lines changed

src/concurrency/thread.rs

+21-23
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Implements threads.
22
33
use std::mem;
4-
use std::num::TryFromIntError;
54
use std::sync::atomic::Ordering::Relaxed;
65
use std::task::Poll;
76
use std::time::{Duration, SystemTime};
@@ -127,26 +126,6 @@ impl Idx for ThreadId {
127126
}
128127
}
129128

130-
impl TryFrom<u64> for ThreadId {
131-
type Error = TryFromIntError;
132-
fn try_from(id: u64) -> Result<Self, Self::Error> {
133-
u32::try_from(id).map(Self)
134-
}
135-
}
136-
137-
impl TryFrom<i128> for ThreadId {
138-
type Error = TryFromIntError;
139-
fn try_from(id: i128) -> Result<Self, Self::Error> {
140-
u32::try_from(id).map(Self)
141-
}
142-
}
143-
144-
impl From<u32> for ThreadId {
145-
fn from(id: u32) -> Self {
146-
Self(id)
147-
}
148-
}
149-
150129
impl From<ThreadId> for u64 {
151130
fn from(t: ThreadId) -> Self {
152131
t.0.into()
@@ -448,6 +427,10 @@ pub enum TimeoutAnchor {
448427
Absolute,
449428
}
450429

430+
/// An error signaling that the requested thread doesn't exist.
431+
#[derive(Debug, Copy, Clone)]
432+
pub struct ThreadNotFound;
433+
451434
/// A set of threads.
452435
#[derive(Debug)]
453436
pub struct ThreadManager<'tcx> {
@@ -509,6 +492,16 @@ impl<'tcx> ThreadManager<'tcx> {
509492
}
510493
}
511494

495+
pub fn thread_id_try_from(&self, id: impl TryInto<u32>) -> Result<ThreadId, ThreadNotFound> {
496+
if let Ok(id) = id.try_into()
497+
&& usize::try_from(id).is_ok_and(|id| id < self.threads.len())
498+
{
499+
Ok(ThreadId(id))
500+
} else {
501+
Err(ThreadNotFound)
502+
}
503+
}
504+
512505
/// Check if we have an allocation for the given thread local static for the
513506
/// active thread.
514507
fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option<StrictPointer> {
@@ -534,6 +527,7 @@ impl<'tcx> ThreadManager<'tcx> {
534527
) -> &mut Vec<Frame<'tcx, Provenance, FrameExtra<'tcx>>> {
535528
&mut self.threads[self.active_thread].stack
536529
}
530+
537531
pub fn all_stacks(
538532
&self,
539533
) -> impl Iterator<Item = (ThreadId, &[Frame<'tcx, Provenance, FrameExtra<'tcx>>])> {
@@ -868,6 +862,11 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
868862
// Public interface to thread management.
869863
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
870864
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
865+
#[inline]
866+
fn thread_id_try_from(&self, id: impl TryInto<u32>) -> Result<ThreadId, ThreadNotFound> {
867+
self.eval_context_ref().machine.threads.thread_id_try_from(id)
868+
}
869+
871870
/// Get a thread-specific allocation id for the given thread-local static.
872871
/// If needed, allocate a new one.
873872
fn get_or_create_thread_local_alloc(
@@ -1160,8 +1159,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
11601159
/// Set the name of the current thread. The buffer must not include the null terminator.
11611160
#[inline]
11621161
fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec<u8>) {
1163-
let this = self.eval_context_mut();
1164-
this.machine.threads.set_thread_name(thread, new_thread_name);
1162+
self.eval_context_mut().machine.threads.set_thread_name(thread, new_thread_name);
11651163
}
11661164

11671165
#[inline]

src/shims/unix/android/thread.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_abi::{ExternAbi, Size};
22
use rustc_span::Symbol;
33

44
use crate::helpers::check_min_arg_count;
5-
use crate::shims::unix::thread::EvalContextExt as _;
5+
use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult};
66
use crate::*;
77

88
const TASK_COMM_LEN: usize = 16;
@@ -32,7 +32,7 @@ pub fn prctl<'tcx>(
3232
// https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html
3333
let res =
3434
this.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?;
35-
assert!(res);
35+
assert_eq!(res, ThreadNameResult::Ok);
3636
Scalar::from_u32(0)
3737
}
3838
op if op == pr_get_name => {
@@ -46,7 +46,7 @@ pub fn prctl<'tcx>(
4646
CheckInAllocMsg::MemoryAccessTest,
4747
)?;
4848
let res = this.pthread_getname_np(thread, name, len, /* truncate*/ false)?;
49-
assert!(res);
49+
assert_eq!(res, ThreadNameResult::Ok);
5050
Scalar::from_u32(0)
5151
}
5252
op => throw_unsup_format!("Miri does not support `prctl` syscall with op={}", op),

src/shims/unix/foreign_items.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -603,13 +603,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
603603
}
604604
"pthread_join" => {
605605
let [thread, retval] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
606-
this.pthread_join(thread, retval)?;
607-
this.write_null(dest)?;
606+
let res = this.pthread_join(thread, retval)?;
607+
this.write_scalar(res, dest)?;
608608
}
609609
"pthread_detach" => {
610610
let [thread] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
611-
this.pthread_detach(thread)?;
612-
this.write_null(dest)?;
611+
let res = this.pthread_detach(thread)?;
612+
this.write_scalar(res, dest)?;
613613
}
614614
"pthread_self" => {
615615
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;

src/shims/unix/linux/foreign_items.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
8181
"pthread_setname_np" => {
8282
let [thread, name] =
8383
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
84-
let res = this.pthread_setname_np(
84+
let res = match this.pthread_setname_np(
8585
this.read_scalar(thread)?,
8686
this.read_scalar(name)?,
8787
TASK_COMM_LEN,
8888
/* truncate */ false,
89-
)?;
90-
let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") };
89+
)? {
90+
ThreadNameResult::Ok => Scalar::from_u32(0),
91+
ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"),
92+
// Act like we faild to open `/proc/self/task/$tid/comm`.
93+
ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"),
94+
};
9195
this.write_scalar(res, dest)?;
9296
}
9397
"pthread_getname_np" => {
@@ -97,14 +101,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
97101
// In case of glibc, the length of the output buffer must
98102
// be not shorter than TASK_COMM_LEN.
99103
let len = this.read_scalar(len)?;
100-
let res = if len.to_target_usize(this)? >= TASK_COMM_LEN as u64
101-
&& this.pthread_getname_np(
104+
let res = if len.to_target_usize(this)? >= TASK_COMM_LEN as u64 {
105+
match this.pthread_getname_np(
102106
this.read_scalar(thread)?,
103107
this.read_scalar(name)?,
104108
len,
105109
/* truncate*/ false,
106110
)? {
107-
Scalar::from_u32(0)
111+
ThreadNameResult::Ok => Scalar::from_u32(0),
112+
ThreadNameResult::NameTooLong => unreachable!(),
113+
// Act like we faild to open `/proc/self/task/$tid/comm`.
114+
ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"),
115+
}
108116
} else {
109117
this.eval_libc("ERANGE")
110118
};

src/shims/unix/macos/foreign_items.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -181,18 +181,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
181181
// are met, then the name is set and 0 is returned. Otherwise, if
182182
// the specified name is lomnger than MAXTHREADNAMESIZE, then
183183
// ENAMETOOLONG is returned.
184-
//
185-
// FIXME: the real implementation maybe returns ESRCH if the thread ID is invalid.
186184
let thread = this.pthread_self()?;
187-
let res = if this.pthread_setname_np(
185+
let res = match this.pthread_setname_np(
188186
thread,
189187
this.read_scalar(name)?,
190188
this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?.try_into().unwrap(),
191189
/* truncate */ false,
192190
)? {
193-
Scalar::from_u32(0)
194-
} else {
195-
this.eval_libc("ENAMETOOLONG")
191+
ThreadNameResult::Ok => Scalar::from_u32(0),
192+
ThreadNameResult::NameTooLong => this.eval_libc("ENAMETOOLONG"),
193+
ThreadNameResult::ThreadNotFound => unreachable!(),
196194
};
197195
// Contrary to the manpage, `pthread_setname_np` on macOS still
198196
// returns an integer indicating success.
@@ -210,15 +208,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
210208
// https://github.com/apple-oss-distributions/libpthread/blob/c032e0b076700a0a47db75528a282b8d3a06531a/src/pthread.c#L1160-L1175.
211209
// The key part is the strlcpy, which truncates the resulting value,
212210
// but always null terminates (except for zero sized buffers).
213-
//
214-
// FIXME: the real implementation returns ESRCH if the thread ID is invalid.
215-
let res = Scalar::from_u32(0);
216-
this.pthread_getname_np(
211+
let res = match this.pthread_getname_np(
217212
this.read_scalar(thread)?,
218213
this.read_scalar(name)?,
219214
this.read_scalar(len)?,
220215
/* truncate */ true,
221-
)?;
216+
)? {
217+
ThreadNameResult::Ok => Scalar::from_u32(0),
218+
// `NameTooLong` is possible when the buffer is zero sized,
219+
ThreadNameResult::NameTooLong => Scalar::from_u32(0),
220+
ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
221+
};
222222
this.write_scalar(res, dest)?;
223223
}
224224

src/shims/unix/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub use self::fs::{DirTable, EvalContextExt as _};
2121
pub use self::linux::epoll::EpollInterestTable;
2222
pub use self::mem::EvalContextExt as _;
2323
pub use self::sync::EvalContextExt as _;
24-
pub use self::thread::EvalContextExt as _;
24+
pub use self::thread::{EvalContextExt as _, ThreadNameResult};
2525
pub use self::unnamed_socket::EvalContextExt as _;
2626

2727
// Make up some constants.

src/shims/unix/solarish/foreign_items.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
2626
// THREAD_NAME_MAX allows a thread name of 31+1 length
2727
// https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613
2828
let max_len = 32;
29-
let res = this.pthread_setname_np(
29+
// See https://illumos.org/man/3C/pthread_setname_np for the error codes.
30+
let res = match this.pthread_setname_np(
3031
this.read_scalar(thread)?,
3132
this.read_scalar(name)?,
3233
max_len,
3334
/* truncate */ false,
34-
)?;
35-
let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") };
35+
)? {
36+
ThreadNameResult::Ok => Scalar::from_u32(0),
37+
ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"),
38+
ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
39+
};
3640
this.write_scalar(res, dest)?;
3741
}
3842
"pthread_getname_np" => {
3943
let [thread, name, len] =
4044
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
41-
// https://github.com/illumos/illumos-gate/blob/c56822be04b6c157c8b6f2281e47214c3b86f657/usr/src/lib/libc/port/threads/thr.c#L2449-L2480
42-
let res = this.pthread_getname_np(
45+
// See https://illumos.org/man/3C/pthread_getname_np for the error codes.
46+
let res = match this.pthread_getname_np(
4347
this.read_scalar(thread)?,
4448
this.read_scalar(name)?,
4549
this.read_scalar(len)?,
4650
/* truncate */ false,
47-
)?;
48-
let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") };
51+
)? {
52+
ThreadNameResult::Ok => Scalar::from_u32(0),
53+
ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"),
54+
ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
55+
};
4956
this.write_scalar(res, dest)?;
5057
}
5158

0 commit comments

Comments
 (0)