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.
This commit is contained in:
Yuki Okushi 2021-03-07 10:41:10 +09:00 committed by GitHub
commit 1d5b2dc945
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 4 deletions

View File

@ -13,9 +13,10 @@ use crate::iter::{InPlaceIterable, SourceIter, TrustedLen};
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 @@ where
b,
index: 0, // unused
len: 0, // unused
a_len: 0, // unused
}
}
@ -184,8 +186,9 @@ where
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 @@ where
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;
@ -262,6 +265,7 @@ where
for _ in 0..sz_a - self.len {
self.a.next_back();
}
self.a_len = self.len;
}
let sz_b = self.b.size();
if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len {
@ -273,6 +277,7 @@ where
}
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()`

View File

@ -265,3 +265,26 @@ fn test_issue_82282() {
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);
}