From af32db21c8e1b1970886eb64b9955f9590e4c445 Mon Sep 17 00:00:00 2001 From: kadmin Date: Tue, 11 Aug 2020 18:39:12 +0000 Subject: [PATCH] Add drop check test & MaybeUninit::first_ptr_mut Also in drop check test add hacky workaround for platforms that don't support panic=unwind --- library/core/src/array/mod.rs | 5 +++-- library/core/tests/array.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index cf3b9f8cce2..6b28ab7d755 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -413,7 +413,8 @@ fn drop(&mut self) { } } let mut dst = MaybeUninit::uninit_array::(); - let mut guard: Guard = Guard { dst: &mut dst as *mut _ as *mut U, initialized: 0 }; + let mut guard: Guard = + Guard { dst: MaybeUninit::first_ptr_mut(&mut dst), initialized: 0 }; for (src, dst) in IntoIter::new(self).zip(&mut dst) { dst.write(f(src)); guard.initialized += 1; @@ -423,6 +424,6 @@ fn drop(&mut self) { crate::mem::forget(guard); // SAFETY: At this point we've properly initialized the whole array // and we just need to cast it to the correct type. - unsafe { (&mut dst as *mut _ as *mut [U; N]).read() } + unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) } } } diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index d4a9b061d85..5aba1a5d958 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -301,3 +301,32 @@ fn array_map() { let b = a.map(|v| v as u64); assert_eq!(b, [1, 2, 3]); } + +// See note on above test for why `should_panic` is used. +#[test] +#[should_panic(expected = "test succeeded")] +fn array_map_drop_safety() { + use core::sync::atomic::AtomicUsize; + use core::sync::atomic::Ordering; + static DROPPED: AtomicUsize = AtomicUsize::new(0); + struct DropCounter; + impl Drop for DropCounter { + fn drop(&mut self) { + DROPPED.fetch_add(1, Ordering::SeqCst); + } + } + + let num_to_create = 5; + let success = std::panic::catch_unwind(|| { + let items = [0; 10]; + let mut nth = 0; + items.map(|_| { + assert!(nth < num_to_create); + nth += 1; + DropCounter + }); + }); + assert!(success.is_err()); + assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create); + panic!("test succeeded") +}