@@ -300,6 +300,10 @@ impl<R: Seek> Seek for BufReader<R> {
300
300
pub struct BufWriter < W : Write > {
301
301
inner : Option < W > ,
302
302
buf : Vec < u8 > ,
303
+ // #30888: If the inner writer panics in a call to write, we don't want to
304
+ // write the buffered data a second time in BufWriter's destructor. This
305
+ // flag tells the Drop impl if it should skip the flush.
306
+ panicked : bool ,
303
307
}
304
308
305
309
/// An error returned by `into_inner` which combines an error that
@@ -364,6 +368,7 @@ impl<W: Write> BufWriter<W> {
364
368
BufWriter {
365
369
inner : Some ( inner) ,
366
370
buf : Vec :: with_capacity ( cap) ,
371
+ panicked : false ,
367
372
}
368
373
}
369
374
@@ -372,7 +377,11 @@ impl<W: Write> BufWriter<W> {
372
377
let len = self . buf . len ( ) ;
373
378
let mut ret = Ok ( ( ) ) ;
374
379
while written < len {
375
- match self . inner . as_mut ( ) . unwrap ( ) . write ( & self . buf [ written..] ) {
380
+ self . panicked = true ;
381
+ let r = self . inner . as_mut ( ) . unwrap ( ) . write ( & self . buf [ written..] ) ;
382
+ self . panicked = false ;
383
+
384
+ match r {
376
385
Ok ( 0 ) => {
377
386
ret = Err ( Error :: new ( ErrorKind :: WriteZero ,
378
387
"failed to write the buffered data" ) ) ;
@@ -455,7 +464,10 @@ impl<W: Write> Write for BufWriter<W> {
455
464
try!( self . flush_buf ( ) ) ;
456
465
}
457
466
if buf. len ( ) >= self . buf . capacity ( ) {
458
- self . inner . as_mut ( ) . unwrap ( ) . write ( buf)
467
+ self . panicked = true ;
468
+ let r = self . inner . as_mut ( ) . unwrap ( ) . write ( buf) ;
469
+ self . panicked = false ;
470
+ r
459
471
} else {
460
472
let amt = cmp:: min ( buf. len ( ) , self . buf . capacity ( ) ) ;
461
473
Write :: write ( & mut self . buf , & buf[ ..amt] )
@@ -489,7 +501,7 @@ impl<W: Write + Seek> Seek for BufWriter<W> {
489
501
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
490
502
impl < W : Write > Drop for BufWriter < W > {
491
503
fn drop ( & mut self ) {
492
- if self . inner . is_some ( ) {
504
+ if self . inner . is_some ( ) && ! self . panicked {
493
505
// dtors should not panic, so we ignore a failed flush
494
506
let _r = self . flush_buf ( ) ;
495
507
}
@@ -777,6 +789,8 @@ mod tests {
777
789
use prelude:: v1:: * ;
778
790
use io:: prelude:: * ;
779
791
use io:: { self , BufReader , BufWriter , LineWriter , SeekFrom } ;
792
+ use sync:: atomic:: { AtomicUsize , Ordering } ;
793
+ use thread;
780
794
use test;
781
795
782
796
/// A dummy reader intended at testing short-reads propagation.
@@ -1065,6 +1079,29 @@ mod tests {
1065
1079
panic ! ( ) ;
1066
1080
}
1067
1081
1082
+ #[ test]
1083
+ fn panic_in_write_doesnt_flush_in_drop ( ) {
1084
+ static WRITES : AtomicUsize = AtomicUsize :: new ( 0 ) ;
1085
+
1086
+ struct PanicWriter ;
1087
+
1088
+ impl Write for PanicWriter {
1089
+ fn write ( & mut self , _: & [ u8 ] ) -> io:: Result < usize > {
1090
+ WRITES . fetch_add ( 1 , Ordering :: SeqCst ) ;
1091
+ panic ! ( ) ;
1092
+ }
1093
+ fn flush ( & mut self ) -> io:: Result < ( ) > { Ok ( ( ) ) }
1094
+ }
1095
+
1096
+ thread:: spawn ( || {
1097
+ let mut writer = BufWriter :: new ( PanicWriter ) ;
1098
+ writer. write ( b"hello world" ) ;
1099
+ writer. flush ( ) ;
1100
+ } ) . join ( ) . err ( ) . unwrap ( ) ;
1101
+
1102
+ assert_eq ! ( WRITES . load( Ordering :: SeqCst ) , 1 ) ;
1103
+ }
1104
+
1068
1105
#[ bench]
1069
1106
fn bench_buffered_reader ( b : & mut test:: Bencher ) {
1070
1107
b. iter ( || {
0 commit comments