about summary refs log tree commit diff
path: root/library/std/src/io/stdio.rs
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-04-11 22:38:53 +0200
committerGitHub <noreply@github.com>2024-04-11 22:38:53 +0200
commit1e99af514b68d0ff6891fa3cb6a9946c3888caef (patch)
tree9a0e27ae2496b1dceefca827032c57c25ab763b9 /library/std/src/io/stdio.rs
parentaa6a697a1c75b0aa06954136f7641706edadc2be (diff)
parentc2e5ee40b699608128654f2b67e0fafa8e1ec8dc (diff)
downloadrust-1e99af514b68d0ff6891fa3cb6a9946c3888caef.tar.gz
rust-1e99af514b68d0ff6891fa3cb6a9946c3888caef.zip
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.
Diffstat (limited to 'library/std/src/io/stdio.rs')
-rw-r--r--library/std/src/io/stdio.rs24
1 files changed, 22 insertions, 2 deletions
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 73fa7cbc3fe..07fa9259e0b 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -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`