about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-19 06:57:36 +0100
committerGitHub <noreply@github.com>2020-03-19 06:57:36 +0100
commit73c3a496cc8ce261e87abbd998b36ab16dab4f4b (patch)
tree92afedadaf106abf4705ade8129565cf9f22ced8
parent904909fd06cd203cea1651910962943b8338286c (diff)
parentd5b6a20557743911ff9f90af5d8ad24c699570d3 (diff)
Rollup merge of #69959 - alexcrichton:fix-panic-in-print, r=Mark-Simulacrum
std: Don't abort process when printing panics in tests

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 #69558
-rw-r--r--src/libstd/io/stdio.rs12
-rw-r--r--src/test/ui/panic-while-printing.rs24
-rw-r--r--src/test/ui/test-panic-while-printing.rs24
3 files changed, 56 insertions, 4 deletions
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index d410faca30d..0fb0757792e 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -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)
         })
diff --git a/src/test/ui/panic-while-printing.rs b/src/test/ui/panic-while-printing.rs
new file mode 100644
index 00000000000..7e9fa16b084
--- /dev/null
+++ b/src/test/ui/panic-while-printing.rs
@@ -0,0 +1,24 @@
+// run-pass
+// ignore-emscripten no subprocess support
+
+#![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());
+}
diff --git a/src/test/ui/test-panic-while-printing.rs b/src/test/ui/test-panic-while-printing.rs
new file mode 100644
index 00000000000..23f45407c1a
--- /dev/null
+++ b/src/test/ui/test-panic-while-printing.rs
@@ -0,0 +1,24 @@
+// compile-flags:--test
+// run-pass
+// ignore-emscripten no subprocess support
+
+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());
+}