@@ -92,8 +92,8 @@ impl<S: Borrow<str>> Join<&str> for [S] {
9292 }
9393}
9494
95- macro_rules! spezialize_for_lengths {
96- ( $separator: expr, $target: expr, $iter: expr; $( $num: expr) ,* ) => {
95+ macro_rules! specialize_for_lengths {
96+ ( $separator: expr, $target: expr, $iter: expr; $( $num: expr) ,* ) => { {
9797 let mut target = $target;
9898 let iter = $iter;
9999 let sep_bytes = $separator;
@@ -104,19 +104,22 @@ macro_rules! spezialize_for_lengths {
104104 $num => {
105105 for s in iter {
106106 copy_slice_and_advance!( target, sep_bytes) ;
107- copy_slice_and_advance!( target, s. borrow( ) . as_ref( ) ) ;
107+ let content_bytes = s. borrow( ) . as_ref( ) ;
108+ copy_slice_and_advance!( target, content_bytes) ;
108109 }
109110 } ,
110111 ) *
111112 _ => {
112113 // arbitrary non-zero size fallback
113114 for s in iter {
114115 copy_slice_and_advance!( target, sep_bytes) ;
115- copy_slice_and_advance!( target, s. borrow( ) . as_ref( ) ) ;
116+ let content_bytes = s. borrow( ) . as_ref( ) ;
117+ copy_slice_and_advance!( target, content_bytes) ;
116118 }
117119 }
118120 }
119- } ;
121+ target
122+ } }
120123}
121124
122125macro_rules! copy_slice_and_advance {
@@ -155,30 +158,33 @@ where
155158 // if the `len` calculation overflows, we'll panic
156159 // we would have run out of memory anyway and the rest of the function requires
157160 // the entire Vec pre-allocated for safety
158- let len = sep_len
161+ let reserved_len = sep_len
159162 . checked_mul ( iter. len ( ) )
160163 . and_then ( |n| {
161164 slice. iter ( ) . map ( |s| s. borrow ( ) . as_ref ( ) . len ( ) ) . try_fold ( n, usize:: checked_add)
162165 } )
163166 . expect ( "attempt to join into collection with len > usize::MAX" ) ;
164167
165- // crucial for safety
166- let mut result = Vec :: with_capacity ( len ) ;
167- assert ! ( result. capacity( ) >= len ) ;
168+ // prepare an uninitialized buffer
169+ let mut result = Vec :: with_capacity ( reserved_len ) ;
170+ debug_assert ! ( result. capacity( ) >= reserved_len ) ;
168171
169172 result. extend_from_slice ( first. borrow ( ) . as_ref ( ) ) ;
170173
171174 unsafe {
172- {
173- let pos = result. len ( ) ;
174- let target = result. get_unchecked_mut ( pos..len) ;
175-
176- // copy separator and slices over without bounds checks
177- // generate loops with hardcoded offsets for small separators
178- // massive improvements possible (~ x2)
179- spezialize_for_lengths ! ( sep, target, iter; 0 , 1 , 2 , 3 , 4 ) ;
180- }
181- result. set_len ( len) ;
175+ let pos = result. len ( ) ;
176+ let target = result. get_unchecked_mut ( pos..reserved_len) ;
177+
178+ // copy separator and slices over without bounds checks
179+ // generate loops with hardcoded offsets for small separators
180+ // massive improvements possible (~ x2)
181+ let remain = specialize_for_lengths ! ( sep, target, iter; 0 , 1 , 2 , 3 , 4 ) ;
182+
183+ // A weird borrow implementation may return different
184+ // slices for the length calculation and the actual copy.
185+ // Make sure we don't expose uninitialized bytes to the caller.
186+ let result_len = reserved_len - remain. len ( ) ;
187+ result. set_len ( result_len) ;
182188 }
183189 result
184190}
0 commit comments