diff options
| author | bors <bors@rust-lang.org> | 2019-03-21 05:41:13 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-03-21 05:41:13 +0000 |
| commit | 15a5dfa0b4438d199e8703fd578f59a5049527be (patch) | |
| tree | 51e15ceab136bccaf4555d033d83b3d517c39837 /src/libstd/io | |
| parent | 20958fc81f5be100fba90db91539d58fa89c948e (diff) | |
| parent | c36d91c5cc446a4688186be1071e0e139ba9d38f (diff) | |
| download | rust-15a5dfa0b4438d199e8703fd578f59a5049527be.tar.gz rust-15a5dfa0b4438d199e8703fd578f59a5049527be.zip | |
Auto merge of #58913 - Milack27:patch_buf_reader, r=joshtriplett
Add new test case for possible bug in BufReader When reading a large chunk from a BufReader, if all the bytes from the buffer have been already consumed, the internal buffer is bypassed entirely. However, it is not invalidated, and it's possible to access its contents using the `seek_relative` method, because it tries to reuse the existing buffer.
Diffstat (limited to 'src/libstd/io')
| -rw-r--r-- | src/libstd/io/buffered.rs | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index a14c10d0b61..4668e3ec7ea 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -193,6 +193,13 @@ impl<R> BufReader<R> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> R { self.inner } + + /// Invalidates all data in the internal buffer. + #[inline] + fn discard_buffer(&mut self) { + self.pos = 0; + self.cap = 0; + } } impl<R: Seek> BufReader<R> { @@ -227,6 +234,7 @@ impl<R: Read> Read for BufReader<R> { // (larger than our internal buffer), bypass our internal buffer // entirely. if self.pos == self.cap && buf.len() >= self.buf.len() { + self.discard_buffer(); return self.inner.read(buf); } let nread = { @@ -240,6 +248,7 @@ impl<R: Read> Read for BufReader<R> { fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { let total_len = bufs.iter().map(|b| b.len()).sum::<usize>(); if self.pos == self.cap && total_len >= self.buf.len() { + self.discard_buffer(); return self.inner.read_vectored(bufs); } let nread = { @@ -325,14 +334,14 @@ impl<R: Seek> Seek for BufReader<R> { } else { // seek backwards by our remainder, and then by the offset self.inner.seek(SeekFrom::Current(-remainder))?; - self.pos = self.cap; // empty the buffer + self.discard_buffer(); result = self.inner.seek(SeekFrom::Current(n))?; } } else { // Seeking with Start/End doesn't care about our buffer length. result = self.inner.seek(pos)?; } - self.pos = self.cap; // empty the buffer + self.discard_buffer(); Ok(result) } } @@ -1069,6 +1078,40 @@ mod tests { } #[test] + fn test_buffered_reader_invalidated_after_read() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); + + assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); + reader.consume(3); + + let mut buffer = [0, 0, 0, 0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(5)); + assert_eq!(buffer, [0, 1, 2, 3, 4]); + + assert!(reader.seek_relative(-2).is_ok()); + let mut buffer = [0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(2)); + assert_eq!(buffer, [3, 4]); + } + + #[test] + fn test_buffered_reader_invalidated_after_seek() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); + + assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); + reader.consume(3); + + assert!(reader.seek(SeekFrom::Current(5)).is_ok()); + + assert!(reader.seek_relative(-2).is_ok()); + let mut buffer = [0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(2)); + assert_eq!(buffer, [3, 4]); + } + + #[test] fn test_buffered_reader_seek_underflow() { // gimmick reader that yields its position modulo 256 for each byte struct PositionReader { |
