#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufReader<R> {
inner: R,
- buf: Vec<u8>,
+ buf: Box<[u8]>,
pos: usize,
cap: usize,
}
pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
BufReader {
inner: inner,
- buf: vec![0; cap],
+ buf: vec![0; cap].into_boxed_slice(),
pos: 0,
cap: 0,
}
pub struct BufWriter<W: Write> {
inner: Option<W>,
buf: Vec<u8>,
+ // #30888: If the inner writer panics in a call to write, we don't want to
+ // write the buffered data a second time in BufWriter's destructor. This
+ // flag tells the Drop impl if it should skip the flush.
+ panicked: bool,
}
/// An error returned by `into_inner` which combines an error that
BufWriter {
inner: Some(inner),
buf: Vec::with_capacity(cap),
+ panicked: false,
}
}
let len = self.buf.len();
let mut ret = Ok(());
while written < len {
- match self.inner.as_mut().unwrap().write(&self.buf[written..]) {
+ self.panicked = true;
+ let r = self.inner.as_mut().unwrap().write(&self.buf[written..]);
+ self.panicked = false;
+
+ match r {
Ok(0) => {
ret = Err(Error::new(ErrorKind::WriteZero,
"failed to write the buffered data"));
try!(self.flush_buf());
}
if buf.len() >= self.buf.capacity() {
- self.inner.as_mut().unwrap().write(buf)
+ self.panicked = true;
+ let r = self.inner.as_mut().unwrap().write(buf);
+ self.panicked = false;
+ r
} else {
let amt = cmp::min(buf.len(), self.buf.capacity());
Write::write(&mut self.buf, &buf[..amt])
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Drop for BufWriter<W> {
fn drop(&mut self) {
- if self.inner.is_some() {
+ if self.inner.is_some() && !self.panicked {
// dtors should not panic, so we ignore a failed flush
let _r = self.flush_buf();
}
use prelude::v1::*;
use io::prelude::*;
use io::{self, BufReader, BufWriter, LineWriter, SeekFrom};
+ use sync::atomic::{AtomicUsize, Ordering};
+ use thread;
use test;
/// A dummy reader intended at testing short-reads propagation.
panic!();
}
+ #[test]
+ fn panic_in_write_doesnt_flush_in_drop() {
+ static WRITES: AtomicUsize = AtomicUsize::new(0);
+
+ struct PanicWriter;
+
+ impl Write for PanicWriter {
+ fn write(&mut self, _: &[u8]) -> io::Result<usize> {
+ WRITES.fetch_add(1, Ordering::SeqCst);
+ panic!();
+ }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+ }
+
+ thread::spawn(|| {
+ let mut writer = BufWriter::new(PanicWriter);
+ let _ = writer.write(b"hello world");
+ let _ = writer.flush();
+ }).join().err().unwrap();
+
+ assert_eq!(WRITES.load(Ordering::SeqCst), 1);
+ }
+
#[bench]
fn bench_buffered_reader(b: &mut test::Bencher) {
b.iter(|| {