summaryrefslogtreecommitdiff
path: root/dev-lang/rust/files/rustc-1.51.0-backport-pr82292.patch
blob: 4baf72a26190c86d34c8443564a8de30ddaec5df (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
From 0babb88efc4d36f3defafc3c3c0343793fa05d52 Mon Sep 17 00:00:00 2001
From: Giacomo Stevanato <giaco.stevanato@gmail.com>
Date: Wed, 3 Mar 2021 21:09:01 +0100
Subject: [PATCH 1/2] Prevent Zip specialization from calling
 __iterator_get_unchecked twice with the same index after calling next_back

(cherry picked from commit 2371914a05f8f2763dffe6e2511d0870bcd6b461)
---
 library/core/src/iter/adapters/zip.rs | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs
index dcbcb1ce7200..7dac0c63ca2d 100644
--- a/library/core/src/iter/adapters/zip.rs
+++ b/library/core/src/iter/adapters/zip.rs
@@ -13,9 +13,10 @@
 pub struct Zip<A, B> {
     a: A,
     b: B,
-    // index and len are only used by the specialized version of zip
+    // index, len and a_len are only used by the specialized version of zip
     index: usize,
     len: usize,
+    a_len: usize,
 }
 impl<A: Iterator, B: Iterator> Zip<A, B> {
     pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
@@ -110,6 +111,7 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
             b,
             index: 0, // unused
             len: 0,   // unused
+            a_len: 0, // unused
         }
     }
 
@@ -184,8 +186,9 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
     B: TrustedRandomAccess + Iterator,
 {
     fn new(a: A, b: B) -> Self {
-        let len = cmp::min(a.size(), b.size());
-        Zip { a, b, index: 0, len }
+        let a_len = a.size();
+        let len = cmp::min(a_len, b.size());
+        Zip { a, b, index: 0, len, a_len }
     }
 
     #[inline]
@@ -197,7 +200,7 @@ fn next(&mut self) -> Option<(A::Item, B::Item)> {
             unsafe {
                 Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
             }
-        } else if A::may_have_side_effect() && self.index < self.a.size() {
+        } else if A::may_have_side_effect() && self.index < self.a_len {
             let i = self.index;
             self.index += 1;
             self.len += 1;
@@ -264,6 +267,7 @@ fn next_back(&mut self) -> Option<(A::Item, B::Item)>
                     for _ in 0..sz_a - self.len {
                         self.a.next_back();
                     }
+                    self.a_len = self.len;
                 }
                 let sz_b = self.b.size();
                 if b_side_effect && sz_b > self.len {
@@ -275,6 +279,7 @@ fn next_back(&mut self) -> Option<(A::Item, B::Item)>
         }
         if self.index < self.len {
             self.len -= 1;
+            self.a_len -= 1;
             let i = self.len;
             // SAFETY: `i` is smaller than the previous value of `self.len`,
             // which is also smaller than or equal to `self.a.len()` and `self.b.len()`
-- 
2.31.1


From 19af66a6f3e2bbb4780bb9eae7eb53bd13e3dd0f Mon Sep 17 00:00:00 2001
From: Giacomo Stevanato <giaco.stevanato@gmail.com>
Date: Fri, 19 Feb 2021 15:25:09 +0100
Subject: [PATCH 2/2] Add relevant test

(cherry picked from commit c1bfb9a78db6d481be1d03355672712c766e20b0)
---
 library/core/tests/iter/adapters/zip.rs | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs
index a59771039295..000c15f72c88 100644
--- a/library/core/tests/iter/adapters/zip.rs
+++ b/library/core/tests/iter/adapters/zip.rs
@@ -265,3 +265,26 @@ fn overflowed_zip(arr: &[i32]) -> impl Iterator<Item = (i32, &())> {
         panic!();
     }
 }
+
+#[test]
+fn test_issue_82291() {
+    use std::cell::Cell;
+
+    let mut v1 = [()];
+    let v2 = [()];
+
+    let called = Cell::new(0);
+
+    let mut zip = v1
+        .iter_mut()
+        .map(|r| {
+            called.set(called.get() + 1);
+            r
+        })
+        .zip(&v2);
+
+    zip.next_back();
+    assert_eq!(called.get(), 1);
+    zip.next();
+    assert_eq!(called.get(), 1);
+}
-- 
2.31.1