Skip to content

Commit 380964c

Browse files
committed
Avoid a panic in set_output_capture in the default panic handler
1 parent eff958c commit 380964c

File tree

3 files changed

+20
-6
lines changed

3 files changed

+20
-6
lines changed

library/std/src/io/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ pub(crate) use self::stdio::attempt_print_to_stderr;
314314
#[unstable(feature = "internal_output_capture", issue = "none")]
315315
#[doc(no_inline, hidden)]
316316
pub use self::stdio::set_output_capture;
317+
pub(crate) use self::stdio::try_set_output_capture;
317318
#[stable(feature = "is_terminal", since = "1.70.0")]
318319
pub use self::stdio::IsTerminal;
319320
#[unstable(feature = "print_internals", issue = "none")]

library/std/src/io/stdio.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::panic::{RefUnwindSafe, UnwindSafe};
1515
use crate::sync::atomic::{AtomicBool, Ordering};
1616
use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantLock, ReentrantLockGuard};
1717
use crate::sys::stdio;
18+
use crate::thread::AccessError;
1819

1920
type LocalStream = Arc<Mutex<Vec<u8>>>;
2021

@@ -1054,12 +1055,24 @@ impl fmt::Debug for StderrLock<'_> {
10541055
)]
10551056
#[doc(hidden)]
10561057
pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> {
1058+
try_set_output_capture(sink).expect(
1059+
"cannot access a Thread Local Storage value \
1060+
during or after destruction",
1061+
)
1062+
}
1063+
1064+
/// Tries to set the thread-local output capture buffer and returns the old one.
1065+
/// This may fail once thread-local destructors are called. It's used in panic
1066+
/// handling instead of `set_output_capture`.
1067+
pub(crate) fn try_set_output_capture(
1068+
sink: Option<LocalStream>,
1069+
) -> Result<Option<LocalStream>, AccessError> {
10571070
if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) {
10581071
// OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false.
1059-
return None;
1072+
return Ok(None);
10601073
}
10611074
OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed);
1062-
OUTPUT_CAPTURE.with(move |slot| slot.replace(sink))
1075+
OUTPUT_CAPTURE.try_with(move |slot| slot.replace(sink))
10631076
}
10641077

10651078
/// Write `args` to the capture buffer if enabled and possible, or `global_s`

library/std/src/panicking.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ use crate::sys_common::thread_info;
2525
use crate::thread;
2626

2727
#[cfg(not(test))]
28-
use crate::io::set_output_capture;
28+
use crate::io::try_set_output_capture;
2929
// make sure to use the stderr output configured
3030
// by libtest in the real copy of std
3131
#[cfg(test)]
32-
use realstd::io::set_output_capture;
32+
use realstd::io::try_set_output_capture;
3333

3434
// Binary interface to the panic runtime that the standard library depends on.
3535
//
@@ -285,9 +285,9 @@ fn default_hook(info: &PanicInfo<'_>) {
285285
}
286286
};
287287

288-
if let Some(local) = set_output_capture(None) {
288+
if let Ok(Some(local)) = try_set_output_capture(None) {
289289
write(&mut *local.lock().unwrap_or_else(|e| e.into_inner()));
290-
set_output_capture(Some(local));
290+
try_set_output_capture(Some(local)).ok();
291291
} else if let Some(mut out) = panic_output() {
292292
write(&mut out);
293293
}

0 commit comments

Comments
 (0)