about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-02-21 16:04:44 +0000
committerbors <bors@rust-lang.org>2017-02-21 16:04:44 +0000
commit8a1ce4020c480e455ec902e3616843a3dd5fe489 (patch)
tree61f01c0b5cfecf3331188b0301892e313ca6ac51 /src/libstd
parent3954c70537cc78dc4a8e28c6ffa0a8ae5198387a (diff)
parenta2d176e8f4774b84db22540a45eed7b29482f154 (diff)
downloadrust-8a1ce4020c480e455ec902e3616843a3dd5fe489.tar.gz
rust-8a1ce4020c480e455ec902e3616843a3dd5fe489.zip
Auto merge of #39874 - amosonn:master, r=alexcrichton
Fixes overflow in libsdt/io/cursor.rs "seek"

Fixes #39631
Test which fails (with old implementation), then fix to implementation.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/io/cursor.rs59
1 files changed, 49 insertions, 10 deletions
diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs
index 0cff8661d88..60767ea4786 100644
--- a/src/libstd/io/cursor.rs
+++ b/src/libstd/io/cursor.rs
@@ -200,18 +200,20 @@ impl<T> Cursor<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> io::Seek for Cursor<T> where T: AsRef<[u8]> {
     fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
-        let pos = match style {
-            SeekFrom::Start(n) => { self.pos = n; return Ok(n) }
-            SeekFrom::End(n) => self.inner.as_ref().len() as i64 + n,
-            SeekFrom::Current(n) => self.pos as i64 + n,
+        let (base_pos, offset) = match style {
+            SeekFrom::Start(n) => { self.pos = n; return Ok(n); }
+            SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n),
+            SeekFrom::Current(n) => (self.pos, n),
         };
-
-        if pos < 0 {
-            Err(Error::new(ErrorKind::InvalidInput,
-                           "invalid seek to a negative position"))
+        let new_pos = if offset >= 0 {
+            base_pos.checked_add(offset as u64)
         } else {
-            self.pos = pos as u64;
-            Ok(self.pos)
+            base_pos.checked_sub((offset.wrapping_neg()) as u64)
+        };
+        match new_pos {
+            Some(n) => {self.pos = n; Ok(self.pos)}
+            None => Err(Error::new(ErrorKind::InvalidInput,
+                           "invalid seek to a negative or overflowing position"))
         }
     }
 }
@@ -527,6 +529,43 @@ mod tests {
     }
 
     #[test]
+    fn seek_past_i64() {
+        let buf = [0xff];
+        let mut r = Cursor::new(&buf[..]);
+        assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+        assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+        assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+        assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+        assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+        assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+        let mut r = Cursor::new(vec![10]);
+        assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+        assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+        assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+        assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+        assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+        assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+        let mut buf = [0];
+        let mut r = Cursor::new(&mut buf[..]);
+        assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+        assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+        assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+        assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+        assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+        assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+        let mut r = Cursor::new(vec![10].into_boxed_slice());
+        assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+        assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+        assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+        assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+        assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+        assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+    }
+
+    #[test]
     fn seek_before_0() {
         let buf = [0xff];
         let mut r = Cursor::new(&buf[..]);