Skip to content

Commit 34e5d19

Browse files
Auto merge of #115746 - tgross35:unnamed-threads-panic-message, r=<try>
Print thread ID in panic message `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>' (0xff9bf) panicked at src/main.rs:3:5: explicit panic Stack overflow messages are updated as well. This change applies to both named and unnamed threads. The ID printed is the OS integer thread ID rather than the Rust thread ID, which should also be what debuggers print. try-job: `dist-various-*` try-job: `test-various-*` try-job: `x86_64-msvc-*`
2 parents fe5c95d + ad799ca commit 34e5d19

File tree

88 files changed

+242
-89
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+242
-89
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/stack_overflow.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ mod imp {
120120
&& thread_info.guard_page_range.contains(&fault_addr)
121121
{
122122
let name = thread_info.thread_name.as_deref().unwrap_or("<unknown>");
123-
rtprintpanic!("\nthread '{name}' has overflowed its stack\n");
123+
let tid = crate::thread::current_os_id().unwrap_or_default();
124+
rtprintpanic!("\nthread '{name}' ({tid:#x}) has overflowed its stack\n");
124125
rtabort!("stack overflow");
125126
}
126127
})
@@ -696,7 +697,8 @@ mod imp {
696697
if code == c::EXCEPTION_STACK_OVERFLOW {
697698
crate::thread::with_current_name(|name| {
698699
let name = name.unwrap_or("<unknown>");
699-
rtprintpanic!("\nthread '{name}' has overflowed its stack\n");
700+
let tid = crate::thread::current_os_id().unwrap_or_default();
701+
rtprintpanic!("\nthread '{name}' ({tid:#x}) has overflowed its stack\n");
700702
});
701703
}
702704
c::EXCEPTION_CONTINUE_SEARCH

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,55 @@ 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_if::cfg_if! {
325+
// Linux-like and some BSDs have methods to get the current `pid_t`, which is an `i32` on
326+
// these platforms.
327+
if #[cfg(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+
} else if #[cfg(target_os = "openbsd")] {
332+
// SAFETY: FFI call with no preconditions.
333+
let id: libc::pid_t = unsafe { libc::getthrid() };
334+
Some(id as u64)
335+
} else if #[cfg(target_os = "freebsd")] {
336+
// SAFETY: FFI call with no preconditions.
337+
let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() };
338+
Some(id as u64)
339+
}
340+
341+
// Solaris, Illumos, and NetBSD are similar but their functions return a `u32`.
342+
else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
343+
// SAFETY: FFI call with no preconditions.
344+
let id: libc::thread_t = unsafe { libc::thr_self() };
345+
Some(id.into())
346+
} else if #[cfg(target_os = "netbsd")] {
347+
let id: libc::lwpid_t = unsafe { libc::_lwp_self() };
348+
Some(id.into())
349+
}
350+
351+
// Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread.
352+
else if #[cfg(target_vendor = "apple")] {
353+
let mut id = 0u64;
354+
// SAFETY: `thread_id` is a valid pointer, no other preconditions.
355+
let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) };
356+
if status == 0 {
357+
Some(id)
358+
} else {
359+
None
360+
}
361+
}
362+
363+
// As a fallback, return the pid which can be used to help identify a crashing process.
364+
else {
365+
Some(super::os::getpid().into())
366+
}
367+
}
368+
}
369+
321370
#[cfg(any(
322371
target_os = "linux",
323372
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

0 commit comments

Comments
 (0)