diff --git a/src/eval.rs b/src/eval.rs index ab82c39836b2..c5a04d75858c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -222,7 +222,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; - // Global destructors. + // Run Windows destructors. (We do not support concurrency on Windows + // yet, so we run the destructor of the main thread separately.) ecx.run_windows_tls_dtors()?; Ok(return_code) })(); diff --git a/src/shims/tls.rs b/src/shims/tls.rs index c08ec78c136d..31a9ee3c9425 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -6,7 +6,6 @@ use std::collections::HashSet; use log::trace; -use rustc_index::vec::Idx; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; @@ -201,7 +200,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } let active_thread = this.get_active_thread()?; - assert_eq!(active_thread.index(), 0, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); assert!(!this.machine.tls.dtors_running.contains(&active_thread), "running TLS dtors twice"); this.machine.tls.dtors_running.insert(active_thread); // Windows has a special magic linker section that is run on certain events. diff --git a/src/thread.rs b/src/thread.rs index 657792bd2c67..8c353d6a8853 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -227,6 +227,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread } + /// Get the total number of threads that were ever spawn by this program. + fn get_total_thread_count(&self) -> usize { + self.threads.len() + } + /// Has the given thread terminated? fn has_terminated(&self, thread_id: ThreadId) -> bool { self.threads[thread_id].state == ThreadState::Terminated @@ -492,6 +497,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.get_active_thread_id()) } + #[inline] + fn get_total_thread_count(&self) -> InterpResult<'tcx, usize> { + let this = self.eval_context_ref(); + Ok(this.machine.threads.get_total_thread_count()) + } + #[inline] fn has_terminated(&self, thread_id: ThreadId) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); diff --git a/tests/compile-fail/concurrency/dangling_tls_lib.rs b/tests/compile-fail/concurrency/dangling_tls_lib.rs index 684dd0e86f60..6be5538bb444 100644 --- a/tests/compile-fail/concurrency/dangling_tls_lib.rs +++ b/tests/compile-fail/concurrency/dangling_tls_lib.rs @@ -1,5 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. +//! Check that we catch if a thread local is accessed after the thread has +//! terminated. + #![feature(thread_local_internals)] use std::cell::RefCell; diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs new file mode 100644 index 000000000000..c9b04a728258 --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -0,0 +1,46 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Check that destructors of the library thread locals are executed immediately +//! after a thread terminates. + +#![feature(thread_local_internals)] + +use std::cell::RefCell; +use std::thread; + +struct TestCell { + value: RefCell, +} + +impl Drop for TestCell { + fn drop(&mut self) { + println!("Dropping: {}", self.value.borrow()) + } +} + +static A: std::thread::LocalKey = { + #[inline] + fn __init() -> TestCell { + TestCell { value: RefCell::new(0) } + } + + unsafe fn __getit() -> Option<&'static TestCell> { + static __KEY: std::thread::__OsLocalKeyInner = + std::thread::__OsLocalKeyInner::new(); + __KEY.get(__init) + } + + unsafe { std::thread::LocalKey::new(__getit) } +}; + +fn main() { + thread::spawn(|| { + A.with(|f| { + assert_eq!(*f.value.borrow(), 0); + *f.value.borrow_mut() = 5; + }); + }) + .join() + .unwrap(); + println!("Continue main.") +} diff --git a/tests/run-pass/concurrency/tls_lib_drop.stderr b/tests/run-pass/concurrency/tls_lib_drop.stderr new file mode 100644 index 000000000000..2dbfb7721d36 --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/tls_lib_drop.stdout b/tests/run-pass/concurrency/tls_lib_drop.stdout new file mode 100644 index 000000000000..d2bbb866b77e --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop.stdout @@ -0,0 +1,2 @@ +Dropping: 5 +Continue main.