Skip to content

Commit 21114c6

Browse files
committed
Print thread ID in panic message if thread name is unknown
`panic!` does not print any identifying information for threads that are unnamed. However, in many cases, the thread ID can be determined. This changes the panic message from something like this: thread '<unnamed>' panicked at src/main.rs:3:5: explicit panic To something like this: thread '<unnamed>' (1234) panicked at src/main.rs:3:5: explicit panic This change applies to both named and unnamed threads. There is no change for threads where an ID cannot be determined.
1 parent 31d0d21 commit 21114c6

24 files changed

+128
-22
lines changed

library/std/src/panicking.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ fn default_hook(info: &PanicHookInfo<'_>) {
269269

270270
thread::with_current_name(|name| {
271271
let name = name.unwrap_or("<unnamed>");
272+
let tid = thread::current_os_id().unwrap_or_default();
272273

273274
// Try to write the panic message to a buffer first to prevent other concurrent outputs
274275
// interleaving with it.
@@ -277,7 +278,7 @@ fn default_hook(info: &PanicHookInfo<'_>) {
277278

278279
let write_msg = |dst: &mut dyn crate::io::Write| {
279280
// We add a newline to ensure the panic message appears at the start of a line.
280-
writeln!(dst, "\nthread '{name}' panicked at {location}:\n{msg}")
281+
writeln!(dst, "\nthread '{name}' ({tid:#x}) panicked at {location}:\n{msg}")
281282
};
282283

283284
if write_msg(&mut cursor).is_ok() {

library/std/src/sys/pal/hermit/thread.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ impl Thread {
103103
}
104104
}
105105

106+
pub(crate) fn current_os_id() -> Option<u64> {
107+
None
108+
}
109+
106110
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
107111
unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) }
108112
}

library/std/src/sys/pal/itron/thread.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,10 @@ unsafe fn terminate_and_delete_current_task() -> ! {
349349
unsafe { crate::hint::unreachable_unchecked() };
350350
}
351351

352+
pub(crate) fn current_os_id() -> Option<u64> {
353+
None
354+
}
355+
352356
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
353357
super::unsupported()
354358
}

library/std/src/sys/pal/teeos/thread.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ impl Drop for Thread {
132132
}
133133
}
134134

135+
pub(crate) fn current_os_id() -> Option<u64> {
136+
None
137+
}
138+
135139
// Note: Both `sched_getaffinity` and `sysconf` are available but not functional on
136140
// teeos, so this function always returns an Error!
137141
pub fn available_parallelism() -> io::Result<NonZero<usize>> {

library/std/src/sys/pal/uefi/thread.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ impl Thread {
4444
}
4545
}
4646

47+
pub(crate) fn current_os_id() -> Option<u64> {
48+
None
49+
}
50+
4751
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
4852
// UEFI is single threaded
4953
Ok(NonZero::new(1).unwrap())

library/std/src/sys/pal/unix/thread.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,58 @@ impl Drop for Thread {
318318
}
319319
}
320320

321+
pub(crate) fn current_os_id() -> Option<u64> {
322+
// Most Unix platforms have a way to query an integer ID of the current thread, all with
323+
// slightly different spellings.
324+
cfg_select! {
325+
// Linux-like and some BSDs have methods to get the current `pid_t`, which is an `i32` on
326+
// these platforms.
327+
any(target_os = "android", target_os = "linux", target_os = "nto") => {
328+
// SAFETY: FFI call with no preconditions.
329+
let id: libc::pid_t = unsafe { libc::gettid() };
330+
Some(id as u64)
331+
}
332+
target_os = "openbsd" => {
333+
// SAFETY: FFI call with no preconditions.
334+
let id: libc::pid_t = unsafe { libc::getthrid() };
335+
Some(id as u64)
336+
}
337+
target_os = "freebsd" => {
338+
// SAFETY: FFI call with no preconditions.
339+
let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() };
340+
Some(id as u64)
341+
}
342+
343+
// Solaris, Illumos, and NetBSD are similar but their functions return a `u32`.
344+
any(target_os = "illumos", target_os = "solaris") => {
345+
// SAFETY: FFI call with no preconditions.
346+
let id: libc::thread_t = unsafe { libc::thr_self() };
347+
Some(id.into())
348+
}
349+
target_os = "netbsd" => {
350+
let id: libc::lwpid_t = unsafe { libc::_lwp_self() };
351+
Some(id.into())
352+
}
353+
354+
// Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread.
355+
target_family = "apple" => {
356+
let mut id = 0u64;
357+
// SAFETY: `thread_id` is a valid pointer, no other preconditions.
358+
let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) };
359+
if status == 0 {
360+
Some(id)
361+
} else {
362+
None
363+
}
364+
}
365+
366+
// As a fallback, return the pid which can be used to help identify a crashing process.
367+
_ => {
368+
Some(super::os::getpid().into())
369+
}
370+
}
371+
}
372+
321373
#[cfg(any(
322374
target_os = "linux",
323375
target_os = "nto",

library/std/src/sys/pal/unsupported/thread.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ impl Thread {
3131
}
3232
}
3333

34+
pub(crate) fn current_os_id() -> Option<u64> {
35+
None
36+
}
37+
3438
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
3539
unsupported()
3640
}

library/std/src/sys/pal/wasi/thread.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ impl Thread {
186186
}
187187
}
188188

189+
pub(crate) fn current_os_id() -> Option<u64> {
190+
None
191+
}
192+
189193
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
190194
cfg_if::cfg_if! {
191195
if #[cfg(target_feature = "atomics")] {

library/std/src/sys/pal/windows/c/bindings.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,6 +2177,7 @@ GetSystemInfo
21772177
GetSystemTimeAsFileTime
21782178
GetSystemTimePreciseAsFileTime
21792179
GetTempPathW
2180+
GetThreadId
21802181
GetUserProfileDirectoryW
21812182
GetWindowsDirectoryW
21822183
HANDLE

library/std/src/sys/pal/windows/stack_overflow.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POIN
2020
if code == c::EXCEPTION_STACK_OVERFLOW {
2121
thread::with_current_name(|name| {
2222
let name = name.unwrap_or("<unknown>");
23-
rtprintpanic!("\nthread '{name}' has overflowed its stack\n");
23+
let tid = thread::current_os_id().unwrap_or_default();
24+
rtprintpanic!("\nthread '{name}' ({tid:#x}) has overflowed its stack\n");
2425
});
2526
}
2627
c::EXCEPTION_CONTINUE_SEARCH

0 commit comments

Comments
 (0)