Skip to content

Commit f50c99e

Browse files
committed
Ensure safety even in the face of panics
1 parent 27b6a1f commit f50c99e

1 file changed

Lines changed: 33 additions & 23 deletions

File tree

library/alloc/src/string.rs

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3658,6 +3658,10 @@ impl String {
36583658
while let Some(l_c) = wc.pop() {
36593659
l_c.to_uppercase().for_each(|u_c| wc.write(u_c));
36603660
}
3661+
// SAFETY: At this point, none of the methods of wc panicked
3662+
unsafe {
3663+
wc.finalize();
3664+
}
36613665
}
36623666

36633667
/// Converts this string to its lowercase equivalent in-place.
@@ -3725,6 +3729,10 @@ impl String {
37253729
u_c.is_cased() || (word_final_so_far && u_c.is_case_ignorable());
37263730
}
37273731
}
3732+
// SAFETY: At this point, none of the methods of wc panicked
3733+
unsafe {
3734+
wc.finalize();
3735+
}
37283736
}
37293737
}
37303738

@@ -3734,39 +3742,19 @@ impl String {
37343742
struct WriteChars<'a> {
37353743
// This is the internal buffer of the string temporarily changed to Vec<u8> because
37363744
// it will contain non utf8 bytes.
3737-
// invariant: self.v.len() == original string until drop is run
3745+
// invariant: self.v.len() == original string until finalize is run
37383746
v: Vec<u8>,
37393747
// A reference kept to restore the string at the end
3740-
// (ie drop time)
3748+
// (ie finalize time)
37413749
s: &'a mut String,
37423750
// invariant: write_offset <= read_offset
37433751
write_offset: usize,
37443752
// invariant: self.read_offset <= self.v.len()
3745-
// before the Drop
3753+
// before finalize
37463754
read_offset: usize,
37473755
buffer: VecDeque<u8>,
37483756
}
37493757

3750-
impl<'a> Drop for WriteChars<'a> {
3751-
// Set the proper length of the string's storage
3752-
// or grow it to add what is still in the buffer.
3753-
fn drop(&mut self) {
3754-
if self.buffer.is_empty() {
3755-
// SAFETY: if the queue is empty, then
3756-
// there were less bytes than in the original so we can simply shrink
3757-
unsafe {
3758-
self.v.set_len(self.write_offset);
3759-
}
3760-
} else {
3761-
let (q1, q2) = self.buffer.as_slices();
3762-
self.v.extend_from_slice(q1);
3763-
self.v.extend_from_slice(q2);
3764-
};
3765-
// SAFETY: this is valid utf8
3766-
*self.s = unsafe { String::from_utf8_unchecked(core::mem::take(&mut self.v)) }
3767-
}
3768-
}
3769-
37703758
#[unstable(issue = "none", feature = "std_internals")]
37713759
impl<'a> WriteChars<'a> {
37723760
fn new(s: &'a mut String) -> Self {
@@ -3806,4 +3794,26 @@ impl<'a> WriteChars<'a> {
38063794
self.write_offset += direct_copy_length;
38073795
self.buffer.extend(&buffer[direct_copy_length..len]);
38083796
}
3797+
3798+
// Set the proper length of the string's storage
3799+
// or grow it to add what is still in the buffer.
3800+
/// Finalize should be run for the modifications to be actually written back to the string
3801+
/// # Safety
3802+
/// Must not be called if one of the previous method calls of self panicked because the buffer
3803+
/// may contain invalid utf8
3804+
unsafe fn finalize(mut self) {
3805+
if self.buffer.is_empty() {
3806+
// SAFETY: if the queue is empty, then
3807+
// there were less bytes than in the original so we can simply shrink
3808+
unsafe {
3809+
self.v.set_len(self.write_offset);
3810+
}
3811+
} else {
3812+
let (q1, q2) = self.buffer.as_slices();
3813+
self.v.extend_from_slice(q1);
3814+
self.v.extend_from_slice(q2);
3815+
};
3816+
// SAFETY: this is valid utf8
3817+
*self.s = unsafe { String::from_utf8_unchecked(core::mem::take(&mut self.v)) }
3818+
}
38093819
}

0 commit comments

Comments
 (0)