Skip to content

Commit 639fab7

Browse files
committed
Auto merge of rust-lang#3345 - RalfJung:win-get-thread-name, r=RalfJung
Windows: support getting the thread name Also organize the thread name tests a bit.
2 parents cdf1071 + c72b487 commit 639fab7

File tree

11 files changed

+145
-44
lines changed

11 files changed

+145
-44
lines changed

src/tools/miri/src/concurrency/data_race.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ impl VClockAlloc {
812812
| MiriMemoryKind::Miri
813813
| MiriMemoryKind::C
814814
| MiriMemoryKind::WinHeap
815+
| MiriMemoryKind::WinLocal
815816
| MiriMemoryKind::Mmap,
816817
)
817818
| MemoryKind::Stack => {
@@ -820,7 +821,8 @@ impl VClockAlloc {
820821
alloc_timestamp.span = current_span;
821822
(alloc_timestamp, alloc_index)
822823
}
823-
// Other global memory should trace races but be allocated at the 0 timestamp.
824+
// Other global memory should trace races but be allocated at the 0 timestamp
825+
// (conceptually they are allocated before everything).
824826
MemoryKind::Machine(
825827
MiriMemoryKind::Global
826828
| MiriMemoryKind::Machine

src/tools/miri/src/concurrency/thread.rs

-11
Original file line numberDiff line numberDiff line change
@@ -981,17 +981,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
981981
this.machine.threads.set_thread_name(thread, new_thread_name);
982982
}
983983

984-
#[inline]
985-
fn set_thread_name_wide(&mut self, thread: ThreadId, new_thread_name: &[u16]) {
986-
let this = self.eval_context_mut();
987-
988-
// The Windows `GetThreadDescription` shim to get the thread name isn't implemented, so being lossy is okay.
989-
// This is only read by diagnostics, which already use `from_utf8_lossy`.
990-
this.machine
991-
.threads
992-
.set_thread_name(thread, String::from_utf16_lossy(new_thread_name).into_bytes());
993-
}
994-
995984
#[inline]
996985
fn get_thread_name<'c>(&'c self, thread: ThreadId) -> Option<&[u8]>
997986
where

src/tools/miri/src/machine.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ pub enum MiriMemoryKind {
113113
C,
114114
/// Windows `HeapAlloc` memory.
115115
WinHeap,
116+
/// Windows "local" memory (to be freed with `LocalFree`)
117+
WinLocal,
116118
/// Memory for args, errno, and other parts of the machine-managed environment.
117119
/// This memory may leak.
118120
Machine,
@@ -144,7 +146,7 @@ impl MayLeak for MiriMemoryKind {
144146
fn may_leak(self) -> bool {
145147
use self::MiriMemoryKind::*;
146148
match self {
147-
Rust | Miri | C | WinHeap | Runtime => false,
149+
Rust | Miri | C | WinHeap | WinLocal | Runtime => false,
148150
Machine | Global | ExternStatic | Tls | Mmap => true,
149151
}
150152
}
@@ -156,7 +158,7 @@ impl MiriMemoryKind {
156158
use self::MiriMemoryKind::*;
157159
match self {
158160
// Heap allocations are fine since the `Allocation` is created immediately.
159-
Rust | Miri | C | WinHeap | Mmap => true,
161+
Rust | Miri | C | WinHeap | WinLocal | Mmap => true,
160162
// Everything else is unclear, let's not show potentially confusing spans.
161163
Machine | Global | ExternStatic | Tls | Runtime => false,
162164
}
@@ -171,6 +173,7 @@ impl fmt::Display for MiriMemoryKind {
171173
Miri => write!(f, "Miri bare-metal heap"),
172174
C => write!(f, "C heap"),
173175
WinHeap => write!(f, "Windows heap"),
176+
WinLocal => write!(f, "Windows local memory"),
174177
Machine => write!(f, "machine-managed memory"),
175178
Runtime => write!(f, "language runtime memory"),
176179
Global => write!(f, "global (static or const)"),

src/tools/miri/src/shims/windows/foreign_items.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ use rustc_span::Symbol;
55
use rustc_target::abi::Size;
66
use rustc_target::spec::abi::Abi;
77

8+
use crate::shims::os_str::bytes_to_os_str;
89
use crate::*;
910
use shims::foreign_items::EmulateForeignItemResult;
1011
use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle};
1112
use shims::windows::sync::EvalContextExt as _;
1213
use shims::windows::thread::EvalContextExt as _;
1314

1415
fn is_dyn_sym(name: &str) -> bool {
15-
matches!(name, "SetThreadDescription" | "WaitOnAddress" | "WakeByAddressSingle")
16+
// std does dynamic detection for these symbols
17+
matches!(
18+
name,
19+
"SetThreadDescription" | "GetThreadDescription" | "WaitOnAddress" | "WakeByAddressSingle"
20+
)
1621
}
1722

1823
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
@@ -172,6 +177,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
172177
let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
173178
this.write_pointer(res, dest)?;
174179
}
180+
"LocalFree" => {
181+
let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
182+
let ptr = this.read_pointer(ptr)?;
183+
this.free(ptr, MiriMemoryKind::WinLocal)?;
184+
this.write_null(dest)?;
185+
}
175186

176187
// errno
177188
"SetLastError" => {
@@ -403,7 +414,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
403414
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
404415

405416
let handle = this.read_scalar(handle)?;
406-
407417
let name = this.read_wide_str(this.read_pointer(name)?)?;
408418

409419
let thread = match Handle::from_scalar(handle, this)? {
@@ -412,7 +422,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
412422
_ => this.invalid_handle("SetThreadDescription")?,
413423
};
414424

415-
this.set_thread_name_wide(thread, &name);
425+
// FIXME: use non-lossy conversion
426+
this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
427+
428+
this.write_null(dest)?;
429+
}
430+
"GetThreadDescription" => {
431+
let [handle, name_ptr] =
432+
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
433+
434+
let handle = this.read_scalar(handle)?;
435+
let name_ptr = this.deref_pointer(name_ptr)?; // the pointer where we should store the ptr to the name
436+
437+
let thread = match Handle::from_scalar(handle, this)? {
438+
Some(Handle::Thread(thread)) => thread,
439+
Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(),
440+
_ => this.invalid_handle("SetThreadDescription")?,
441+
};
442+
// Looks like the default thread name is empty.
443+
let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
444+
let name = this.alloc_os_str_as_wide_str(
445+
bytes_to_os_str(&name)?,
446+
MiriMemoryKind::WinLocal.into(),
447+
)?;
448+
449+
this.write_scalar(Scalar::from_maybe_pointer(name, this), &name_ptr)?;
416450

417451
this.write_null(dest)?;
418452
}

src/tools/miri/tests/pass/concurrency/simple.rs

-19
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,6 @@ fn create_move_out() {
4545
assert_eq!(result.len(), 6);
4646
}
4747

48-
fn panic() {
49-
let result = thread::spawn(|| panic!("Hello!")).join().unwrap_err();
50-
let msg = result.downcast_ref::<&'static str>().unwrap();
51-
assert_eq!(*msg, "Hello!");
52-
}
53-
54-
fn panic_named() {
55-
thread::Builder::new()
56-
.name("childthread".to_string())
57-
.spawn(move || {
58-
panic!("Hello, world!");
59-
})
60-
.unwrap()
61-
.join()
62-
.unwrap_err();
63-
}
64-
6548
// This is not a data race!
6649
fn shared_readonly() {
6750
use std::sync::Arc;
@@ -89,6 +72,4 @@ fn main() {
8972
create_move_in();
9073
create_move_out();
9174
shared_readonly();
92-
panic();
93-
panic_named();
9475
}

src/tools/miri/tests/pass/concurrency/simple.stderr

-5
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use std::thread;
2+
3+
fn main() {
4+
// When we have not set the name...
5+
thread::spawn(|| {
6+
assert!(thread::current().name().is_none());
7+
});
8+
9+
// ... and when we have set it.
10+
thread::Builder::new()
11+
.name("childthread".to_string())
12+
.spawn(move || {
13+
assert_eq!(thread::current().name().unwrap(), "childthread");
14+
})
15+
.unwrap()
16+
.join()
17+
.unwrap();
18+
19+
// Also check main thread name.
20+
assert_eq!(thread::current().name().unwrap(), "main");
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//! Panicking in other threads.
2+
3+
use std::thread;
4+
5+
fn panic() {
6+
let result = thread::spawn(|| panic!("Hello!")).join().unwrap_err();
7+
let msg = result.downcast_ref::<&'static str>().unwrap();
8+
assert_eq!(*msg, "Hello!");
9+
}
10+
11+
fn panic_named() {
12+
thread::Builder::new()
13+
.name("childthread".to_string())
14+
.spawn(move || {
15+
panic!("Hello, world!");
16+
})
17+
.unwrap()
18+
.join()
19+
.unwrap_err();
20+
}
21+
22+
fn main() {
23+
panic();
24+
panic_named();
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
thread '<unnamed>' panicked at $DIR/thread_panic.rs:LL:CC:
2+
Hello!
3+
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
4+
thread 'childthread' panicked at $DIR/thread_panic.rs:LL:CC:
5+
Hello, world!

src/tools/miri/tests/pass/shims/windows-rand.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@only-target-windows: this directly tests windows only random functions
1+
//@only-target-windows: this directly tests windows-only functions
22
use core::ffi::c_void;
33
use core::mem::size_of_val;
44
use core::ptr::null_mut;
@@ -26,12 +26,12 @@ extern "system" {
2626
#[cfg(target_arch = "x86")]
2727
#[link(name = "bcryptprimitives", kind = "raw-dylib", import_name_type = "undecorated")]
2828
extern "system" {
29-
pub fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
29+
fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
3030
}
3131
#[cfg(not(target_arch = "x86"))]
3232
#[link(name = "bcryptprimitives", kind = "raw-dylib")]
3333
extern "system" {
34-
pub fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
34+
fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
3535
}
3636

3737
fn main() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//@only-target-windows: this directly tests windows-only functions
2+
3+
use std::ffi::OsStr;
4+
use std::os::windows::ffi::OsStrExt;
5+
6+
use core::ffi::c_void;
7+
type HANDLE = *mut c_void;
8+
type PWSTR = *mut u16;
9+
type PCWSTR = *const u16;
10+
type HRESULT = i32;
11+
type HLOCAL = *mut ::core::ffi::c_void;
12+
extern "system" {
13+
fn GetCurrentThread() -> HANDLE;
14+
fn GetThreadDescription(hthread: HANDLE, lpthreaddescription: *mut PWSTR) -> HRESULT;
15+
fn SetThreadDescription(hthread: HANDLE, lpthreaddescription: PCWSTR) -> HRESULT;
16+
fn LocalFree(hmem: HLOCAL) -> HLOCAL;
17+
}
18+
19+
fn to_u16s<S: AsRef<OsStr>>(s: S) -> Vec<u16> {
20+
let mut result: Vec<_> = s.as_ref().encode_wide().collect();
21+
result.push(0);
22+
result
23+
}
24+
25+
fn main() {
26+
unsafe {
27+
let name = c"mythreadname";
28+
29+
let utf16 = to_u16s(name.to_str().unwrap());
30+
SetThreadDescription(GetCurrentThread(), utf16.as_ptr());
31+
32+
let mut ptr = core::ptr::null_mut::<u16>();
33+
let result = GetThreadDescription(GetCurrentThread(), &mut ptr);
34+
assert!(result >= 0);
35+
let name_gotten = String::from_utf16_lossy({
36+
let mut len = 0;
37+
while *ptr.add(len) != 0 {
38+
len += 1;
39+
}
40+
core::slice::from_raw_parts(ptr, len)
41+
});
42+
assert_eq!(name_gotten, name.to_str().unwrap());
43+
let r = LocalFree(ptr.cast());
44+
assert!(r.is_null());
45+
}
46+
}

0 commit comments

Comments
 (0)