| use std::any::Any; |
| use std::cell::{Cell, RefCell}; |
| use std::iter::TrustedLen; |
| use std::sync::{Arc, UniqueArc, Weak}; |
| |
| #[test] |
| fn uninhabited() { |
| enum Void {} |
| let mut a = Weak::<Void>::new(); |
| a = a.clone(); |
| assert!(a.upgrade().is_none()); |
| |
| let mut a: Weak<dyn Any> = a; // Unsizing |
| a = a.clone(); |
| assert!(a.upgrade().is_none()); |
| } |
| |
| #[test] |
| fn slice() { |
| let a: Arc<[u32; 3]> = Arc::new([3, 2, 1]); |
| let a: Arc<[u32]> = a; // Unsizing |
| let b: Arc<[u32]> = Arc::from(&[3, 2, 1][..]); // Conversion |
| assert_eq!(a, b); |
| |
| // Exercise is_dangling() with a DST |
| let mut a = Arc::downgrade(&a); |
| a = a.clone(); |
| assert!(a.upgrade().is_some()); |
| } |
| |
| #[test] |
| fn trait_object() { |
| let a: Arc<u32> = Arc::new(4); |
| let a: Arc<dyn Any> = a; // Unsizing |
| |
| // Exercise is_dangling() with a DST |
| let mut a = Arc::downgrade(&a); |
| a = a.clone(); |
| assert!(a.upgrade().is_some()); |
| |
| let mut b = Weak::<u32>::new(); |
| b = b.clone(); |
| assert!(b.upgrade().is_none()); |
| let mut b: Weak<dyn Any> = b; // Unsizing |
| b = b.clone(); |
| assert!(b.upgrade().is_none()); |
| } |
| |
| #[test] |
| fn float_nan_ne() { |
| let x = Arc::new(f32::NAN); |
| assert!(x != x); |
| assert!(!(x == x)); |
| } |
| |
| #[test] |
| fn partial_eq() { |
| struct TestPEq(RefCell<usize>); |
| impl PartialEq for TestPEq { |
| fn eq(&self, other: &TestPEq) -> bool { |
| *self.0.borrow_mut() += 1; |
| *other.0.borrow_mut() += 1; |
| true |
| } |
| } |
| let x = Arc::new(TestPEq(RefCell::new(0))); |
| assert!(x == x); |
| assert!(!(x != x)); |
| assert_eq!(*x.0.borrow(), 4); |
| } |
| |
| #[test] |
| fn eq() { |
| #[derive(Eq)] |
| struct TestEq(RefCell<usize>); |
| impl PartialEq for TestEq { |
| fn eq(&self, other: &TestEq) -> bool { |
| *self.0.borrow_mut() += 1; |
| *other.0.borrow_mut() += 1; |
| true |
| } |
| } |
| let x = Arc::new(TestEq(RefCell::new(0))); |
| assert!(x == x); |
| assert!(!(x != x)); |
| assert_eq!(*x.0.borrow(), 0); |
| } |
| |
| #[test] |
| fn eq_unsized() { |
| #[derive(Eq)] |
| struct TestEq<T: ?Sized>(RefCell<usize>, T); |
| impl<T: ?Sized> PartialEq for TestEq<T> { |
| fn eq(&self, other: &TestEq<T>) -> bool { |
| *self.0.borrow_mut() += 1; |
| *other.0.borrow_mut() += 1; |
| true |
| } |
| } |
| let x = Arc::<TestEq<[u8; 3]>>::new(TestEq(RefCell::new(0), [0, 1, 2])) as Arc<TestEq<[u8]>>; |
| assert!(x == x); |
| assert!(!(x != x)); |
| assert_eq!(*x.0.borrow(), 0); |
| } |
| |
| #[test] |
| fn eq_unsized_slice() { |
| let a: Arc<[()]> = Arc::new([(); 3]); |
| let ptr: *const () = Arc::into_raw(a.clone()).cast(); |
| let b: Arc<[()]> = unsafe { Arc::from_raw(ptr.cast_slice(42)) }; |
| assert!(a == a); |
| assert!(!(a != a)); |
| assert!(a != b); |
| assert!(!(a == b)); |
| } |
| |
| // The test code below is identical to that in `rc.rs`. |
| // For better maintainability we therefore define this type alias. |
| type Rc<T, A = std::alloc::Global> = Arc<T, A>; |
| |
| const SHARED_ITER_MAX: u16 = 100; |
| |
| fn assert_trusted_len<I: TrustedLen>(_: &I) {} |
| |
| #[test] |
| fn shared_from_iter_normal() { |
| // Exercise the base implementation for non-`TrustedLen` iterators. |
| { |
| // `Filter` is never `TrustedLen` since we don't |
| // know statically how many elements will be kept: |
| let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new); |
| |
| // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference: |
| let vec = iter.clone().collect::<Vec<_>>(); |
| let rc = iter.collect::<Rc<[_]>>(); |
| assert_eq!(&*vec, &*rc); |
| |
| // Clone a bit and let these get dropped. |
| { |
| let _rc_2 = rc.clone(); |
| let _rc_3 = rc.clone(); |
| let _rc_4 = Rc::downgrade(&_rc_3); |
| } |
| } // Drop what hasn't been here. |
| } |
| |
| #[test] |
| fn shared_from_iter_trustedlen_normal() { |
| // Exercise the `TrustedLen` implementation under normal circumstances |
| // where `size_hint()` matches `(_, Some(exact_len))`. |
| { |
| let iter = (0..SHARED_ITER_MAX).map(Box::new); |
| assert_trusted_len(&iter); |
| |
| // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference: |
| let vec = iter.clone().collect::<Vec<_>>(); |
| let rc = iter.collect::<Rc<[_]>>(); |
| assert_eq!(&*vec, &*rc); |
| assert_eq!(size_of::<Box<u16>>() * SHARED_ITER_MAX as usize, size_of_val(&*rc)); |
| |
| // Clone a bit and let these get dropped. |
| { |
| let _rc_2 = rc.clone(); |
| let _rc_3 = rc.clone(); |
| let _rc_4 = Rc::downgrade(&_rc_3); |
| } |
| } // Drop what hasn't been here. |
| |
| // Try a ZST to make sure it is handled well. |
| { |
| let iter = (0..SHARED_ITER_MAX).map(drop); |
| let vec = iter.clone().collect::<Vec<_>>(); |
| let rc = iter.collect::<Rc<[_]>>(); |
| assert_eq!(&*vec, &*rc); |
| assert_eq!(0, size_of_val(&*rc)); |
| { |
| let _rc_2 = rc.clone(); |
| let _rc_3 = rc.clone(); |
| let _rc_4 = Rc::downgrade(&_rc_3); |
| } |
| } |
| } |
| |
| #[test] |
| #[should_panic = "I've almost got 99 problems."] |
| fn shared_from_iter_trustedlen_panic() { |
| // Exercise the `TrustedLen` implementation when `size_hint()` matches |
| // `(_, Some(exact_len))` but where `.next()` drops before the last iteration. |
| let iter = (0..SHARED_ITER_MAX).map(|val| match val { |
| 98 => panic!("I've almost got 99 problems."), |
| _ => Box::new(val), |
| }); |
| assert_trusted_len(&iter); |
| let _ = iter.collect::<Rc<[_]>>(); |
| |
| panic!("I am unreachable."); |
| } |
| |
| #[test] |
| fn shared_from_iter_trustedlen_no_fuse() { |
| // Exercise the `TrustedLen` implementation when `size_hint()` matches |
| // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner. |
| struct Iter(std::vec::IntoIter<Option<Box<u8>>>); |
| |
| unsafe impl TrustedLen for Iter {} |
| |
| impl Iterator for Iter { |
| fn size_hint(&self) -> (usize, Option<usize>) { |
| (2, Some(2)) |
| } |
| |
| type Item = Box<u8>; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| self.0.next().flatten() |
| } |
| } |
| |
| let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))]; |
| let iter = Iter(vec.into_iter()); |
| assert_trusted_len(&iter); |
| assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>()); |
| } |
| |
| #[test] |
| fn weak_may_dangle() { |
| fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> { |
| val.clone() |
| } |
| |
| // Without #[may_dangle] we get: |
| let mut val = Weak::new(); |
| hmm(&mut val); |
| // ~~~~~~~~ borrowed value does not live long enough |
| // |
| // `val` dropped here while still borrowed |
| // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak` |
| } |
| |
| /// Test that a panic from a destructor does not leak the allocation. |
| #[test] |
| #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] |
| fn panic_no_leak() { |
| use std::alloc::{AllocError, Allocator, Global, Layout}; |
| use std::panic::{AssertUnwindSafe, catch_unwind}; |
| use std::ptr::NonNull; |
| |
| struct AllocCount(Cell<i32>); |
| unsafe impl Allocator for AllocCount { |
| fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { |
| self.0.set(self.0.get() + 1); |
| Global.allocate(layout) |
| } |
| unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { |
| self.0.set(self.0.get() - 1); |
| unsafe { Global.deallocate(ptr, layout) } |
| } |
| } |
| |
| struct PanicOnDrop; |
| impl Drop for PanicOnDrop { |
| fn drop(&mut self) { |
| panic!("PanicOnDrop"); |
| } |
| } |
| |
| let alloc = AllocCount(Cell::new(0)); |
| let rc = Rc::new_in(PanicOnDrop, &alloc); |
| assert_eq!(alloc.0.get(), 1); |
| |
| let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); |
| assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); |
| assert_eq!(alloc.0.get(), 0); |
| } |
| |
| /// This is similar to the doc-test for `Arc::make_mut()`, but on an unsized type (slice). |
| #[test] |
| fn make_mut_unsized() { |
| use alloc::sync::Arc; |
| |
| let mut data: Arc<[i32]> = Arc::new([10, 20, 30]); |
| |
| Arc::make_mut(&mut data)[0] += 1; // Won't clone anything |
| let mut other_data = Arc::clone(&data); // Won't clone inner data |
| Arc::make_mut(&mut data)[1] += 1; // Clones inner data |
| Arc::make_mut(&mut data)[2] += 1; // Won't clone anything |
| Arc::make_mut(&mut other_data)[0] *= 10; // Won't clone anything |
| |
| // Now `data` and `other_data` point to different allocations. |
| assert_eq!(*data, [11, 21, 31]); |
| assert_eq!(*other_data, [110, 20, 30]); |
| } |
| |
| #[test] |
| fn test_unique_arc_weak() { |
| let data = UniqueArc::new(32); |
| |
| // Test that `Weak` downgraded from `UniqueArc` cannot be upgraded. |
| let weak = UniqueArc::downgrade(&data); |
| assert_eq!(weak.strong_count(), 0); |
| assert_eq!(weak.weak_count(), 0); |
| assert!(weak.upgrade().is_none()); |
| |
| // Test that `Weak` can now be upgraded after the `UniqueArc` being converted to `Arc`. |
| let strong = UniqueArc::into_arc(data); |
| assert_eq!(*strong, 32); |
| assert_eq!(weak.strong_count(), 1); |
| assert_eq!(weak.weak_count(), 1); |
| let upgraded = weak.upgrade().unwrap(); |
| assert_eq!(*upgraded, 32); |
| assert_eq!(weak.strong_count(), 2); |
| assert_eq!(weak.weak_count(), 1); |
| } |
| |
| #[allow(unused)] |
| mod pin_coerce_unsized { |
| use alloc::sync::{Arc, UniqueArc}; |
| use core::pin::Pin; |
| |
| pub trait MyTrait {} |
| impl MyTrait for String {} |
| |
| // Pin coercion should work for Arc |
| pub fn pin_arc(arg: Pin<Arc<String>>) -> Pin<Arc<dyn MyTrait>> { |
| arg |
| } |
| pub fn pin_unique_arc(arg: Pin<UniqueArc<String>>) -> Pin<UniqueArc<dyn MyTrait>> { |
| arg |
| } |
| } |
| |
| /// Test that `Arc::make_mut` does not forget an allocator when it steals the data. |
| #[test] |
| fn issue_158875_make_mut_dont_leak_allocator() { |
| use std::alloc::Global; |
| |
| let alloc = Rc::new(Global); |
| |
| { |
| let mut arc = Arc::new_in(123, alloc.clone()); |
| let weak = Arc::downgrade(&arc); // create a weak so make_mut steals the data |
| _ = Arc::make_mut(&mut arc); |
| assert_eq!(weak.upgrade(), None); |
| } |
| |
| assert_eq!(Rc::strong_count(&alloc), 1); // if this is >1, we have a memory leak! |
| } |
| |
| /// Test that `Arc::make_mut` does not cause a UAF if the allocator panics on |
| /// clone when it steals the data. |
| #[test] |
| #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] |
| fn issue_155746_make_mut_panic_safety() { |
| use std::alloc::{Allocator, System}; |
| use std::panic::AssertUnwindSafe; |
| |
| #[derive(Default)] |
| struct PanickingCloneAlloc { |
| do_panic: Rc<Cell<bool>>, |
| } |
| unsafe impl Allocator for PanickingCloneAlloc { |
| fn allocate( |
| &self, |
| layout: std::alloc::Layout, |
| ) -> Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError> { |
| System.allocate(layout) |
| } |
| |
| unsafe fn deallocate(&self, ptr: std::ptr::NonNull<u8>, layout: std::alloc::Layout) { |
| unsafe { System.deallocate(ptr, layout) } |
| } |
| } |
| impl Clone for PanickingCloneAlloc { |
| fn clone(&self) -> Self { |
| if self.do_panic.get() { panic!() } else { Self { do_panic: self.do_panic.clone() } } |
| } |
| } |
| |
| let alloc = PanickingCloneAlloc::default(); |
| let mut arc = Arc::new_in(vec![vec![1]], alloc.clone()); |
| |
| let _weak = Arc::downgrade(&arc); // create a weak so make_mut steals the data |
| |
| alloc.do_panic.set(true); |
| std::panic::catch_unwind(AssertUnwindSafe(|| { |
| Arc::make_mut(&mut arc); |
| })) |
| .unwrap_err(); |
| |
| assert_eq!(*arc, [[1]]); |
| assert_eq!(Arc::strong_count(&arc), 1); // if this is 0, we have a UAF! |
| } |
| |
| #[test] |
| #[should_panic = "capacity overflow"] |
| fn new_uninit_slice_capacity_overflow() { |
| let _ = Arc::<[u8]>::new_uninit_slice(isize::MAX as usize); |
| } |