Skip to content

Commit

Permalink
std: Don't abort process when printing panics in tests
Browse files Browse the repository at this point in the history
This commit fixes an issue when using `set_print` and friends, notably
used by libtest, to avoid aborting the process if printing panics. This
previously panicked due to borrowing a mutable `RefCell` twice, and this
is worked around by borrowing these cells for less time, instead
taking out and removing contents temporarily.

Closes rust-lang#69558
  • Loading branch information
alexcrichton committed Mar 13, 2020
1 parent 23de827 commit 7d31795
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 4 deletions.
12 changes: 8 additions & 4 deletions src/libstd/io/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -792,10 +792,14 @@ fn print_to<T>(
{
let result = local_s
.try_with(|s| {
if let Ok(mut borrowed) = s.try_borrow_mut() {
if let Some(w) = borrowed.as_mut() {
return w.write_fmt(args);
}
// Note that we completely remove a local sink to write to in case
// our printing recursively panics/prints, so the recursive
// panic/print goes to the global sink instead of our local sink.
let prev = s.borrow_mut().take();
if let Some(mut w) = prev {
let result = w.write_fmt(args);
*s.borrow_mut() = Some(w);
return result;
}
global_s().write_fmt(args)
})
Expand Down
23 changes: 23 additions & 0 deletions src/test/ui/panic-while-printing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// run-pass

#![feature(set_stdio)]

use std::fmt;
use std::fmt::{Display, Formatter};
use std::io::set_panic;

pub struct A;

impl Display for A {
fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
panic!();
}
}

fn main() {
set_panic(Some(Box::new(Vec::new())));
assert!(std::panic::catch_unwind(|| {
eprintln!("{}", A);
})
.is_err());
}
23 changes: 23 additions & 0 deletions src/test/ui/test-panic-while-printing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// compile-flags:--test
// run-pass

use std::fmt;
use std::fmt::{Display, Formatter};

pub struct A(Vec<u32>);

impl Display for A {
fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
self.0[0];
Ok(())
}
}

#[test]
fn main() {
let result = std::panic::catch_unwind(|| {
let a = A(vec![]);
eprintln!("{}", a);
});
assert!(result.is_err());
}

0 comments on commit 7d31795

Please sign in to comment.