From 9cd91a39f49ed3f7735f0dab7c951d4aabd891a1 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 5 Nov 2025 13:57:55 -0800 Subject: [PATCH 1/2] Fix UB in Vec::clone --- src/vec.rs | 13 ++++++++++++- tests/frozenvec_clone_miri.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 tests/frozenvec_clone_miri.rs diff --git a/src/vec.rs b/src/vec.rs index 2e15d6f..2ed1b10 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -225,8 +225,19 @@ impl Default for FrozenVec { impl Clone for FrozenVec { fn clone(&self) -> Self { + // Vec::clone() will internally call Clone impls, which may reaccess the FrozenVec + // Instead, we iterate element-by-element. + let mut newvec; + unsafe { + let len = self.vec.get().as_ref().unwrap().len(); + newvec = Vec::with_capacity(len); + for i in 0..len { + let element = self.vec.get().as_ref().unwrap()[i].clone(); + newvec.push(element); + } + } Self { - vec: unsafe { self.vec.get().as_ref().unwrap() }.clone().into(), + vec: UnsafeCell::new(newvec), } } } diff --git a/tests/frozenvec_clone_miri.rs b/tests/frozenvec_clone_miri.rs new file mode 100644 index 0000000..89dc2eb --- /dev/null +++ b/tests/frozenvec_clone_miri.rs @@ -0,0 +1,32 @@ +use elsa::FrozenVec; + +struct Yo<'a> { + some_flag: bool, + reference: &'a FrozenVec>>, +} +impl Clone for Yo<'_> { + fn clone(&self) -> Self { + self.reference.push(Box::new(Yo { + some_flag: self.some_flag, + reference: &self.reference, + })); + + Self { + some_flag: self.some_flag, + reference: self.reference, + } + } +} + +#[test] +fn test_miri() { + let vec: FrozenVec> = FrozenVec::new(); + + let something = Box::new(Yo { + some_flag: true, + reference: &vec, + }); + + vec.push(something); + let _ = vec.clone(); +} From 99a83bb2886b267af2de94f3450e8233df75ca45 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 5 Nov 2025 14:13:14 -0800 Subject: [PATCH 2/2] fix nightly ci --- src/index_set.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/index_set.rs b/src/index_set.rs index d8abad5..dd2be9f 100644 --- a/src/index_set.rs +++ b/src/index_set.rs @@ -56,7 +56,8 @@ impl FrozenIndexSet { let ret = unsafe { let set = self.set.get(); let (index, _was_vacant) = (*set).insert_full(value); - &*(*set)[index] + let set_ref = &(*set); + &*set_ref[index] }; self.in_use.set(false); ret @@ -83,7 +84,8 @@ impl FrozenIndexSet { let ret = unsafe { let set = self.set.get(); let (index, _was_vacant) = (*set).insert_full(value); - (index, &*(*set)[index]) + let set_ref = &(*set); + (index, &*set_ref[index]) }; self.in_use.set(false); ret @@ -261,7 +263,8 @@ impl Index for FrozenIndexSet { self.in_use.set(true); let ret = unsafe { let set = self.set.get(); - &*(*set)[idx] + let set_ref = &(*set); + &*set_ref[idx] }; self.in_use.set(false); ret