diff options
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/backtrace.rs | 6 | ||||
| -rw-r--r-- | library/std/src/sync/rwlock.rs | 63 | ||||
| -rw-r--r-- | library/std/src/thread/mod.rs | 55 |
3 files changed, 88 insertions, 36 deletions
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 5cf6ec81789..34b57c37635 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -14,8 +14,8 @@ //! Backtraces are attempted to be as accurate as possible, but no guarantees //! are provided about the exact accuracy of a backtrace. Instruction pointers, //! symbol names, filenames, line numbers, etc, may all be incorrect when -//! reported. Accuracy is attempted on a best-effort basis, however, and bugs -//! are always welcome to indicate areas of improvement! +//! reported. Accuracy is attempted on a best-effort basis, however, any bug +//! reports are always welcome to indicate areas of improvement! //! //! For most platforms a backtrace with a filename/line number requires that //! programs be compiled with debug information. Without debug information @@ -39,7 +39,7 @@ //! default. Its behavior is governed by two environment variables: //! //! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture` -//! will never capture a backtrace. Any other value this is set to will enable +//! will never capture a backtrace. Any other value set will enable //! `Backtrace::capture`. //! //! * `RUST_BACKTRACE` - if `RUST_LIB_BACKTRACE` is not set, then this variable diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index ee2c79b6669..8b387760768 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -167,7 +167,7 @@ impl<T> RwLock<T> { } impl<T: ?Sized> RwLock<T> { - /// Locks this rwlock with shared read access, blocking the current thread + /// Locks this `RwLock` with shared read access, blocking the current thread /// until it can be acquired. /// /// The calling thread will be blocked until there are no more writers which @@ -181,9 +181,10 @@ impl<T: ?Sized> RwLock<T> { /// /// # Errors /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. - /// The failure will occur immediately after the lock has been acquired. + /// This function will return an error if the `RwLock` is poisoned. An + /// `RwLock` is poisoned whenever a writer panics while holding an exclusive + /// lock. The failure will occur immediately after the lock has been + /// acquired. /// /// # Panics /// @@ -215,7 +216,7 @@ impl<T: ?Sized> RwLock<T> { } } - /// Attempts to acquire this rwlock with shared read access. + /// Attempts to acquire this `RwLock` with shared read access. /// /// If the access could not be granted at this time, then `Err` is returned. /// Otherwise, an RAII guard is returned which will release the shared access @@ -228,13 +229,13 @@ impl<T: ?Sized> RwLock<T> { /// /// # Errors /// - /// This function will return the [`Poisoned`] error if the RwLock is poisoned. - /// An RwLock is poisoned whenever a writer panics while holding an exclusive - /// lock. `Poisoned` will only be returned if the lock would have otherwise been - /// acquired. + /// This function will return the [`Poisoned`] error if the `RwLock` is + /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding + /// an exclusive lock. `Poisoned` will only be returned if the lock would + /// have otherwise been acquired. /// - /// This function will return the [`WouldBlock`] error if the RwLock could not - /// be acquired because it was already locked exclusively. + /// This function will return the [`WouldBlock`] error if the `RwLock` could + /// not be acquired because it was already locked exclusively. /// /// [`Poisoned`]: TryLockError::Poisoned /// [`WouldBlock`]: TryLockError::WouldBlock @@ -263,20 +264,20 @@ impl<T: ?Sized> RwLock<T> { } } - /// Locks this rwlock with exclusive write access, blocking the current + /// Locks this `RwLock` with exclusive write access, blocking the current /// thread until it can be acquired. /// /// This function will not return while other writers or other readers /// currently have access to the lock. /// - /// Returns an RAII guard which will drop the write access of this rwlock + /// Returns an RAII guard which will drop the write access of this `RwLock` /// when dropped. /// /// # Errors /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. - /// An error will be returned when the lock is acquired. + /// This function will return an error if the `RwLock` is poisoned. An + /// `RwLock` is poisoned whenever a writer panics while holding an exclusive + /// lock. An error will be returned when the lock is acquired. /// /// # Panics /// @@ -303,7 +304,7 @@ impl<T: ?Sized> RwLock<T> { } } - /// Attempts to lock this rwlock with exclusive write access. + /// Attempts to lock this `RwLock` with exclusive write access. /// /// If the lock could not be acquired at this time, then `Err` is returned. /// Otherwise, an RAII guard is returned which will release the lock when @@ -316,13 +317,13 @@ impl<T: ?Sized> RwLock<T> { /// /// # Errors /// - /// This function will return the [`Poisoned`] error if the RwLock is - /// poisoned. An RwLock is poisoned whenever a writer panics while holding - /// an exclusive lock. `Poisoned` will only be returned if the lock would have - /// otherwise been acquired. + /// This function will return the [`Poisoned`] error if the `RwLock` is + /// poisoned. An `RwLock` is poisoned whenever a writer panics while holding + /// an exclusive lock. `Poisoned` will only be returned if the lock would + /// have otherwise been acquired. /// - /// This function will return the [`WouldBlock`] error if the RwLock could not - /// be acquired because it was already locked exclusively. + /// This function will return the [`WouldBlock`] error if the `RwLock` could + /// not be acquired because it was already locked exclusively. /// /// [`Poisoned`]: TryLockError::Poisoned /// [`WouldBlock`]: TryLockError::WouldBlock @@ -422,10 +423,10 @@ impl<T: ?Sized> RwLock<T> { /// /// # Errors /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. An - /// error will only be returned if the lock would have otherwise been - /// acquired. + /// This function will return an error if the `RwLock` is poisoned. An + /// `RwLock` is poisoned whenever a writer panics while holding an exclusive + /// lock. An error will only be returned if the lock would have otherwise + /// been acquired. /// /// # Examples /// @@ -455,10 +456,10 @@ impl<T: ?Sized> RwLock<T> { /// /// # Errors /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. An - /// error will only be returned if the lock would have otherwise been - /// acquired. + /// This function will return an error if the `RwLock` is poisoned. An + /// `RwLock` is poisoned whenever a writer panics while holding an exclusive + /// lock. An error will only be returned if the lock would have otherwise + /// been acquired. /// /// # Examples /// 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); } //////////////////////////////////////////////////////////////////////////////// |
