@@ -982,6 +982,8 @@ impl<T, A: Allocator> VecDeque<T, A> {
982982        // `head` and `len` are at most `isize::MAX` and `target_cap < self.capacity()`, so nothing can 
983983        // overflow. 
984984        let  tail_outside = ( target_cap + 1 ..=self . capacity ( ) ) . contains ( & ( self . head  + self . len ) ) ; 
985+         // Used in the drop guard below. 
986+         let  old_head = self . head ; 
985987
986988        if  self . len  == 0  { 
987989            self . head  = 0 ; 
@@ -1034,12 +1036,74 @@ impl<T, A: Allocator> VecDeque<T, A> {
10341036            } 
10351037            self . head  = new_head; 
10361038        } 
1037-         self . buf . shrink_to_fit ( target_cap) ; 
1039+ 
1040+         struct  Guard < ' a ,  T ,  A :  Allocator >  { 
1041+             deque :  & ' a  mut  VecDeque < T ,  A > , 
1042+             old_head :  usize , 
1043+             target_cap :  usize , 
1044+         } 
1045+ 
1046+         impl < T ,  A :  Allocator >  Drop  for  Guard < ' _ ,  T ,  A >  { 
1047+             #[ cold]  
1048+             fn  drop ( & mut  self )  { 
1049+                 unsafe  { 
1050+                     // SAFETY: This is only called if `buf.shrink_to_fit` unwinds, 
1051+                     // which is the only time it's safe to call `abort_shrink`. 
1052+                     self . deque . abort_shrink ( self . old_head ,  self . target_cap ) 
1053+                 } 
1054+             } 
1055+         } 
1056+ 
1057+         let  guard = Guard  {  deque :  self ,  old_head,  target_cap } ; 
1058+ 
1059+         guard. deque . buf . shrink_to_fit ( target_cap) ; 
1060+ 
1061+         // Don't drop the guard if we didn't unwind. 
1062+         mem:: forget ( guard) ; 
10381063
10391064        debug_assert ! ( self . head < self . capacity( )  || self . capacity( )  == 0 ) ; 
10401065        debug_assert ! ( self . len <= self . capacity( ) ) ; 
10411066    } 
10421067
1068+     /// Reverts the deque back into a consistent state in case `shrink_to` failed. 
1069+      /// This is necessary to prevent UB if the backing allocator returns an error 
1070+      /// from `shrink` and `handle_alloc_error` subsequently unwinds (see #123369). 
1071+      /// 
1072+      /// `old_head` refers to the head index before `shrink_to` was called. `target_cap` 
1073+      /// is the capacity that it was trying to shrink to. 
1074+      unsafe  fn  abort_shrink ( & mut  self ,  old_head :  usize ,  target_cap :  usize )  { 
1075+         // Moral equivalent of self.head + self.len <= target_cap. Won't overflow 
1076+         // because `self.len <= target_cap`. 
1077+         if  self . head  <= target_cap - self . len  { 
1078+             // The deque's buffer is contiguous, so no need to copy anything around. 
1079+             return ; 
1080+         } 
1081+ 
1082+         // `shrink_to` already copied the head to fit into the new capacity, so this won't overflow. 
1083+         let  head_len = target_cap - self . head ; 
1084+         // `self.head > target_cap - self.len` => `self.len > target_cap - self.head =: head_len` so this must be positive. 
1085+         let  tail_len = self . len  - head_len; 
1086+ 
1087+         if  tail_len <= cmp:: min ( head_len,  self . capacity ( )  - target_cap)  { 
1088+             // There's enough spare capacity to copy the tail to the back (because `tail_len < self.capacity() - target_cap`), 
1089+             // and copying the tail should be cheaper than copying the head (because `tail_len <= head_len`). 
1090+ 
1091+             unsafe  { 
1092+                 // The old tail and the new tail can't overlap because the head slice lies between them. The 
1093+                 // head slice ends at `target_cap`, so that's where we copy to. 
1094+                 self . copy_nonoverlapping ( 0 ,  target_cap,  tail_len) ; 
1095+             } 
1096+         }  else  { 
1097+             // Either there's not enough spare capacity to make the deque contiguous, or the head is shorter than the tail 
1098+             // (and therefore hopefully cheaper to copy). 
1099+             unsafe  { 
1100+                 // The old and the new head slice can overlap, so we can't use `copy_nonoverlapping` here. 
1101+                 self . copy ( self . head ,  old_head,  head_len) ; 
1102+                 self . head  = old_head; 
1103+             } 
1104+         } 
1105+     } 
1106+ 
10431107    /// Shortens the deque, keeping the first `len` elements and dropping 
10441108     /// the rest. 
10451109     /// 
0 commit comments