1
1
use crate :: alloc:: alloc:: { handle_alloc_error, Layout } ;
2
- use crate :: scopeguard:: guard;
2
+ use crate :: scopeguard:: { guard, ScopeGuard } ;
3
3
use crate :: TryReserveError ;
4
4
use core:: iter:: FusedIterator ;
5
5
use core:: marker:: PhantomData ;
@@ -1602,25 +1602,27 @@ impl<T: Clone, A: Allocator + Clone> Clone for RawTable<T, A> {
1602
1602
Self :: new_in ( self . table . alloc . clone ( ) )
1603
1603
} else {
1604
1604
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| {
1619
1619
new_table. free_buckets ( ) ;
1620
1620
} ) ;
1621
1621
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) )
1624
1626
}
1625
1627
}
1626
1628
}
@@ -1630,19 +1632,30 @@ impl<T: Clone, A: Allocator + Clone> Clone for RawTable<T, A> {
1630
1632
* self = Self :: new_in ( self . table . alloc . clone ( ) ) ;
1631
1633
} else {
1632
1634
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 ( ) ;
1635
1648
1636
1649
// If necessary, resize our table to match the source.
1637
- if self . buckets ( ) != source. buckets ( ) {
1650
+ if self_ . buckets ( ) != source. buckets ( ) {
1638
1651
// 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 ( ) ;
1641
1654
}
1642
- ( self as * mut Self ) . write (
1655
+ ( & mut * * self_ as * mut Self ) . write (
1643
1656
// Avoid `Result::unwrap_or_else` because it bloats LLVM IR.
1644
1657
match Self :: new_uninitialized (
1645
- self . table . alloc . clone ( ) ,
1658
+ self_ . table . alloc . clone ( ) ,
1646
1659
source. buckets ( ) ,
1647
1660
Fallibility :: Infallible ,
1648
1661
) {
@@ -1652,31 +1665,31 @@ impl<T: Clone, A: Allocator + Clone> Clone for RawTable<T, A> {
1652
1665
) ;
1653
1666
}
1654
1667
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_ ) ;
1659
1672
}
1660
1673
}
1661
1674
}
1662
1675
}
1663
1676
1664
1677
/// Specialization of `clone_from` for `Copy` types
1665
1678
trait 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 ) ;
1667
1680
}
1668
1681
impl < T : Clone , A : Allocator + Clone > RawTableClone for RawTable < T , A > {
1669
1682
default_fn ! {
1670
1683
#[ 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) ;
1673
1686
}
1674
1687
}
1675
1688
}
1676
1689
#[ cfg( feature = "nightly" ) ]
1677
1690
impl < T : Copy , A : Allocator + Clone > RawTableClone for RawTable < T , A > {
1678
1691
#[ 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 ) {
1680
1693
source
1681
1694
. table
1682
1695
. ctrl ( 0 )
@@ -1691,9 +1704,12 @@ impl<T: Copy, A: Allocator + Clone> RawTableClone for RawTable<T, A> {
1691
1704
}
1692
1705
1693
1706
impl < 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.
1695
1711
#[ 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 ) {
1697
1713
// Copy the control bytes unchanged. We do this in a single pass
1698
1714
source
1699
1715
. table
@@ -1711,11 +1727,6 @@ impl<T: Clone, A: Allocator + Clone> RawTable<T, A> {
1711
1727
}
1712
1728
}
1713
1729
}
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_) ;
1719
1730
} ) ;
1720
1731
1721
1732
for from in source. iter ( ) {
0 commit comments