@@ -135,13 +135,9 @@ macro_rules! copy_slice_and_advance {
135135//
136136// This implementation calls `borrow()` multiple times:
137137// 1. To calculate `reserved_len`, all elements are borrowed once.
138- // 2. The first element is borrowed again when copied via `extend_from_slice`.
139- // 3. Subsequent elements are borrowed a second time when building the mapped iterator.
138+ // 2. All elements, except the first, are borrowed a second time when building the mapped iterator.
140139//
141140// Risks and Mitigations:
142- // - If the first element GROWS on the second borrow, the length subtraction underflows.
143- // We mitigate this by doing a `checked_sub` to panic rather than allowing an underflow
144- // that fabricates a huge destination slice.
145141// - If elements 2..N GROW on their second borrow, the target slice bounds set by `checked_sub`
146142// means that `split_at_mut` inside `copy_slice_and_advance!` will correctly panic.
147143// - If elements SHRINK on their second borrow, the spare space is never written, and the final
@@ -157,8 +153,10 @@ where
157153 let mut iter = slice. iter ( ) ;
158154
159155 // the first slice is the only one without a separator preceding it
156+ // we take care to only borrow this once during the length calculation
157+ // to avoid inconsistent Borrow implementations from breaking our assumptions
160158 let first = match iter. next ( ) {
161- Some ( first) => first,
159+ Some ( first) => first. borrow ( ) . as_ref ( ) ,
162160 None => return vec ! [ ] ,
163161 } ;
164162
@@ -168,21 +166,24 @@ where
168166 // the entire Vec pre-allocated for safety
169167 let reserved_len = sep_len
170168 . checked_mul ( iter. len ( ) )
169+ . and_then ( |n| n. checked_add ( first. len ( ) ) )
171170 . and_then ( |n| {
172- slice. iter ( ) . map ( |s| s. borrow ( ) . as_ref ( ) . len ( ) ) . try_fold ( n, usize:: checked_add)
171+ // iter starts from the second element as we've already taken the first
172+ // it's cloned so we can reuse the same iterator below
173+ iter. clone ( ) . map ( |s| s. borrow ( ) . as_ref ( ) . len ( ) ) . try_fold ( n, usize:: checked_add)
173174 } )
174175 . expect ( "attempt to join into collection with len > usize::MAX" ) ;
175176
176177 // prepare an uninitialized buffer
177178 let mut result = Vec :: with_capacity ( reserved_len) ;
178179 debug_assert ! ( result. capacity( ) >= reserved_len) ;
179180
180- result. extend_from_slice ( first. borrow ( ) . as_ref ( ) ) ;
181+ result. extend_from_slice ( first) ;
181182
182183 unsafe {
183184 let pos = result. len ( ) ;
184- let target_len = reserved_len . checked_sub ( pos) . expect ( "inconsistent Borrow implementation" ) ;
185- let target = result. spare_capacity_mut ( ) . get_unchecked_mut ( ..target_len ) ;
185+ debug_assert ! ( reserved_len >= pos) ;
186+ let target = result. spare_capacity_mut ( ) . get_unchecked_mut ( ..reserved_len - pos ) ;
186187
187188 // Convert the separator and slices to slices of MaybeUninit
188189 // to simplify implementation in specialize_for_lengths.
0 commit comments