11use crate :: alloc:: alloc:: { handle_alloc_error, Layout } ;
2- use crate :: scopeguard:: guard;
2+ use crate :: scopeguard:: { guard, ScopeGuard } ;
33use crate :: TryReserveError ;
44use core:: iter:: FusedIterator ;
55use core:: marker:: PhantomData ;
@@ -1602,25 +1602,27 @@ impl<T: Clone, A: Allocator + Clone> Clone for RawTable<T, A> {
16021602 Self :: new_in ( self . table . alloc . clone ( ) )
16031603 } else {
16041604 unsafe {
1605- let mut new_table = ManuallyDrop :: new (
1606- // Avoid `Result::ok_or_else` because it bloats LLVM IR.
1607- match Self :: new_uninitialized (
1608- self . table . alloc . clone ( ) ,
1609- self . table . buckets ( ) ,
1610- Fallibility :: Infallible ,
1611- ) {
1612- Ok ( table ) => table ,
1613- Err ( _ ) => hint :: unreachable_unchecked ( ) ,
1614- } ,
1615- ) ;
1616-
1617- new_table . clone_from_spec ( self , |new_table| {
1618- // We need to free the memory allocated for the new table.
1605+ // Avoid `Result::ok_or_else` because it bloats LLVM IR.
1606+ let new_table = match Self :: new_uninitialized (
1607+ self . table . alloc . clone ( ) ,
1608+ self . table . buckets ( ) ,
1609+ Fallibility :: Infallible ,
1610+ ) {
1611+ Ok ( table ) => table ,
1612+ Err ( _ ) => hint :: unreachable_unchecked ( ) ,
1613+ } ;
1614+
1615+ // If cloning fails then we need to free the allocation for the
1616+ // new table. However we don't run its drop since its control
1617+ // bytes are not initialized yet.
1618+ let mut guard = guard ( ManuallyDrop :: new ( new_table ) , |new_table| {
16191619 new_table. free_buckets ( ) ;
16201620 } ) ;
16211621
1622- // Return the newly created table.
1623- ManuallyDrop :: into_inner ( new_table)
1622+ guard. clone_from_spec ( self ) ;
1623+
1624+ // Disarm the scope guard and return the newly created table.
1625+ ManuallyDrop :: into_inner ( ScopeGuard :: into_inner ( guard) )
16241626 }
16251627 }
16261628 }
@@ -1630,19 +1632,30 @@ impl<T: Clone, A: Allocator + Clone> Clone for RawTable<T, A> {
16301632 * self = Self :: new_in ( self . table . alloc . clone ( ) ) ;
16311633 } else {
16321634 unsafe {
1633- // First, drop all our elements without clearing the control bytes.
1634- self . drop_elements ( ) ;
1635+ // Make sure that if any panics occurs, we clear the table and
1636+ // leave it in an empty state.
1637+ let mut self_ = guard ( self , |self_| {
1638+ self_. clear_no_drop ( ) ;
1639+ } ) ;
1640+
1641+ // First, drop all our elements without clearing the control
1642+ // bytes. If this panics then the scope guard will clear the
1643+ // table, leaking any elements that were not dropped yet.
1644+ //
1645+ // This leak is unavoidable: we can't try dropping more elements
1646+ // since this could lead to another panic and abort the process.
1647+ self_. drop_elements ( ) ;
16351648
16361649 // If necessary, resize our table to match the source.
1637- if self . buckets ( ) != source. buckets ( ) {
1650+ if self_ . buckets ( ) != source. buckets ( ) {
16381651 // Skip our drop by using ptr::write.
1639- if !self . table . is_empty_singleton ( ) {
1640- self . free_buckets ( ) ;
1652+ if !self_ . table . is_empty_singleton ( ) {
1653+ self_ . free_buckets ( ) ;
16411654 }
1642- ( self as * mut Self ) . write (
1655+ ( & mut * * self_ as * mut Self ) . write (
16431656 // Avoid `Result::unwrap_or_else` because it bloats LLVM IR.
16441657 match Self :: new_uninitialized (
1645- self . table . alloc . clone ( ) ,
1658+ self_ . table . alloc . clone ( ) ,
16461659 source. buckets ( ) ,
16471660 Fallibility :: Infallible ,
16481661 ) {
@@ -1652,31 +1665,31 @@ impl<T: Clone, A: Allocator + Clone> Clone for RawTable<T, A> {
16521665 ) ;
16531666 }
16541667
1655- self . clone_from_spec ( source, |self_| {
1656- // We need to leave the table in an empty state.
1657- self_ . clear_no_drop ( ) ;
1658- } ) ;
1668+ self_ . clone_from_spec ( source) ;
1669+
1670+ // Disarm the scope guard if cloning was successful.
1671+ ScopeGuard :: into_inner ( self_ ) ;
16591672 }
16601673 }
16611674 }
16621675}
16631676
16641677/// Specialization of `clone_from` for `Copy` types
16651678trait RawTableClone {
1666- unsafe fn clone_from_spec ( & mut self , source : & Self , on_panic : impl FnMut ( & mut Self ) ) ;
1679+ unsafe fn clone_from_spec ( & mut self , source : & Self ) ;
16671680}
16681681impl < T : Clone , A : Allocator + Clone > RawTableClone for RawTable < T , A > {
16691682 default_fn ! {
16701683 #[ cfg_attr( feature = "inline-more" , inline) ]
1671- unsafe fn clone_from_spec( & mut self , source: & Self , on_panic : impl FnMut ( & mut Self ) ) {
1672- self . clone_from_impl( source, on_panic ) ;
1684+ unsafe fn clone_from_spec( & mut self , source: & Self ) {
1685+ self . clone_from_impl( source) ;
16731686 }
16741687 }
16751688}
16761689#[ cfg( feature = "nightly" ) ]
16771690impl < T : Copy , A : Allocator + Clone > RawTableClone for RawTable < T , A > {
16781691 #[ cfg_attr( feature = "inline-more" , inline) ]
1679- unsafe fn clone_from_spec ( & mut self , source : & Self , _on_panic : impl FnMut ( & mut Self ) ) {
1692+ unsafe fn clone_from_spec ( & mut self , source : & Self ) {
16801693 source
16811694 . table
16821695 . ctrl ( 0 )
@@ -1691,9 +1704,12 @@ impl<T: Copy, A: Allocator + Clone> RawTableClone for RawTable<T, A> {
16911704}
16921705
16931706impl < T : Clone , A : Allocator + Clone > RawTable < T , A > {
1694- /// Common code for clone and clone_from. Assumes `self.buckets() == source.buckets()`.
1707+ /// Common code for clone and clone_from. Assumes:
1708+ /// - `self.buckets() == source.buckets()`.
1709+ /// - Any existing elements have been dropped.
1710+ /// - The control bytes are not initialized yet.
16951711 #[ cfg_attr( feature = "inline-more" , inline) ]
1696- unsafe fn clone_from_impl ( & mut self , source : & Self , mut on_panic : impl FnMut ( & mut Self ) ) {
1712+ unsafe fn clone_from_impl ( & mut self , source : & Self ) {
16971713 // Copy the control bytes unchanged. We do this in a single pass
16981714 source
16991715 . table
@@ -1711,11 +1727,6 @@ impl<T: Clone, A: Allocator + Clone> RawTable<T, A> {
17111727 }
17121728 }
17131729 }
1714-
1715- // Depending on whether we were called from clone or clone_from, we
1716- // either need to free the memory for the destination table or just
1717- // clear the control bytes.
1718- on_panic ( self_) ;
17191730 } ) ;
17201731
17211732 for from in source. iter ( ) {
0 commit comments