Skip to content

Commit 7dbba3d

Browse files
committed
Auto merge of #58464 - jethrogb:jb/std-test-panic-output, r=alexcrichton
Use the correct stderr when testing libstd When compiling the unit tests for libstd, there are two copies of `std` in existence, see [lib.rs](https://github.com/rust-lang/rust/blob/919cf42/src/libstd/lib.rs#L335-L341). This means there are two copies of everything, including thread local variable definitions. Before this PR, it's possible that libtest would configure a stderr sink in one of those copies, whereas the panic logic would inspect the sink in the other copy, resulting in libtest missing the relevant panic message. This PR makes sure that when testing, the panic logic always accesses the stderr sink from “realstd”, using the same logic that libtest uses.
2 parents 0ea2271 + c0e8cf9 commit 7dbba3d

File tree

4 files changed

+41
-19
lines changed

4 files changed

+41
-19
lines changed

src/libstd/io/impls.rs

+14
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,20 @@ impl<B: BufRead + ?Sized> BufRead for Box<B> {
165165
}
166166
}
167167

168+
// Used by panicking::default_hook
169+
#[cfg(test)]
170+
/// This impl is only used by printing logic, so any error returned is always
171+
/// of kind `Other`, and should be ignored.
172+
impl Write for Box<dyn (::realstd::io::Write) + Send> {
173+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
174+
(**self).write(buf).map_err(|_| ErrorKind::Other.into())
175+
}
176+
177+
fn flush(&mut self) -> io::Result<()> {
178+
(**self).flush().map_err(|_| ErrorKind::Other.into())
179+
}
180+
}
181+
168182
// =============================================================================
169183
// In-memory buffer implementations
170184

src/libstd/io/stdio.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![cfg_attr(test, allow(unused))]
2+
13
use crate::io::prelude::*;
24

35
use crate::cell::RefCell;
@@ -16,6 +18,13 @@ thread_local! {
1618
}
1719
}
1820

21+
/// Stderr used by eprint! and eprintln! macros, and panics
22+
thread_local! {
23+
static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = {
24+
RefCell::new(None)
25+
}
26+
}
27+
1928
/// A handle to a raw instance of the standard input stream of this process.
2029
///
2130
/// This handle is not synchronized or buffered in any fashion. Constructed via
@@ -668,7 +677,6 @@ impl fmt::Debug for StderrLock<'_> {
668677
issue = "0")]
669678
#[doc(hidden)]
670679
pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
671-
use crate::panicking::LOCAL_STDERR;
672680
use crate::mem;
673681
LOCAL_STDERR.with(move |slot| {
674682
mem::replace(&mut *slot.borrow_mut(), sink)
@@ -740,6 +748,7 @@ where
740748
reason = "implementation detail which may disappear or be replaced at any time",
741749
issue = "0")]
742750
#[doc(hidden)]
751+
#[cfg(not(test))]
743752
pub fn _print(args: fmt::Arguments) {
744753
print_to(args, &LOCAL_STDOUT, stdout, "stdout");
745754
}
@@ -748,11 +757,14 @@ pub fn _print(args: fmt::Arguments) {
748757
reason = "implementation detail which may disappear or be replaced at any time",
749758
issue = "0")]
750759
#[doc(hidden)]
760+
#[cfg(not(test))]
751761
pub fn _eprint(args: fmt::Arguments) {
752-
use crate::panicking::LOCAL_STDERR;
753762
print_to(args, &LOCAL_STDERR, stderr, "stderr");
754763
}
755764

765+
#[cfg(test)]
766+
pub use realstd::io::{_eprint, _print};
767+
756768
#[cfg(test)]
757769
mod tests {
758770
use crate::panic::{UnwindSafe, RefUnwindSafe};

src/libstd/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@
219219
// std may use features in a platform-specific way
220220
#![allow(unused_features)]
221221

222-
#![cfg_attr(test, feature(test, update_panic_count))]
222+
#![cfg_attr(test, feature(print_internals, set_stdio, test, update_panic_count))]
223223
#![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"),
224224
feature(global_asm, range_contains, slice_index_methods,
225225
decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))]

src/libstd/panicking.rs

+12-16
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,9 @@
77
//! * Executing a panic up to doing the actual implementation
88
//! * Shims around "try"
99
10-
use core::panic::BoxMeUp;
11-
use core::panic::{PanicInfo, Location};
12-
13-
use crate::io::prelude::*;
10+
use core::panic::{BoxMeUp, PanicInfo, Location};
1411

1512
use crate::any::Any;
16-
use crate::cell::RefCell;
1713
use crate::fmt;
1814
use crate::intrinsics;
1915
use crate::mem;
@@ -25,11 +21,12 @@ use crate::sys_common::thread_info;
2521
use crate::sys_common::util;
2622
use crate::thread;
2723

28-
thread_local! {
29-
pub static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = {
30-
RefCell::new(None)
31-
}
32-
}
24+
#[cfg(not(test))]
25+
use crate::io::set_panic;
26+
// make sure to use the stderr output configured
27+
// by libtest in the real copy of std
28+
#[cfg(test)]
29+
use realstd::io::set_panic;
3330

3431
// Binary interface to the panic runtime that the standard library depends on.
3532
//
@@ -205,12 +202,11 @@ fn default_hook(info: &PanicInfo) {
205202
}
206203
};
207204

208-
if let Some(mut local) = LOCAL_STDERR.with(|s| s.borrow_mut().take()) {
209-
write(&mut *local);
210-
let mut s = Some(local);
211-
LOCAL_STDERR.with(|slot| {
212-
*slot.borrow_mut() = s.take();
213-
});
205+
if let Some(mut local) = set_panic(None) {
206+
// NB. In `cfg(test)` this uses the forwarding impl
207+
// for `Box<dyn (::realstd::io::Write) + Send>`.
208+
write(&mut local);
209+
set_panic(Some(local));
214210
} else if let Some(mut out) = panic_output() {
215211
write(&mut out);
216212
}

0 commit comments

Comments
 (0)