A weird Borrow implementation that returns a different result for each call can create a string with uninitialized bytes with join() implementation of [Borrow<str>] type.
The problem is in join_generic_copy function.
-
The borrow result is first used for the length calculation.
|
// compute the exact total length of the joined Vec |
|
// if the `len` calculation overflows, we'll panic |
|
// we would have run out of memory anyway and the rest of the function requires |
|
// the entire Vec pre-allocated for safety |
|
let len = sep_len |
|
.checked_mul(iter.len()) |
|
.and_then(|n| { |
|
slice.iter().map(|s| s.borrow().as_ref().len()).try_fold(n, usize::checked_add) |
|
}) |
|
.expect("attempt to join into collection with len > usize::MAX"); |
-
Then, inside spezialize_for_lengths macro, the user-provided slice is borrowed again and the content is copied.
|
// arbitrary non-zero size fallback |
|
for s in iter { |
|
copy_slice_and_advance!(target, sep_bytes); |
|
copy_slice_and_advance!(target, s.borrow().as_ref()); |
|
} |
-
Finally, the length of the slice is set to the length calculated in step 1.
Playground link, which demonstrates creating a non-UTF-8 string by only using safe Rust.
A weird
Borrowimplementation that returns a different result for each call can create a string with uninitialized bytes with join() implementation of[Borrow<str>]type.The problem is in
join_generic_copyfunction.The borrow result is first used for the length calculation.
rust/library/alloc/src/str.rs
Lines 152 to 161 in 3ffea60
Then, inside
spezialize_for_lengthsmacro, the user-provided slice is borrowed again and the content is copied.rust/library/alloc/src/str.rs
Lines 110 to 114 in 3ffea60
Finally, the length of the slice is set to the length calculated in step 1.
rust/library/alloc/src/str.rs
Line 179 in 3ffea60
Playground link, which demonstrates creating a non-UTF-8 string by only using safe Rust.