Skip to content

Commit 2b8c9b1

Browse files
committed
Auto merge of #24478 - alexcrichton:issue-24313, r=aturon
Inspecting the current thread's info may not always work due to the TLS value having been destroyed (or is actively being destroyed). The code for printing a panic message assumed, however, that it could acquire the thread's name through this method. Instead this commit propagates the `Option` outwards to allow the `std::panicking` module to handle the case where the current thread isn't present. While it solves the immediate issue of #24313, there is still another underlying issue of panicking destructors in thread locals will abort the process. Closes #24313
2 parents 97d4e76 + d98ab4f commit 2b8c9b1

File tree

6 files changed

+55
-31
lines changed

6 files changed

+55
-31
lines changed

src/libstd/panicking.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use any::Any;
1717
use cell::RefCell;
1818
use rt::{backtrace, unwind};
1919
use sys::stdio::Stderr;
20-
use thread;
20+
use sys_common::thread_info;
2121

2222
thread_local! {
2323
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
@@ -34,8 +34,8 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
3434
}
3535
};
3636
let mut err = Stderr::new();
37-
let thread = thread::current();
38-
let name = thread.name().unwrap_or("<unnamed>");
37+
let thread = thread_info::current_thread();
38+
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
3939
let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
4040
match prev {
4141
Some(mut stderr) => {

src/libstd/sys/common/thread_info.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,9 @@ struct ThreadInfo {
2525
thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = RefCell::new(None) }
2626

2727
impl ThreadInfo {
28-
fn with<R, F>(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R {
28+
fn with<R, F>(f: F) -> Option<R> where F: FnOnce(&mut ThreadInfo) -> R {
2929
if THREAD_INFO.state() == LocalKeyState::Destroyed {
30-
panic!("Use of std::thread::current() is not possible after \
31-
the thread's local data has been destroyed");
30+
return None
3231
}
3332

3433
THREAD_INFO.with(move |c| {
@@ -38,16 +37,16 @@ impl ThreadInfo {
3837
thread: NewThread::new(None),
3938
})
4039
}
41-
f(c.borrow_mut().as_mut().unwrap())
40+
Some(f(c.borrow_mut().as_mut().unwrap()))
4241
})
4342
}
4443
}
4544

46-
pub fn current_thread() -> Thread {
45+
pub fn current_thread() -> Option<Thread> {
4746
ThreadInfo::with(|info| info.thread.clone())
4847
}
4948

50-
pub fn stack_guard() -> usize {
49+
pub fn stack_guard() -> Option<usize> {
5150
ThreadInfo::with(|info| info.stack_guard)
5251
}
5352

src/libstd/sys/unix/stack_overflow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ mod imp {
8181
// We're calling into functions with stack checks
8282
stack::record_sp_limit(0);
8383

84-
let guard = thread_info::stack_guard();
84+
let guard = thread_info::stack_guard().unwrap_or(0);
8585
let addr = (*info).si_addr as usize;
8686

8787
if guard == 0 || addr < guard - PAGE_SIZE || addr >= guard {

src/libstd/thread/local.rs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use cell::UnsafeCell;
1818

1919
// Sure wish we had macro hygiene, no?
2020
#[doc(hidden)]
21-
#[unstable(feature = "thread_local_internals")]
2221
pub mod __impl {
2322
pub use super::imp::Key as KeyInner;
2423
pub use super::imp::destroy_value;
@@ -78,12 +77,10 @@ pub struct LocalKey<T> {
7877
// This is trivially devirtualizable by LLVM because we never store anything
7978
// to this field and rustc can declare the `static` as constant as well.
8079
#[doc(hidden)]
81-
#[unstable(feature = "thread_local_internals")]
8280
pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,
8381

8482
// initialization routine to invoke to create a value
8583
#[doc(hidden)]
86-
#[unstable(feature = "thread_local_internals")]
8784
pub init: fn() -> T,
8885
}
8986

@@ -297,36 +294,31 @@ impl<T: 'static> LocalKey<T> {
297294
}
298295

299296
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
297+
#[doc(hidden)]
300298
mod imp {
301299
use prelude::v1::*;
302300

303301
use cell::UnsafeCell;
304302
use intrinsics;
305303
use ptr;
306304

307-
#[doc(hidden)]
308-
#[unstable(feature = "thread_local_internals")]
309305
pub struct Key<T> {
310306
// Place the inner bits in an `UnsafeCell` to currently get around the
311307
// "only Sync statics" restriction. This allows any type to be placed in
312308
// the cell.
313309
//
314310
// Note that all access requires `T: 'static` so it can't be a type with
315311
// any borrowed pointers still.
316-
#[unstable(feature = "thread_local_internals")]
317312
pub inner: UnsafeCell<T>,
318313

319314
// Metadata to keep track of the state of the destructor. Remember that
320315
// these variables are thread-local, not global.
321-
#[unstable(feature = "thread_local_internals")]
322316
pub dtor_registered: UnsafeCell<bool>, // should be Cell
323-
#[unstable(feature = "thread_local_internals")]
324317
pub dtor_running: UnsafeCell<bool>, // should be Cell
325318
}
326319

327320
unsafe impl<T> ::marker::Sync for Key<T> { }
328321

329-
#[doc(hidden)]
330322
impl<T> Key<T> {
331323
pub unsafe fn get(&'static self) -> Option<&'static T> {
332324
if intrinsics::needs_drop::<T>() && *self.dtor_running.get() {
@@ -422,8 +414,6 @@ mod imp {
422414
_tlv_atexit(dtor, t);
423415
}
424416

425-
#[doc(hidden)]
426-
#[unstable(feature = "thread_local_internals")]
427417
pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
428418
let ptr = ptr as *mut Key<T>;
429419
// Right before we run the user destructor be sure to flag the
@@ -435,6 +425,7 @@ mod imp {
435425
}
436426

437427
#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
428+
#[doc(hidden)]
438429
mod imp {
439430
use prelude::v1::*;
440431

@@ -444,16 +435,12 @@ mod imp {
444435
use ptr;
445436
use sys_common::thread_local::StaticKey as OsStaticKey;
446437

447-
#[doc(hidden)]
448-
#[unstable(feature = "thread_local_internals")]
449438
pub struct Key<T> {
450439
// Statically allocated initialization expression, using an `UnsafeCell`
451440
// for the same reasons as above.
452-
#[unstable(feature = "thread_local_internals")]
453441
pub inner: UnsafeCell<T>,
454442

455443
// OS-TLS key that we'll use to key off.
456-
#[unstable(feature = "thread_local_internals")]
457444
pub os: OsStaticKey,
458445
}
459446

@@ -464,7 +451,6 @@ mod imp {
464451
value: T,
465452
}
466453

467-
#[doc(hidden)]
468454
impl<T> Key<T> {
469455
pub unsafe fn get(&'static self) -> Option<&'static T> {
470456
self.ptr().map(|p| &*p)
@@ -489,14 +475,12 @@ mod imp {
489475
key: self,
490476
value: mem::transmute_copy(&self.inner),
491477
};
492-
let ptr: *mut Value<T> = boxed::into_raw(ptr);
478+
let ptr = boxed::into_raw(ptr);
493479
self.os.set(ptr as *mut u8);
494480
Some(&mut (*ptr).value as *mut T)
495481
}
496482
}
497483

498-
#[doc(hidden)]
499-
#[unstable(feature = "thread_local_internals")]
500484
pub unsafe extern fn destroy_value<T: 'static>(ptr: *mut u8) {
501485
// The OS TLS ensures that this key contains a NULL value when this
502486
// destructor starts to run. We set it back to a sentinel value of 1 to
@@ -505,7 +489,7 @@ mod imp {
505489
//
506490
// Note that to prevent an infinite loop we reset it back to null right
507491
// before we return from the destructor ourselves.
508-
let ptr: Box<Value<T>> = Box::from_raw(ptr as *mut Value<T>);
492+
let ptr = Box::from_raw(ptr as *mut Value<T>);
509493
let key = ptr.key;
510494
key.os.set(1 as *mut u8);
511495
drop(ptr);

src/libstd/thread/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,9 @@ pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
407407
/// Gets a handle to the thread that invokes it.
408408
#[stable(feature = "rust1", since = "1.0.0")]
409409
pub fn current() -> Thread {
410-
thread_info::current_thread()
410+
thread_info::current_thread().expect("use of std::thread::current() is not \
411+
possible after the thread's local \
412+
data has been destroyed")
411413
}
412414

413415
/// Cooperatively gives up a timeslice to the OS scheduler.

src/test/run-pass/issue-24313.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::thread;
12+
use std::env;
13+
use std::process::Command;
14+
15+
struct Handle(i32);
16+
17+
impl Drop for Handle {
18+
fn drop(&mut self) { panic!(); }
19+
}
20+
21+
thread_local!(static HANDLE: Handle = Handle(0));
22+
23+
fn main() {
24+
let args = env::args().collect::<Vec<_>>();
25+
if args.len() == 1 {
26+
let out = Command::new(&args[0]).arg("test").output().unwrap();
27+
let stderr = std::str::from_utf8(&out.stderr).unwrap();
28+
assert!(stderr.contains("panicked at 'explicit panic'"),
29+
"bad failure message:\n{}\n", stderr);
30+
} else {
31+
// TLS dtors are not always run on process exit
32+
thread::spawn(|| {
33+
HANDLE.with(|h| {
34+
println!("{}", h.0);
35+
});
36+
}).join().unwrap();
37+
}
38+
}
39+

0 commit comments

Comments
 (0)