From 8b518542d042a0b046d44d5c2b754976481c80ce Mon Sep 17 00:00:00 2001 From: The8472 Date: Sat, 19 Jun 2021 02:20:22 +0200 Subject: [PATCH 1/2] 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. --- library/core/src/iter/adapters/zip.rs | 3 ++- library/core/tests/iter/adapters/zip.rs | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 8a6955060e82f..46bf93dcc01e2 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -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 { diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs index 797bfd957f906..fce88daee195a 100644 --- a/library/core/tests/iter/adapters/zip.rs +++ b/library/core/tests/iter/adapters/zip.rs @@ -1,5 +1,7 @@ use super::*; use core::iter::*; +use std::panic::catch_unwind; +use std::panic::AssertUnwindSafe; #[test] fn test_zip_nth() { @@ -232,6 +234,29 @@ fn test_zip_trusted_random_access_composition() { assert_eq!(z2.next().unwrap(), ((1, 1), 1)); } +#[test] +fn test_zip_trusted_random_access_next_back_drop() { + 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]; From b4734b7c38dc2b9e84dd0358114534f55bd1849e Mon Sep 17 00:00:00 2001 From: The8472 Date: Sun, 20 Jun 2021 12:20:05 +0200 Subject: [PATCH 2/2] disable test on platforms that don't support unwinding --- library/core/tests/iter/adapters/zip.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs index fce88daee195a..585cfbb90e40c 100644 --- a/library/core/tests/iter/adapters/zip.rs +++ b/library/core/tests/iter/adapters/zip.rs @@ -1,7 +1,5 @@ use super::*; use core::iter::*; -use std::panic::catch_unwind; -use std::panic::AssertUnwindSafe; #[test] fn test_zip_nth() { @@ -235,7 +233,11 @@ fn test_zip_trusted_random_access_composition() { } #[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| {