Skip to content

Commit 1d5b2dc

Browse files
authored
Rollup merge of #82292 - SkiFire13:fix-issue-82291, r=m-ou-se
Prevent specialized ZipImpl from calling `__iterator_get_unchecked` twice with the same index Fixes #82291 It's open for review, but conflicts with #82289, wait before merging. The conflict involves only the new test, so it should be rather trivial to fix.
2 parents 0adc196 + c1bfb9a commit 1d5b2dc

File tree

2 files changed

+32
-4
lines changed
  • library/core

2 files changed

+32
-4
lines changed

library/core/src/iter/adapters/zip.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ use crate::iter::{InPlaceIterable, SourceIter, TrustedLen};
1313
pub struct Zip<A, B> {
1414
a: A,
1515
b: B,
16-
// index and len are only used by the specialized version of zip
16+
// index, len and a_len are only used by the specialized version of zip
1717
index: usize,
1818
len: usize,
19+
a_len: usize,
1920
}
2021
impl<A: Iterator, B: Iterator> Zip<A, B> {
2122
pub(in crate::iter) fn new(a: A, b: B) -> Zip<A, B> {
@@ -110,6 +111,7 @@ where
110111
b,
111112
index: 0, // unused
112113
len: 0, // unused
114+
a_len: 0, // unused
113115
}
114116
}
115117

@@ -184,8 +186,9 @@ where
184186
B: TrustedRandomAccess + Iterator,
185187
{
186188
fn new(a: A, b: B) -> Self {
187-
let len = cmp::min(a.size(), b.size());
188-
Zip { a, b, index: 0, len }
189+
let a_len = a.size();
190+
let len = cmp::min(a_len, b.size());
191+
Zip { a, b, index: 0, len, a_len }
189192
}
190193

191194
#[inline]
@@ -197,7 +200,7 @@ where
197200
unsafe {
198201
Some((self.a.__iterator_get_unchecked(i), self.b.__iterator_get_unchecked(i)))
199202
}
200-
} else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a.size() {
203+
} else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a_len {
201204
let i = self.index;
202205
self.index += 1;
203206
self.len += 1;
@@ -262,6 +265,7 @@ where
262265
for _ in 0..sz_a - self.len {
263266
self.a.next_back();
264267
}
268+
self.a_len = self.len;
265269
}
266270
let sz_b = self.b.size();
267271
if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len {
@@ -273,6 +277,7 @@ where
273277
}
274278
if self.index < self.len {
275279
self.len -= 1;
280+
self.a_len -= 1;
276281
let i = self.len;
277282
// SAFETY: `i` is smaller than the previous value of `self.len`,
278283
// which is also smaller than or equal to `self.a.len()` and `self.b.len()`

library/core/tests/iter/adapters/zip.rs

+23
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,26 @@ fn test_issue_82282() {
265265
panic!();
266266
}
267267
}
268+
269+
#[test]
270+
fn test_issue_82291() {
271+
use std::cell::Cell;
272+
273+
let mut v1 = [()];
274+
let v2 = [()];
275+
276+
let called = Cell::new(0);
277+
278+
let mut zip = v1
279+
.iter_mut()
280+
.map(|r| {
281+
called.set(called.get() + 1);
282+
r
283+
})
284+
.zip(&v2);
285+
286+
zip.next_back();
287+
assert_eq!(called.get(), 1);
288+
zip.next();
289+
assert_eq!(called.get(), 1);
290+
}

0 commit comments

Comments
 (0)