From 6399bb425b3a82111cd554737f194c95b8f6bad5 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 13 Apr 2015 12:08:20 -0700 Subject: [PATCH] De-stabilize `thread::scoped` and friends Issue #24292 demonstrates that the `scoped` API as currently offered can be memory-unsafe: the `JoinGuard` can be moved into a context that will fail to execute destructors prior to the stack frame being popped (for example, by creating an `Rc` cycle). This commit reverts the APIs to `unstable` status while a long-term solution is worked out. (There are several possible ways to address this issue; it's not a fundamental problem with the `scoped` idea, but rather an indication that Rust doesn't currently provide a good way to ensure that destructors are run within a particular stack frame.) [breaking-change] --- src/libstd/thread/mod.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 0e5fee27ffe22..239911026500d 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -274,7 +274,8 @@ impl Builder { /// Unlike the `scoped` free function, this method yields an /// `io::Result` to capture any failure to create the thread at /// the OS level. - #[stable(feature = "rust1", since = "1.0.0")] + #[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] pub fn scoped<'a, T, F>(self, f: F) -> io::Result> where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a { @@ -387,7 +388,8 @@ pub fn spawn(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static { /// /// Panics if the OS fails to create a thread; use `Builder::scoped` /// to recover from such errors. -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a { @@ -674,7 +676,8 @@ impl Drop for JoinHandle { /// handle: the ability to join a child thread is a uniquely-owned /// permission. #[must_use = "thread will be immediately joined if `JoinGuard` is not used"] -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] pub struct JoinGuard<'a, T: Send + 'a> { inner: JoinInner, _marker: PhantomData<&'a T>, @@ -706,7 +709,8 @@ impl<'a, T: Send + 'a> JoinGuard<'a, T> { } #[unsafe_destructor] -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> { fn drop(&mut self) { if !self.inner.joined {