diff options
| author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2022-10-25 14:43:15 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-10-25 14:43:15 +0530 |
| commit | 75023d61a191a0edf38e13f82bc88cddb2eb5f95 (patch) | |
| tree | c022a67d3ab3ea4c1f6994bc92c22ca26dbbd1b8 /library/std/src | |
| parent | 8ba2a651fb16f5d0f54c961e0ae925c9bad2fafb (diff) | |
| parent | 15cfeb33b08c91090d52685651aa9762b8f3c43f (diff) | |
| download | rust-75023d61a191a0edf38e13f82bc88cddb2eb5f95.tar.gz rust-75023d61a191a0edf38e13f82bc88cddb2eb5f95.zip | |
Rollup merge of #103379 - cuviper:truncate-thread-name, r=thomcc
Truncate thread names on Linux and Apple targets These targets have system limits on the thread names, 16 and 64 bytes respectively, and `pthread_setname_np` returns an error if the name is longer. However, we're not in a context that can propagate errors when we call this, and we used to implicitly truncate on Linux with `prctl`, so now we manually truncate these names ahead of time. r? ``````@thomcc``````
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/sys/unix/thread.rs | 18 | ||||
| -rw-r--r-- | library/std/src/thread/tests.rs | 31 |
2 files changed, 49 insertions, 0 deletions
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 42ac6fcd8bf..69cd2b500a1 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -132,8 +132,11 @@ impl Thread { #[cfg(target_os = "linux")] pub fn set_name(name: &CStr) { + const TASK_COMM_LEN: usize = 16; + unsafe { // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20. + let name = truncate_cstr(name, TASK_COMM_LEN); libc::pthread_setname_np(libc::pthread_self(), name.as_ptr()); } } @@ -148,6 +151,7 @@ impl Thread { #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] pub fn set_name(name: &CStr) { unsafe { + let name = truncate_cstr(name, libc::MAXTHREADNAMESIZE); libc::pthread_setname_np(name.as_ptr()); } } @@ -276,6 +280,20 @@ impl Drop for Thread { } } +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))] +fn truncate_cstr(cstr: &CStr, max_with_nul: usize) -> crate::borrow::Cow<'_, CStr> { + use crate::{borrow::Cow, ffi::CString}; + + if cstr.to_bytes_with_nul().len() > max_with_nul { + let bytes = cstr.to_bytes()[..max_with_nul - 1].to_vec(); + // SAFETY: the non-nul bytes came straight from a CStr. + // (CString will add the terminating nul.) + Cow::Owned(unsafe { CString::from_vec_unchecked(bytes) }) + } else { + Cow::Borrowed(cstr) + } +} + pub fn available_parallelism() -> io::Result<NonZeroUsize> { cfg_if::cfg_if! { if #[cfg(any( diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index dfb8765ab4e..6c9ce6fa0dd 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -37,6 +37,37 @@ fn test_named_thread() { .unwrap(); } +#[cfg(any( + // Note: musl didn't add pthread_getname_np until 1.2.3 + all(target_os = "linux", target_env = "gnu"), + target_os = "macos", + target_os = "ios", + target_os = "watchos" +))] +#[test] +fn test_named_thread_truncation() { + use crate::ffi::CStr; + + let long_name = crate::iter::once("test_named_thread_truncation") + .chain(crate::iter::repeat(" yada").take(100)) + .collect::<String>(); + + let result = Builder::new().name(long_name.clone()).spawn(move || { + // Rust remembers the full thread name itself. + assert_eq!(thread::current().name(), Some(long_name.as_str())); + + // But the system is limited -- make sure we successfully set a truncation. + let mut buf = vec![0u8; long_name.len() + 1]; + unsafe { + libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len()); + } + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + assert!(cstr.to_bytes().len() > 0); + assert!(long_name.as_bytes().starts_with(cstr.to_bytes())); + }); + result.unwrap().join().unwrap(); +} + #[test] #[should_panic] fn test_invalid_named_thread() { |
