use prelude::v1::*;
use io::prelude::*;
-use cell::RefCell;
+use cell::{RefCell, BorrowState};
use cmp;
use fmt;
use io::lazy::Lazy;
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.lock().write_all(buf)
}
- fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
- self.lock().write_fmt(fmt)
- }
+ // Don't override write_fmt as it's possible to run arbitrary code during a
+ // write_fmt, allowing the possibility of a recursive lock (aka deadlock)
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for StdoutLock<'a> {
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.lock().write_all(buf)
}
- fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
- self.lock().write_fmt(fmt)
- }
+ // Don't override write_fmt for the same reasons as Stdout
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for StderrLock<'a> {
reason = "implementation detail which may disappear or be replaced at any time")]
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
- if let Err(e) = LOCAL_STDOUT.with(|s| match s.borrow_mut().as_mut() {
- Some(w) => w.write_fmt(args),
- None => stdout().write_fmt(args)
- }) {
+ let result = LOCAL_STDOUT.with(|s| {
+ if s.borrow_state() == BorrowState::Unused {
+ if let Some(w) = s.borrow_mut().as_mut() {
+ return w.write_fmt(args);
+ }
+ }
+ stdout().write_fmt(args)
+ });
+ if let Err(e) = result {
panic!("failed printing to stdout: {}", e);
}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::fmt;
+
+struct Foo;
+impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ println!("<Foo as Debug>::fmt()");
+
+ write!(fmt, "")
+ }
+}
+
+fn test1() {
+ let foo_str = format!("{:?}", Foo);
+
+ println!("{}", foo_str);
+}
+
+fn test2() {
+ println!("{:?}", Foo);
+}
+
+fn main() {
+ // This works fine
+ test1();
+
+ // This fails
+ test2();
+}