From d98ab4faf869ff0430ad73260b13ef8e473ef212 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Apr 2015 12:27:05 -0700 Subject: [PATCH] std: Don't assume thread::current() works on panic 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 --- src/libstd/panicking.rs | 6 ++--- src/libstd/sys/common/thread_info.rs | 11 ++++---- src/libstd/sys/unix/stack_overflow.rs | 2 +- src/libstd/thread/mod.rs | 4 ++- src/test/run-pass/issue-24313.rs | 39 +++++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 src/test/run-pass/issue-24313.rs diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 11b057d0094ae..7366524fd7ea8 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -17,7 +17,7 @@ use any::Any; use cell::RefCell; use rt::{backtrace, unwind}; use sys::stdio::Stderr; -use thread; +use sys_common::thread_info; thread_local! { pub static LOCAL_STDERR: RefCell>> = { @@ -34,8 +34,8 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) { } }; let mut err = Stderr::new(); - let thread = thread::current(); - let name = thread.name().unwrap_or(""); + let thread = thread_info::current_thread(); + let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take()); match prev { Some(mut stderr) => { diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs index 22cb594337130..ae55bae37aa88 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -25,10 +25,9 @@ struct ThreadInfo { thread_local! { static THREAD_INFO: RefCell> = RefCell::new(None) } impl ThreadInfo { - fn with(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R { + fn with(f: F) -> Option where F: FnOnce(&mut ThreadInfo) -> R { if THREAD_INFO.state() == LocalKeyState::Destroyed { - panic!("Use of std::thread::current() is not possible after \ - the thread's local data has been destroyed"); + return None } THREAD_INFO.with(move |c| { @@ -38,16 +37,16 @@ impl ThreadInfo { thread: NewThread::new(None), }) } - f(c.borrow_mut().as_mut().unwrap()) + Some(f(c.borrow_mut().as_mut().unwrap())) }) } } -pub fn current_thread() -> Thread { +pub fn current_thread() -> Option { ThreadInfo::with(|info| info.thread.clone()) } -pub fn stack_guard() -> usize { +pub fn stack_guard() -> Option { ThreadInfo::with(|info| info.stack_guard) } diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 6887095c53a7d..2bc280d127439 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -81,7 +81,7 @@ mod imp { // We're calling into functions with stack checks stack::record_sp_limit(0); - let guard = thread_info::stack_guard(); + let guard = thread_info::stack_guard().unwrap_or(0); let addr = (*info).si_addr as usize; if guard == 0 || addr < guard - PAGE_SIZE || addr >= guard { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 383726b3e8370..ce531fb13812c 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -407,7 +407,9 @@ pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where /// Gets a handle to the thread that invokes it. #[stable(feature = "rust1", since = "1.0.0")] pub fn current() -> Thread { - thread_info::current_thread() + thread_info::current_thread().expect("use of std::thread::current() is not \ + possible after the thread's local \ + data has been destroyed") } /// Cooperatively gives up a timeslice to the OS scheduler. diff --git a/src/test/run-pass/issue-24313.rs b/src/test/run-pass/issue-24313.rs new file mode 100644 index 0000000000000..9acfb04d781e0 --- /dev/null +++ b/src/test/run-pass/issue-24313.rs @@ -0,0 +1,39 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::thread; +use std::env; +use std::process::Command; + +struct Handle(i32); + +impl Drop for Handle { + fn drop(&mut self) { panic!(); } +} + +thread_local!(static HANDLE: Handle = Handle(0)); + +fn main() { + let args = env::args().collect::>(); + if args.len() == 1 { + let out = Command::new(&args[0]).arg("test").output().unwrap(); + let stderr = std::str::from_utf8(&out.stderr).unwrap(); + assert!(stderr.contains("panicked at 'explicit panic'"), + "bad failure message:\n{}\n", stderr); + } else { + // TLS dtors are not always run on process exit + thread::spawn(|| { + HANDLE.with(|h| { + println!("{}", h.0); + }); + }).join().unwrap(); + } +} +