Fix invalid slice access in String::retain

This commit is contained in:
Giacomo Stevanato 2021-02-26 15:44:35 +01:00
parent d95d304861
commit c89e64363b

View file

@ -1233,37 +1233,44 @@ impl String {
where where
F: FnMut(char) -> bool, F: FnMut(char) -> bool,
{ {
let len = self.len(); struct SetLenOnDrop<'a> {
let mut del_bytes = 0; s: &'a mut String,
let mut idx = 0; idx: usize,
del_bytes: usize,
unsafe {
self.vec.set_len(0);
} }
while idx < len { impl<'a> Drop for SetLenOnDrop<'a> {
let ch = unsafe { self.get_unchecked(idx..len).chars().next().unwrap() }; fn drop(&mut self) {
let new_len = self.idx - self.del_bytes;
debug_assert!(new_len <= self.s.len());
unsafe { self.s.vec.set_len(new_len) };
}
}
let len = self.len();
let mut guard = SetLenOnDrop { s: self, idx: 0, del_bytes: 0 };
while guard.idx < len {
let ch = unsafe { guard.s.get_unchecked(guard.idx..len).chars().next().unwrap() };
let ch_len = ch.len_utf8(); let ch_len = ch.len_utf8();
if !f(ch) { if !f(ch) {
del_bytes += ch_len; guard.del_bytes += ch_len;
} else if del_bytes > 0 { } else if guard.del_bytes > 0 {
unsafe { unsafe {
ptr::copy( ptr::copy(
self.vec.as_ptr().add(idx), guard.s.vec.as_ptr().add(guard.idx),
self.vec.as_mut_ptr().add(idx - del_bytes), guard.s.vec.as_mut_ptr().add(guard.idx - guard.del_bytes),
ch_len, ch_len,
); );
} }
} }
// Point idx to the next char // Point idx to the next char
idx += ch_len; guard.idx += ch_len;
} }
unsafe { drop(guard);
self.vec.set_len(len - del_bytes);
}
} }
/// Inserts a character into this `String` at a byte position. /// Inserts a character into this `String` at a byte position.