diff options
| author | bors <bors@rust-lang.org> | 2022-10-11 11:03:12 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-10-11 11:03:12 +0000 |
| commit | bb93450ec4af83c20e9ba6c8e575aca55423001a (patch) | |
| tree | 1f8ec522088447d95945bf12ac8b5fcadc34f95c /library/std/src/thread | |
| parent | 1e926f06528ecb2503f026e2fd53cb735d487b10 (diff) | |
| parent | 3011538b80a52aedb2d7374798ffa35ea742d475 (diff) | |
| download | rust-bb93450ec4af83c20e9ba6c8e575aca55423001a.tar.gz rust-bb93450ec4af83c20e9ba6c8e575aca55423001a.zip | |
Auto merge of #102915 - JohnTitor:rollup-5ht99y1, r=JohnTitor
Rollup of 7 pull requests Successful merges: - #102258 (Remove unused variable in float formatting.) - #102277 (Consistently write `RwLock`) - #102412 (Never panic in `thread::park` and `thread::park_timeout`) - #102589 (scoped threads: pass closure through MaybeUninit to avoid invalid dangling references) - #102625 (fix backtrace small typo) - #102859 (Move lifetime resolution module to rustc_hir_analysis.) - #102898 (rustdoc: remove unneeded `<div>` wrapper from sidebar DOM) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'library/std/src/thread')
| -rw-r--r-- | library/std/src/thread/mod.rs | 55 |
1 files changed, 53 insertions, 2 deletions
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 2de7da3793f..55110c44b6e 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -160,7 +160,7 @@ use crate::ffi::{CStr, CString}; use crate::fmt; use crate::io; use crate::marker::PhantomData; -use crate::mem; +use crate::mem::{self, forget}; use crate::num::NonZeroU64; use crate::num::NonZeroUsize; use crate::panic; @@ -499,6 +499,31 @@ impl Builder { let output_capture = crate::io::set_output_capture(None); crate::io::set_output_capture(output_capture.clone()); + // Pass `f` in `MaybeUninit` because actually that closure might *run longer than the lifetime of `F`*. + // See <https://github.com/rust-lang/rust/issues/101983> for more details. + // To prevent leaks we use a wrapper that drops its contents. + #[repr(transparent)] + struct MaybeDangling<T>(mem::MaybeUninit<T>); + impl<T> MaybeDangling<T> { + fn new(x: T) -> Self { + MaybeDangling(mem::MaybeUninit::new(x)) + } + fn into_inner(self) -> T { + // SAFETY: we are always initiailized. + let ret = unsafe { self.0.assume_init_read() }; + // Make sure we don't drop. + mem::forget(self); + ret + } + } + impl<T> Drop for MaybeDangling<T> { + fn drop(&mut self) { + // SAFETY: we are always initiailized. + unsafe { self.0.assume_init_drop() }; + } + } + + let f = MaybeDangling::new(f); let main = move || { if let Some(name) = their_thread.cname() { imp::Thread::set_name(name); @@ -506,6 +531,8 @@ impl Builder { crate::io::set_output_capture(output_capture); + // SAFETY: we constructed `f` initialized. + let f = f.into_inner(); // SAFETY: the stack guard passed is the one for the current thread. // This means the current thread's stack and the new thread's stack // are properly set and protected from each other. @@ -518,6 +545,12 @@ impl Builder { // same `JoinInner` as this closure meaning the mutation will be // safe (not modify it and affect a value far away). unsafe { *their_packet.result.get() = Some(try_result) }; + // Here `their_packet` gets dropped, and if this is the last `Arc` for that packet that + // will call `decrement_num_running_threads` and therefore signal that this thread is + // done. + drop(their_packet); + // Here, the lifetime `'a` and even `'scope` can end. `main` keeps running for a bit + // after that before returning itself. }; if let Some(scope_data) = &my_packet.scope { @@ -851,10 +884,22 @@ pub fn sleep(dur: Duration) { imp::Thread::sleep(dur) } +/// Used to ensure that `park` and `park_timeout` do not unwind, as that can +/// cause undefined behaviour if not handled correctly (see #102398 for context). +struct PanicGuard; + +impl Drop for PanicGuard { + fn drop(&mut self) { + rtabort!("an irrecoverable error occurred while synchronizing threads") + } +} + /// Blocks unless or until the current thread's token is made available. /// /// A call to `park` does not guarantee that the thread will remain parked -/// forever, and callers should be prepared for this possibility. +/// forever, and callers should be prepared for this possibility. However, +/// it is guaranteed that this function will not panic (it may abort the +/// process if the implementation encounters some rare errors). /// /// # park and unpark /// @@ -939,10 +984,13 @@ pub fn sleep(dur: Duration) { /// [`thread::park_timeout`]: park_timeout #[stable(feature = "rust1", since = "1.0.0")] pub fn park() { + let guard = PanicGuard; // SAFETY: park_timeout is called on the parker owned by this thread. unsafe { current().inner.as_ref().parker().park(); } + // No panic occurred, do not abort. + forget(guard); } /// Use [`park_timeout`]. @@ -1003,10 +1051,13 @@ pub fn park_timeout_ms(ms: u32) { /// ``` #[stable(feature = "park_timeout", since = "1.4.0")] pub fn park_timeout(dur: Duration) { + let guard = PanicGuard; // SAFETY: park_timeout is called on the parker owned by this thread. unsafe { current().inner.as_ref().parker().park_timeout(dur); } + // No panic occurred, do not abort. + forget(guard); } //////////////////////////////////////////////////////////////////////////////// |
