Check for overflow in Cursor<Vec<u8>>::write.

Ensure that cursor position fits into usize, before proceeding with
write. Fixes issue #36884.
This commit is contained in:
Tomasz Miąsko 2016-10-01 00:00:00 +02:00
parent 5045d4e396
commit 4935343f6e
1 changed files with 18 additions and 7 deletions

View File

@ -10,6 +10,7 @@
use io::prelude::*;
use core::convert::TryInto;
use cmp;
use io::{self, SeekFrom, Error, ErrorKind};
@ -242,18 +243,20 @@ impl<'a> Write for Cursor<&'a mut [u8]> {
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Cursor<Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let pos: usize = self.position().try_into().map_err(|_| {
Error::new(ErrorKind::InvalidInput,
"cursor position exceeds maximum possible vector length")
})?;
// Make sure the internal buffer is as least as big as where we
// currently are
let pos = self.position();
let amt = pos.saturating_sub(self.inner.len() as u64);
// use `resize` so that the zero filling is as efficient as possible
let len = self.inner.len();
self.inner.resize(len + amt as usize, 0);
if len < pos {
// use `resize` so that the zero filling is as efficient as possible
self.inner.resize(pos, 0);
}
// Figure out what bytes will be used to overwrite what's currently
// there (left), and what will be appended on the end (right)
{
let pos = pos as usize;
let space = self.inner.len() - pos;
let (left, right) = buf.split_at(cmp::min(space, buf.len()));
self.inner[pos..pos + left.len()].copy_from_slice(left);
@ -261,7 +264,7 @@ impl Write for Cursor<Vec<u8>> {
}
// Bump us forward
self.set_position(pos + buf.len() as u64);
self.set_position((pos + buf.len()) as u64);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
@ -580,4 +583,12 @@ mod tests {
let mut r = Cursor::new(Vec::new());
assert!(r.seek(SeekFrom::End(-2)).is_err());
}
#[test]
#[cfg(target_pointer_width = "32")]
fn vec_seek_and_write_past_usize_max() {
let mut c = Cursor::new(Vec::new());
c.set_position(<usize>::max_value() as u64 + 1);
assert!(c.write_all(&[1, 2, 3]).is_err());
}
}