From a5734ca41748dfd62904c1b5a1ade7ecd0f9c11e Mon Sep 17 00:00:00 2001 From: mendess Date: Sat, 23 May 2020 14:08:53 +0100 Subject: [PATCH 1/3] Override Box::<[T]>::clone_from --- src/liballoc/boxed.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8ef6090c743a9..bbe68e4222a1f 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -1090,6 +1090,14 @@ impl Clone for Box<[T]> { fn clone(&self) -> Self { self.to_vec().into_boxed_slice() } + + fn clone_from(&mut self, other: &Self) { + if self.len() == other.len() { + self.clone_from_slice(&other); + } else { + *self = other.clone(); + } + } } #[stable(feature = "box_borrow", since = "1.1.0")] From 32eedadee1ed3273a318fa109c5261482e518578 Mon Sep 17 00:00:00 2001 From: mendess Date: Sat, 23 May 2020 16:51:02 +0100 Subject: [PATCH 2/3] Add tests --- src/liballoc/tests/boxed.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/liballoc/tests/boxed.rs b/src/liballoc/tests/boxed.rs index 66782ecbeb7f6..c0b8fa665615e 100644 --- a/src/liballoc/tests/boxed.rs +++ b/src/liballoc/tests/boxed.rs @@ -16,3 +16,39 @@ fn unitialized_zero_size_box() { NonNull::>::dangling().as_ptr(), ); } + +#[derive(Clone, PartialEq, Eq, Debug)] +struct Dummy { + _data: u8, +} + +#[test] +fn box_clone_and_clone_from_equivalence() { + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let clone = control.clone(); + let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); + copy.clone_from(&control); + assert_eq!(control, clone); + assert_eq!(control, copy); + } +} + +#[test] +fn box_clone_from_ptr_stability() { + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); + let copy_raw = copy.as_ptr() as usize; + copy.clone_from(&control); + assert_eq!(copy.as_ptr() as usize, copy_raw); + } + + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let mut copy = vec![Dummy { _data: 84 }; size + 1].into_boxed_slice(); + let copy_raw = copy.as_ptr() as usize; + copy.clone_from(&control); + assert_ne!(copy.as_ptr() as usize, copy_raw); + } +} From dbf32e2270f82601bd2816da270ce70269cc59ba Mon Sep 17 00:00:00 2001 From: mendess Date: Fri, 29 May 2020 11:18:15 +0100 Subject: [PATCH 3/3] Remove flaky test and document the other's flakiness --- src/liballoc/tests/boxed.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/liballoc/tests/boxed.rs b/src/liballoc/tests/boxed.rs index c0b8fa665615e..5377485da8f3b 100644 --- a/src/liballoc/tests/boxed.rs +++ b/src/liballoc/tests/boxed.rs @@ -34,6 +34,11 @@ fn box_clone_and_clone_from_equivalence() { } } +/// This test might give a false positive in case the box realocates, but the alocator keeps the +/// original pointer. +/// +/// On the other hand it won't give a false negative, if it fails than the memory was definitly not +/// reused #[test] fn box_clone_from_ptr_stability() { for size in (0..8).map(|i| 2usize.pow(i)) { @@ -43,12 +48,4 @@ fn box_clone_from_ptr_stability() { copy.clone_from(&control); assert_eq!(copy.as_ptr() as usize, copy_raw); } - - for size in (0..8).map(|i| 2usize.pow(i)) { - let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); - let mut copy = vec![Dummy { _data: 84 }; size + 1].into_boxed_slice(); - let copy_raw = copy.as_ptr() as usize; - copy.clone_from(&control); - assert_ne!(copy.as_ptr() as usize, copy_raw); - } }