| 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 |
| |