Skip to content

Commit 29a1040

Browse files
authored
Rollup merge of rust-lang#86452 - the8472:fix-zip-drop-safety, r=m-ou-se
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 rust-lang#86443
2 parents 4a54179 + b4734b7 commit 29a1040

File tree

2 files changed

+29
-1
lines changed
  • library/core

2 files changed

+29
-1
lines changed

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -295,9 +295,10 @@ where
295295
let sz_a = self.a.size();
296296
if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len {
297297
for _ in 0..sz_a - self.len {
298+
self.a_len -= 1;
298299
self.a.next_back();
299300
}
300-
self.a_len = self.len;
301+
debug_assert_eq!(self.a_len, self.len);
301302
}
302303
let sz_b = self.b.size();
303304
if B::MAY_HAVE_SIDE_EFFECT && sz_b > self.len {

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

+27
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,33 @@ fn test_zip_trusted_random_access_composition() {
232232
assert_eq!(z2.next().unwrap(), ((1, 1), 1));
233233
}
234234

235+
#[test]
236+
#[cfg(panic = "unwind")]
237+
fn test_zip_trusted_random_access_next_back_drop() {
238+
use std::panic::catch_unwind;
239+
use std::panic::AssertUnwindSafe;
240+
241+
let mut counter = 0;
242+
243+
let it = [42].iter().map(|e| {
244+
let c = counter;
245+
counter += 1;
246+
if c == 0 {
247+
panic!("bomb");
248+
}
249+
250+
e
251+
});
252+
let it2 = [(); 0].iter();
253+
let mut zip = it.zip(it2);
254+
catch_unwind(AssertUnwindSafe(|| {
255+
zip.next_back();
256+
}))
257+
.unwrap_err();
258+
assert!(zip.next().is_none());
259+
assert_eq!(counter, 1);
260+
}
261+
235262
#[test]
236263
fn test_double_ended_zip() {
237264
let xs = [1, 2, 3, 4, 5, 6];

0 commit comments

Comments
 (0)