Skip to content

Commit

Permalink
Rollup merge of #86452 - the8472:fix-zip-drop-safety, r=m-ou-se
Browse files Browse the repository at this point in the history
fix panic-safety in specialized Zip::next_back

This was unsound since a panic in a.next_back() would result in the
length not being updated which would then lead to the same element
being revisited in the side-effect preserving code.

fixes #86443
  • Loading branch information
JohnTitor committed Jun 21, 2021
2 parents 13b0f1a + b4734b7 commit 504c378
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 1 deletion.
3 changes: 2 additions & 1 deletion library/core/src/iter/adapters/zip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,10 @@ where
let sz_a = self.a.size();
if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len {
for _ in 0..sz_a - self.len {
self.a_len -= 1;
self.a.next_back();
}
self.a_len = self.len;
debug_assert_eq!(self.a_len, self.len);
}
let sz_b = self.b.size();
if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len {
Expand Down
27 changes: 27 additions & 0 deletions library/core/tests/iter/adapters/zip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,33 @@ fn test_zip_trusted_random_access_composition() {
assert_eq!(z2.next().unwrap(), ((1, 1), 1));
}

#[test]
#[cfg(panic = "unwind")]
fn test_zip_trusted_random_access_next_back_drop() {
use std::panic::catch_unwind;
use std::panic::AssertUnwindSafe;

let mut counter = 0;

let it = [42].iter().map(|e| {
let c = counter;
counter += 1;
if c == 0 {
panic!("bomb");
}

e
});
let it2 = [(); 0].iter();
let mut zip = it.zip(it2);
catch_unwind(AssertUnwindSafe(|| {
zip.next_back();
}))
.unwrap_err();
assert!(zip.next().is_none());
assert_eq!(counter, 1);
}

#[test]
fn test_double_ended_zip() {
let xs = [1, 2, 3, 4, 5, 6];
Expand Down

0 comments on commit 504c378

Please sign in to comment.