|  | 
| 1 | 1 | use std::any::Any; | 
| 2 |  | -use std::cell::RefCell; | 
|  | 2 | +use std::cell::{Cell, RefCell}; | 
| 3 | 3 | use std::iter::TrustedLen; | 
| 4 | 4 | use std::mem; | 
| 5 | 5 | use std::sync::{Arc, Weak}; | 
| @@ -89,7 +89,7 @@ fn eq() { | 
| 89 | 89 | 
 | 
| 90 | 90 | // The test code below is identical to that in `rc.rs`. | 
| 91 | 91 | // For better maintainability we therefore define this type alias. | 
| 92 |  | -type Rc<T> = Arc<T>; | 
|  | 92 | +type Rc<T, A = std::alloc::Global> = Arc<T, A>; | 
| 93 | 93 | 
 | 
| 94 | 94 | const SHARED_ITER_MAX: u16 = 100; | 
| 95 | 95 | 
 | 
| @@ -210,6 +210,42 @@ fn weak_may_dangle() { | 
| 210 | 210 |     // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak` | 
| 211 | 211 | } | 
| 212 | 212 | 
 | 
|  | 213 | +/// Test that a panic from a destructor does not leak the allocation. | 
|  | 214 | +#[test] | 
|  | 215 | +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] | 
|  | 216 | +fn panic_no_leak() { | 
|  | 217 | +    use std::alloc::{AllocError, Allocator, Global, Layout}; | 
|  | 218 | +    use std::panic::{AssertUnwindSafe, catch_unwind}; | 
|  | 219 | +    use std::ptr::NonNull; | 
|  | 220 | + | 
|  | 221 | +    struct AllocCount(Cell<i32>); | 
|  | 222 | +    unsafe impl Allocator for AllocCount { | 
|  | 223 | +        fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { | 
|  | 224 | +            self.0.set(self.0.get() + 1); | 
|  | 225 | +            Global.allocate(layout) | 
|  | 226 | +        } | 
|  | 227 | +        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { | 
|  | 228 | +            self.0.set(self.0.get() - 1); | 
|  | 229 | +            unsafe { Global.deallocate(ptr, layout) } | 
|  | 230 | +        } | 
|  | 231 | +    } | 
|  | 232 | + | 
|  | 233 | +    struct PanicOnDrop; | 
|  | 234 | +    impl Drop for PanicOnDrop { | 
|  | 235 | +        fn drop(&mut self) { | 
|  | 236 | +            panic!("PanicOnDrop"); | 
|  | 237 | +        } | 
|  | 238 | +    } | 
|  | 239 | + | 
|  | 240 | +    let alloc = AllocCount(Cell::new(0)); | 
|  | 241 | +    let rc = Rc::new_in(PanicOnDrop, &alloc); | 
|  | 242 | +    assert_eq!(alloc.0.get(), 1); | 
|  | 243 | + | 
|  | 244 | +    let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); | 
|  | 245 | +    assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); | 
|  | 246 | +    assert_eq!(alloc.0.get(), 0); | 
|  | 247 | +} | 
|  | 248 | + | 
| 213 | 249 | /// This is similar to the doc-test for `Arc::make_mut()`, but on an unsized type (slice). | 
| 214 | 250 | #[test] | 
| 215 | 251 | fn make_mut_unsized() { | 
|  | 
0 commit comments