| 
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