|
11 | 11 | use prelude::v1::*; |
12 | 12 | use io::prelude::*; |
13 | 13 |
|
14 | | -use cell::RefCell; |
| 14 | +use cell::{RefCell, BorrowState}; |
15 | 15 | use cmp; |
16 | 16 | use fmt; |
17 | 17 | use io::lazy::Lazy; |
@@ -264,9 +264,8 @@ impl Write for Stdout { |
264 | 264 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
265 | 265 | self.lock().write_all(buf) |
266 | 266 | } |
267 | | - fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { |
268 | | - self.lock().write_fmt(fmt) |
269 | | - } |
| 267 | + // Don't override write_fmt as it's possible to run arbitrary code during a |
| 268 | + // write_fmt, allowing the possibility of a recursive lock (aka deadlock) |
270 | 269 | } |
271 | 270 | #[stable(feature = "rust1", since = "1.0.0")] |
272 | 271 | impl<'a> Write for StdoutLock<'a> { |
@@ -334,9 +333,7 @@ impl Write for Stderr { |
334 | 333 | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { |
335 | 334 | self.lock().write_all(buf) |
336 | 335 | } |
337 | | - fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { |
338 | | - self.lock().write_fmt(fmt) |
339 | | - } |
| 336 | + // Don't override write_fmt for the same reasons as Stdout |
340 | 337 | } |
341 | 338 | #[stable(feature = "rust1", since = "1.0.0")] |
342 | 339 | impl<'a> Write for StderrLock<'a> { |
@@ -395,10 +392,15 @@ pub fn set_print(sink: Box<Write + Send>) -> Option<Box<Write + Send>> { |
395 | 392 | reason = "implementation detail which may disappear or be replaced at any time")] |
396 | 393 | #[doc(hidden)] |
397 | 394 | pub fn _print(args: fmt::Arguments) { |
398 | | - if let Err(e) = LOCAL_STDOUT.with(|s| match s.borrow_mut().as_mut() { |
399 | | - Some(w) => w.write_fmt(args), |
400 | | - None => stdout().write_fmt(args) |
401 | | - }) { |
| 395 | + let result = LOCAL_STDOUT.with(|s| { |
| 396 | + if s.borrow_state() == BorrowState::Unused { |
| 397 | + if let Some(w) = s.borrow_mut().as_mut() { |
| 398 | + return w.write_fmt(args); |
| 399 | + } |
| 400 | + } |
| 401 | + stdout().write_fmt(args) |
| 402 | + }); |
| 403 | + if let Err(e) = result { |
402 | 404 | panic!("failed printing to stdout: {}", e); |
403 | 405 | } |
404 | 406 | } |
|
0 commit comments