Skip to content

Commit 5be6c9b

Browse files
Rollup merge of #135104 - the8472:disable-in-place-iter-for-flatten, r=Mark-Simulacrum
do not in-place-iterate over flatmap/flatten The implementation is unsound when a partially consumed iterator has some elements buffered in the front/back parts and cloning the Iterator removes the capacity from the backing vec::IntoIter. This is a fix for #135103 that removes the specialization trait impls without removing some supporting parts. I've kept it small so it can be easily backported. I'll either remove the remaining parts or think of a way to recover the optimization in a separate PR.
2 parents dcb8be8 + 1ed0ea4 commit 5be6c9b

File tree

2 files changed

+22
-51
lines changed

2 files changed

+22
-51
lines changed

library/alloc/tests/vec.rs

+20-19
Original file line numberDiff line numberDiff line change
@@ -1204,22 +1204,16 @@ fn test_from_iter_specialization_with_iterator_adapters() {
12041204
#[test]
12051205
fn test_in_place_specialization_step_up_down() {
12061206
fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {}
1207-
let src = vec![[0u8; 4]; 256];
1208-
let srcptr = src.as_ptr();
1209-
let src_cap = src.capacity();
1210-
let iter = src.into_iter().flatten();
1211-
assert_in_place_trait(&iter);
1212-
let sink = iter.collect::<Vec<_>>();
1213-
let sinkptr = sink.as_ptr();
1214-
assert_eq!(srcptr as *const u8, sinkptr);
1215-
assert_eq!(src_cap * 4, sink.capacity());
12161207

1217-
let iter = sink.into_iter().array_chunks::<4>();
1208+
let src = vec![0u8; 1024];
1209+
let srcptr = src.as_ptr();
1210+
let src_bytes = src.capacity();
1211+
let iter = src.into_iter().array_chunks::<4>();
12181212
assert_in_place_trait(&iter);
12191213
let sink = iter.collect::<Vec<_>>();
12201214
let sinkptr = sink.as_ptr();
1221-
assert_eq!(srcptr, sinkptr);
1222-
assert_eq!(src_cap, sink.capacity());
1215+
assert_eq!(srcptr.addr(), sinkptr.addr());
1216+
assert_eq!(src_bytes, sink.capacity() * 4);
12231217

12241218
let mut src: Vec<u8> = Vec::with_capacity(17);
12251219
let src_bytes = src.capacity();
@@ -1236,13 +1230,6 @@ fn test_in_place_specialization_step_up_down() {
12361230
let sink: Vec<[u8; 2]> = iter.collect();
12371231
assert_eq!(sink.len(), 8);
12381232
assert!(sink.capacity() <= 25);
1239-
1240-
let src = vec![[0u8; 4]; 256];
1241-
let srcptr = src.as_ptr();
1242-
let iter = src.into_iter().flat_map(|a| a.into_iter().map(|b| b.wrapping_add(1)));
1243-
assert_in_place_trait(&iter);
1244-
let sink = iter.collect::<Vec<_>>();
1245-
assert_eq!(srcptr as *const u8, sink.as_ptr());
12461233
}
12471234

12481235
#[test]
@@ -1350,6 +1337,20 @@ fn test_collect_after_iterator_clone() {
13501337
assert_eq!(v, [1, 1, 1, 1, 1]);
13511338
assert!(v.len() <= v.capacity());
13521339
}
1340+
1341+
// regression test for #135103, similar to the one above Flatten/FlatMap had an unsound InPlaceIterable
1342+
// implementation.
1343+
#[test]
1344+
fn test_flatten_clone() {
1345+
const S: String = String::new();
1346+
1347+
let v = vec![[S, "Hello World!".into()], [S, S]];
1348+
let mut i = v.into_iter().flatten();
1349+
let _ = i.next();
1350+
let result: Vec<String> = i.clone().collect();
1351+
assert_eq!(result, ["Hello World!", "", ""]);
1352+
}
1353+
13531354
#[test]
13541355
fn test_cow_from() {
13551356
let borrowed: &[_] = &["borrowed", "(slice)"];

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

+2-32
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::iter::adapters::SourceIter;
22
use crate::iter::{
3-
Cloned, Copied, Empty, Filter, FilterMap, Fuse, FusedIterator, InPlaceIterable, Map, Once,
4-
OnceWith, TrustedFused, TrustedLen,
3+
Cloned, Copied, Empty, Filter, FilterMap, Fuse, FusedIterator, Map, Once, OnceWith,
4+
TrustedFused, TrustedLen,
55
};
66
use crate::num::NonZero;
77
use crate::ops::{ControlFlow, Try};
@@ -157,21 +157,6 @@ where
157157
{
158158
}
159159

160-
#[unstable(issue = "none", feature = "inplace_iteration")]
161-
unsafe impl<I, U, F> InPlaceIterable for FlatMap<I, U, F>
162-
where
163-
I: InPlaceIterable,
164-
U: BoundedSize + IntoIterator,
165-
{
166-
const EXPAND_BY: Option<NonZero<usize>> = const {
167-
match (I::EXPAND_BY, U::UPPER_BOUND) {
168-
(Some(m), Some(n)) => m.checked_mul(n),
169-
_ => None,
170-
}
171-
};
172-
const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
173-
}
174-
175160
#[unstable(issue = "none", feature = "inplace_iteration")]
176161
unsafe impl<I, U, F> SourceIter for FlatMap<I, U, F>
177162
where
@@ -386,21 +371,6 @@ where
386371
{
387372
}
388373

389-
#[unstable(issue = "none", feature = "inplace_iteration")]
390-
unsafe impl<I> InPlaceIterable for Flatten<I>
391-
where
392-
I: InPlaceIterable + Iterator,
393-
<I as Iterator>::Item: IntoIterator + BoundedSize,
394-
{
395-
const EXPAND_BY: Option<NonZero<usize>> = const {
396-
match (I::EXPAND_BY, I::Item::UPPER_BOUND) {
397-
(Some(m), Some(n)) => m.checked_mul(n),
398-
_ => None,
399-
}
400-
};
401-
const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
402-
}
403-
404374
#[unstable(issue = "none", feature = "inplace_iteration")]
405375
unsafe impl<I> SourceIter for Flatten<I>
406376
where

0 commit comments

Comments
 (0)