@@ -275,6 +275,7 @@ use fmt;
275
275
use result;
276
276
use str;
277
277
use memchr;
278
+ use ptr;
278
279
279
280
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
280
281
pub use self :: buffered:: { BufReader , BufWriter , LineWriter } ;
@@ -292,7 +293,7 @@ pub use self::stdio::{stdin, stdout, stderr, Stdin, Stdout, Stderr};
292
293
pub use self :: stdio:: { StdoutLock , StderrLock , StdinLock } ;
293
294
#[ unstable( feature = "print_internals" , issue = "0" ) ]
294
295
pub use self :: stdio:: { _print, _eprint} ;
295
- #[ unstable( feature = "libstd_io_internals" , issue = "0 " ) ]
296
+ #[ unstable( feature = "libstd_io_internals" , issue = "42788 " ) ]
296
297
#[ doc( no_inline, hidden) ]
297
298
pub use self :: stdio:: { set_panic, set_print} ;
298
299
@@ -307,6 +308,14 @@ mod stdio;
307
308
308
309
const DEFAULT_BUF_SIZE : usize = :: sys_common:: io:: DEFAULT_BUF_SIZE ;
309
310
311
+ struct Guard < ' a > { buf : & ' a mut Vec < u8 > , len : usize }
312
+
313
+ impl < ' a > Drop for Guard < ' a > {
314
+ fn drop ( & mut self ) {
315
+ unsafe { self . buf . set_len ( self . len ) ; }
316
+ }
317
+ }
318
+
310
319
// A few methods below (read_to_string, read_line) will append data into a
311
320
// `String` buffer, but we need to be pretty careful when doing this. The
312
321
// implementation will just call `.as_mut_vec()` and then delegate to a
@@ -328,23 +337,16 @@ const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
328
337
fn append_to_string < F > ( buf : & mut String , f : F ) -> Result < usize >
329
338
where F : FnOnce ( & mut Vec < u8 > ) -> Result < usize >
330
339
{
331
- struct Guard < ' a > { s : & ' a mut Vec < u8 > , len : usize }
332
- impl < ' a > Drop for Guard < ' a > {
333
- fn drop ( & mut self ) {
334
- unsafe { self . s . set_len ( self . len ) ; }
335
- }
336
- }
337
-
338
340
unsafe {
339
- let mut g = Guard { len : buf. len ( ) , s : buf. as_mut_vec ( ) } ;
340
- let ret = f ( g. s ) ;
341
- if str:: from_utf8 ( & g. s [ g. len ..] ) . is_err ( ) {
341
+ let mut g = Guard { len : buf. len ( ) , buf : buf. as_mut_vec ( ) } ;
342
+ let ret = f ( g. buf ) ;
343
+ if str:: from_utf8 ( & g. buf [ g. len ..] ) . is_err ( ) {
342
344
ret. and_then ( |_| {
343
345
Err ( Error :: new ( ErrorKind :: InvalidData ,
344
346
"stream did not contain valid UTF-8" ) )
345
347
} )
346
348
} else {
347
- g. len = g. s . len ( ) ;
349
+ g. len = g. buf . len ( ) ;
348
350
ret
349
351
}
350
352
}
@@ -356,25 +358,32 @@ fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
356
358
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
357
359
// time is 4,500 times (!) slower than this if the reader has a very small
358
360
// amount of data to return.
361
+ //
362
+ // Because we're extending the buffer with uninitialized data for trusted
363
+ // readers, we need to make sure to truncate that if any of this panics.
359
364
fn read_to_end < R : Read + ?Sized > ( r : & mut R , buf : & mut Vec < u8 > ) -> Result < usize > {
360
365
let start_len = buf. len ( ) ;
361
- let mut len = start_len ;
366
+ let mut g = Guard { len : buf . len ( ) , buf : buf } ;
362
367
let mut new_write_size = 16 ;
363
368
let ret;
364
369
loop {
365
- if len == buf. len ( ) {
370
+ if g . len == g . buf . len ( ) {
366
371
if new_write_size < DEFAULT_BUF_SIZE {
367
372
new_write_size *= 2 ;
368
373
}
369
- buf. resize ( len + new_write_size, 0 ) ;
374
+ unsafe {
375
+ g. buf . reserve ( new_write_size) ;
376
+ g. buf . set_len ( g. len + new_write_size) ;
377
+ r. initializer ( ) . initialize ( & mut g. buf [ g. len ..] ) ;
378
+ }
370
379
}
371
380
372
- match r. read ( & mut buf[ len..] ) {
381
+ match r. read ( & mut g . buf [ g . len ..] ) {
373
382
Ok ( 0 ) => {
374
- ret = Ok ( len - start_len) ;
383
+ ret = Ok ( g . len - start_len) ;
375
384
break ;
376
385
}
377
- Ok ( n) => len += n,
386
+ Ok ( n) => g . len += n,
378
387
Err ( ref e) if e. kind ( ) == ErrorKind :: Interrupted => { }
379
388
Err ( e) => {
380
389
ret = Err ( e) ;
@@ -383,7 +392,6 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
383
392
}
384
393
}
385
394
386
- buf. truncate ( len) ;
387
395
ret
388
396
}
389
397
@@ -494,6 +502,31 @@ pub trait Read {
494
502
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
495
503
fn read ( & mut self , buf : & mut [ u8 ] ) -> Result < usize > ;
496
504
505
+ /// Determines if this `Read`er can work with buffers of uninitialized
506
+ /// memory.
507
+ ///
508
+ /// The default implementation returns an initializer which will zero
509
+ /// buffers.
510
+ ///
511
+ /// If a `Read`er guarantees that it can work properly with uninitialized
512
+ /// memory, it should call `Initializer::nop()`. See the documentation for
513
+ /// `Initializer` for details.
514
+ ///
515
+ /// The behavior of this method must be independent of the state of the
516
+ /// `Read`er - the method only takes `&self` so that it can be used through
517
+ /// trait objects.
518
+ ///
519
+ /// # Unsafety
520
+ ///
521
+ /// This method is unsafe because a `Read`er could otherwise return a
522
+ /// non-zeroing `Initializer` from another `Read` type without an `unsafe`
523
+ /// block.
524
+ #[ unstable( feature = "read_initializer" , issue = "42788" ) ]
525
+ #[ inline]
526
+ unsafe fn initializer ( & self ) -> Initializer {
527
+ Initializer :: zeroing ( )
528
+ }
529
+
497
530
/// Read all bytes until EOF in this source, placing them into `buf`.
498
531
///
499
532
/// All bytes read from this source will be appended to the specified buffer
@@ -829,6 +862,50 @@ pub trait Read {
829
862
}
830
863
}
831
864
865
+ /// A type used to conditionally initialize buffers passed to `Read` methods.
866
+ #[ unstable( feature = "read_initializer" , issue = "42788" ) ]
867
+ #[ derive( Debug ) ]
868
+ pub struct Initializer ( bool ) ;
869
+
870
+ impl Initializer {
871
+ /// Returns a new `Initializer` which will zero out buffers.
872
+ #[ unstable( feature = "read_initializer" , issue = "42788" ) ]
873
+ #[ inline]
874
+ pub fn zeroing ( ) -> Initializer {
875
+ Initializer ( true )
876
+ }
877
+
878
+ /// Returns a new `Initializer` which will not zero out buffers.
879
+ ///
880
+ /// # Unsafety
881
+ ///
882
+ /// This may only be called by `Read`ers which guarantee that they will not
883
+ /// read from buffers passed to `Read` methods, and that the return value of
884
+ /// the method accurately reflects the number of bytes that have been
885
+ /// written to the head of the buffer.
886
+ #[ unstable( feature = "read_initializer" , issue = "42788" ) ]
887
+ #[ inline]
888
+ pub unsafe fn nop ( ) -> Initializer {
889
+ Initializer ( false )
890
+ }
891
+
892
+ /// Indicates if a buffer should be initialized.
893
+ #[ unstable( feature = "read_initializer" , issue = "42788" ) ]
894
+ #[ inline]
895
+ pub fn should_initialize ( & self ) -> bool {
896
+ self . 0
897
+ }
898
+
899
+ /// Initializes a buffer if necessary.
900
+ #[ unstable( feature = "read_initializer" , issue = "42788" ) ]
901
+ #[ inline]
902
+ pub fn initialize ( & self , buf : & mut [ u8 ] ) {
903
+ if self . should_initialize ( ) {
904
+ unsafe { ptr:: write_bytes ( buf. as_mut_ptr ( ) , 0 , buf. len ( ) ) }
905
+ }
906
+ }
907
+ }
908
+
832
909
/// A trait for objects which are byte-oriented sinks.
833
910
///
834
911
/// Implementors of the `Write` trait are sometimes called 'writers'.
@@ -1608,6 +1685,15 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
1608
1685
}
1609
1686
self . second . read ( buf)
1610
1687
}
1688
+
1689
+ unsafe fn initializer ( & self ) -> Initializer {
1690
+ let initializer = self . first . initializer ( ) ;
1691
+ if initializer. should_initialize ( ) {
1692
+ initializer
1693
+ } else {
1694
+ self . second . initializer ( )
1695
+ }
1696
+ }
1611
1697
}
1612
1698
1613
1699
#[ stable( feature = "chain_bufread" , since = "1.9.0" ) ]
@@ -1772,6 +1858,10 @@ impl<T: Read> Read for Take<T> {
1772
1858
self . limit -= n as u64 ;
1773
1859
Ok ( n)
1774
1860
}
1861
+
1862
+ unsafe fn initializer ( & self ) -> Initializer {
1863
+ self . inner . initializer ( )
1864
+ }
1775
1865
}
1776
1866
1777
1867
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
0 commit comments