1
Fork 0

Rollup merge of #122882 - Zoxc:panic-output-panic, r=Amanieu

Avoid a panic in `set_output_capture` in the default panic handler

This avoid a panic in the default panic handler by not using `set_output_capture` as `OUTPUT_CAPTURE.with` may panic once `OUTPUT_CAPTURE` is dropped.

A new non-panicking `try_set_output_capture` variant of `set_output_capture` is added for use in the default panic handler.
This commit is contained in:
Matthias Krüger 2024-04-11 22:38:53 +02:00 committed by GitHub
commit 1e99af514b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 29 additions and 9 deletions

View file

@ -311,14 +311,14 @@ pub use self::buffered::WriterPanicked;
#[unstable(feature = "raw_os_error_ty", issue = "107792")]
pub use self::error::RawOsError;
pub(crate) use self::stdio::attempt_print_to_stderr;
#[unstable(feature = "internal_output_capture", issue = "none")]
#[doc(no_inline, hidden)]
pub use self::stdio::set_output_capture;
#[stable(feature = "is_terminal", since = "1.70.0")]
pub use self::stdio::IsTerminal;
#[unstable(feature = "print_internals", issue = "none")]
#[doc(hidden)]
pub use self::stdio::{_eprint, _print};
#[unstable(feature = "internal_output_capture", issue = "none")]
#[doc(no_inline, hidden)]
pub use self::stdio::{set_output_capture, try_set_output_capture};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::{
buffered::{BufReader, BufWriter, IntoInnerError, LineWriter},

View file

@ -15,6 +15,7 @@ use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantLock, ReentrantLockGuard};
use crate::sys::stdio;
use crate::thread::AccessError;
type LocalStream = Arc<Mutex<Vec<u8>>>;
@ -1064,12 +1065,31 @@ impl fmt::Debug for StderrLock<'_> {
)]
#[doc(hidden)]
pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> {
try_set_output_capture(sink).expect(
"cannot access a Thread Local Storage value \
during or after destruction",
)
}
/// Tries to set the thread-local output capture buffer and returns the old one.
/// This may fail once thread-local destructors are called. It's used in panic
/// handling instead of `set_output_capture`.
#[unstable(
feature = "internal_output_capture",
reason = "this function is meant for use in the test crate \
and may disappear in the future",
issue = "none"
)]
#[doc(hidden)]
pub fn try_set_output_capture(
sink: Option<LocalStream>,
) -> Result<Option<LocalStream>, AccessError> {
if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) {
// OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false.
return None;
return Ok(None);
}
OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed);
OUTPUT_CAPTURE.with(move |slot| slot.replace(sink))
OUTPUT_CAPTURE.try_with(move |slot| slot.replace(sink))
}
/// Write `args` to the capture buffer if enabled and possible, or `global_s`