about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorEduardo Sánchez Muñoz <eduardosm-dev@e64.io>2023-09-22 20:44:56 +0200
committerEduardo Sánchez Muñoz <eduardosm-dev@e64.io>2023-09-23 16:27:57 +0200
commit93863383c8240c35f6bfda97ab96fd5ce8a5783c (patch)
tree0f34f2be5a91ac1fd6d37c5b58baa9abf482ec8a /library/std/src
parent959b2c703d45f06962da3afa086bdda70d42efcf (diff)
downloadrust-93863383c8240c35f6bfda97ab96fd5ce8a5783c.tar.gz
rust-93863383c8240c35f6bfda97ab96fd5ce8a5783c.zip
Avoid overflow in `IoSlice::advance_slices`
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/io/mod.rs35
1 files changed, 19 insertions, 16 deletions
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 7582c7444f0..604b795cd52 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1236,22 +1236,22 @@ impl<'a> IoSliceMut<'a> {
     pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) {
         // Number of buffers to remove.
         let mut remove = 0;
-        // Total length of all the to be removed buffers.
-        let mut accumulated_len = 0;
+        // Remaining length before reaching n.
+        let mut left = n;
         for buf in bufs.iter() {
-            if accumulated_len + buf.len() > n {
-                break;
-            } else {
-                accumulated_len += buf.len();
+            if let Some(remainder) = left.checked_sub(buf.len()) {
+                left = remainder;
                 remove += 1;
+            } else {
+                break;
             }
         }
 
         *bufs = &mut take(bufs)[remove..];
         if bufs.is_empty() {
-            assert!(n == accumulated_len, "advancing io slices beyond their length");
+            assert!(left == 0, "advancing io slices beyond their length");
         } else {
-            bufs[0].advance(n - accumulated_len)
+            bufs[0].advance(left);
         }
     }
 }
@@ -1379,22 +1379,25 @@ impl<'a> IoSlice<'a> {
     pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) {
         // Number of buffers to remove.
         let mut remove = 0;
-        // Total length of all the to be removed buffers.
-        let mut accumulated_len = 0;
+        // Remaining length before reaching n. This prevents overflow
+        // that could happen if the length of slices in `bufs` were instead
+        // accumulated. Those slice may be aliased and, if they are large
+        // enough, their added length may overflow a `usize`.
+        let mut left = n;
         for buf in bufs.iter() {
-            if accumulated_len + buf.len() > n {
-                break;
-            } else {
-                accumulated_len += buf.len();
+            if let Some(remainder) = left.checked_sub(buf.len()) {
+                left = remainder;
                 remove += 1;
+            } else {
+                break;
             }
         }
 
         *bufs = &mut take(bufs)[remove..];
         if bufs.is_empty() {
-            assert!(n == accumulated_len, "advancing io slices beyond their length");
+            assert!(left == 0, "advancing io slices beyond their length");
         } else {
-            bufs[0].advance(n - accumulated_len)
+            bufs[0].advance(left);
         }
     }
 }