Description
Related to #85863, which now includes a high-level description covering both #85863 and #85873. [This issue is not a duplicate because both issues can be fixed independently in different ways.]
use std::{iter::Zip, marker::PhantomData, vec};
struct MyStruct<T>(PhantomData<T>);
impl<T> Clone for MyStruct<T> {
fn clone(&self) -> Self {
Self(PhantomData)
}
}
impl Copy for MyStruct<fn(&())> {}
#[allow(clippy::type_complexity)]
fn main() {
let i: vec::IntoIter<MyStruct<fn(&())>> = vec![MyStruct::<fn(&())>(PhantomData)].into_iter();
let mut y = [Some(&42)];
let mut z = i.zip(y.iter_mut());
let r1 = z.next().unwrap().1;
let mut z: Zip<vec::IntoIter<MyStruct<fn(&'static ())>>, _> = z;
let r2 = z.next().unwrap().1;
let elt = r1.as_ref().unwrap();
dbg!(elt);
*r2 = None;
dbg!(elt);
}
Compiling playground v0.0.1 (/playground)
Finished dev [unoptimized + debuginfo] target(s) in 1.10s
Running `target/debug/playground`
[src/main.rs:20] elt = 42
[src/main.rs:22] elt = timeout: the monitored command dumped core
/playground/tools/entrypoint.sh: line 11: 8 Segmentation fault timeout --signal=KILL ${timeout} "$@"
@rustbot label T-libs-impl, T-compiler, A-specialization, A-iterators, A-typesystem, A-lifetimes, A-traits, regression-from-stable-to-stable
someone please add the unsound label thanks
Explanation
Zip
uses an optimization if both contained iterators implement TrustedRandomAccess
. There’s an impl
impl<T> TrustedRandomAccess for IntoIter<T>
where
T: Copy,
for both vec::IntoIter
and vec_deque::IntoIter
that depend on Copy
. This way, unsound specialization is possible. This can be turned into actual ill-behaved programs at runtime similar as in #85863, relying on covariance of IntoIter
and Zip
. This way, the ZipImpl
implementation is switched out and this way the Zip
iterator gets into an illegal state resulting in violation of the contract of TrustedRandomAccess
by calling .next()
on the IterMut
iterator after the first item was already read via __iterator_get_unchecked
. The best immediate fix is probably to remove those two TrustedRandomAccess
implementations for IntoIter
; they’re an optimization only, anyway. This distinguishes this issue clearly from #85863 because for the FusedIterator
trait, the specialization is quite directly part of the API, whereas this issue is only about a soundness regression from a performance optimization that can easily be reverted.