Description
Thread
(or well Inner
) has the following invariant:
rust/library/std/src/thread/mod.rs
Line 1252 in d009f60
and relies on it for soundness:
rust/library/std/src/thread/mod.rs
Line 1413 in d009f60
Starting with #121666, this invariant can be broken, because the native thread names are not required to be UTF-8. So for example, this code is unsound:
use std::mem::MaybeUninit;
use std::ptr;
use std::thread;
extern "C" fn foreign(_arg: *mut libc::c_void) -> *mut libc::c_void {
unsafe {
let id = libc::pthread_self();
let r = libc::pthread_setname_np(id, [0xff, 0].as_ptr().cast());
assert_eq!(r, 0);
}
let current = thread::current();
println!("{:?}", current.name().unwrap().chars()); // Whoops!
ptr::null_mut()
}
fn main() {
unsafe {
let mut id = MaybeUninit::uninit();
let r = libc::pthread_create(id.as_mut_ptr(), ptr::null(), foreign, ptr::null_mut());
assert_eq!(r, 0);
let id = id.assume_init();
let r = libc::pthread_join(id, ptr::null_mut());
assert_eq!(r, 0);
}
}
(run with miri and --target x86_64-unknown-linux-gnu
)
This can even be exploited in entirely safe code. On platforms with key-based thread locals, the Thread
handle is initialized with the system thread name when accessed in TLS destructors. On all UNIXes except macOS, the main thread name is the name of the program. So if you spawn a program with a bad name on these platforms (e.g. Illumos), calling thread::current().name()
will cause UB.
We can fix this by checking the thread name in Thread::new
, and not using it if it is bad. In the long-term, a function like os_name
might be nice and perhaps fix some other issues as well.
CC @ChrisDenton