Skip to content

Commit 2b62867

Browse files
authored
Rollup merge of rust-lang#127918 - ChrisDenton:thread-name-string, r=joboet
Safely enforce thread name requirements The requirements for the thread name to be both UTF-8 and null terminated are easily enforced by a wrapper type so lets do that. The fact this used to be just a bare `CString` has tripped me up before because it was entirely safe to use a non UTF-8 `CString`.
2 parents a077eb1 + 8378261 commit 2b62867

File tree

1 file changed

+51
-23
lines changed

1 file changed

+51
-23
lines changed

std/src/thread/mod.rs

+51-23
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ mod tests;
161161
use crate::any::Any;
162162
use crate::cell::{Cell, OnceCell, UnsafeCell};
163163
use crate::env;
164-
use crate::ffi::{CStr, CString};
164+
use crate::ffi::CStr;
165165
use crate::fmt;
166166
use crate::io;
167167
use crate::marker::PhantomData;
@@ -487,11 +487,7 @@ impl Builder {
487487
amt
488488
});
489489

490-
let my_thread = name.map_or_else(Thread::new_unnamed, |name| unsafe {
491-
Thread::new(
492-
CString::new(name).expect("thread name may not contain interior null bytes"),
493-
)
494-
});
490+
let my_thread = name.map_or_else(Thread::new_unnamed, Thread::new);
495491
let their_thread = my_thread.clone();
496492

497493
let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
@@ -1299,10 +1295,51 @@ impl ThreadId {
12991295
/// The internal representation of a `Thread`'s name.
13001296
enum ThreadName {
13011297
Main,
1302-
Other(CString),
1298+
Other(ThreadNameString),
13031299
Unnamed,
13041300
}
13051301

1302+
// This module ensures private fields are kept private, which is necessary to enforce the safety requirements.
1303+
mod thread_name_string {
1304+
use super::ThreadName;
1305+
use crate::ffi::{CStr, CString};
1306+
use core::str;
1307+
1308+
/// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated.
1309+
pub(crate) struct ThreadNameString {
1310+
inner: CString,
1311+
}
1312+
impl core::ops::Deref for ThreadNameString {
1313+
type Target = CStr;
1314+
fn deref(&self) -> &CStr {
1315+
&self.inner
1316+
}
1317+
}
1318+
impl From<String> for ThreadNameString {
1319+
fn from(s: String) -> Self {
1320+
Self {
1321+
inner: CString::new(s).expect("thread name may not contain interior null bytes"),
1322+
}
1323+
}
1324+
}
1325+
impl ThreadName {
1326+
pub fn as_cstr(&self) -> Option<&CStr> {
1327+
match self {
1328+
ThreadName::Main => Some(c"main"),
1329+
ThreadName::Other(other) => Some(other),
1330+
ThreadName::Unnamed => None,
1331+
}
1332+
}
1333+
1334+
pub fn as_str(&self) -> Option<&str> {
1335+
// SAFETY: `as_cstr` can only return `Some` for a fixed CStr or a `ThreadNameString`,
1336+
// which is guaranteed to be UTF-8.
1337+
self.as_cstr().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
1338+
}
1339+
}
1340+
}
1341+
pub(crate) use thread_name_string::ThreadNameString;
1342+
13061343
/// The internal representation of a `Thread` handle
13071344
struct Inner {
13081345
name: ThreadName, // Guaranteed to be UTF-8
@@ -1342,25 +1379,20 @@ pub struct Thread {
13421379

13431380
impl Thread {
13441381
/// Used only internally to construct a thread object without spawning.
1345-
///
1346-
/// # Safety
1347-
/// `name` must be valid UTF-8.
1348-
pub(crate) unsafe fn new(name: CString) -> Thread {
1349-
unsafe { Self::new_inner(ThreadName::Other(name)) }
1382+
pub(crate) fn new(name: String) -> Thread {
1383+
Self::new_inner(ThreadName::Other(name.into()))
13501384
}
13511385

13521386
pub(crate) fn new_unnamed() -> Thread {
1353-
unsafe { Self::new_inner(ThreadName::Unnamed) }
1387+
Self::new_inner(ThreadName::Unnamed)
13541388
}
13551389

13561390
// Used in runtime to construct main thread
13571391
pub(crate) fn new_main() -> Thread {
1358-
unsafe { Self::new_inner(ThreadName::Main) }
1392+
Self::new_inner(ThreadName::Main)
13591393
}
13601394

1361-
/// # Safety
1362-
/// If `name` is `ThreadName::Other(_)`, the contained string must be valid UTF-8.
1363-
unsafe fn new_inner(name: ThreadName) -> Thread {
1395+
fn new_inner(name: ThreadName) -> Thread {
13641396
// We have to use `unsafe` here to construct the `Parker` in-place,
13651397
// which is required for the UNIX implementation.
13661398
//
@@ -1483,15 +1515,11 @@ impl Thread {
14831515
#[stable(feature = "rust1", since = "1.0.0")]
14841516
#[must_use]
14851517
pub fn name(&self) -> Option<&str> {
1486-
self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
1518+
self.inner.name.as_str()
14871519
}
14881520

14891521
fn cname(&self) -> Option<&CStr> {
1490-
match &self.inner.name {
1491-
ThreadName::Main => Some(c"main"),
1492-
ThreadName::Other(other) => Some(&other),
1493-
ThreadName::Unnamed => None,
1494-
}
1522+
self.inner.name.as_cstr()
14951523
}
14961524
}
14971525

0 commit comments

Comments
 (0)