Skip to content

Update unsound DrainFilter and RString::retain #44

@Qwaz

Description

@Qwaz

Hello, we (Rust group @sslab-gatech) found a memory-safety/soundness issue in this crate while scanning Rust code on crates.io for potential vulnerabilities.

impl<T, F> Iterator for DrainFilter<'_, T, F>
where F: FnMut(&mut T) -> bool,
{
type Item = T;
fn next(&mut self) -> Option<T> {
unsafe {
while self.idx != self.old_len {
let i = self.idx;
self.idx += 1;
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
if (self.pred)(&mut v[i]) {
self.del += 1;
return Some(ptr::read(&v[i]));
} else if self.del > 0 {
let del = self.del;
let src: *const T = &v[i];
let dst: *mut T = &mut v[i - del];
ptr::copy_nonoverlapping(src, dst, 1);
}
}
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.old_len - self.idx))
}
}

#[inline]
pub fn retain<F>(&mut self, mut pred: F)
where F: FnMut(char) -> bool
{
// literal copy-paste of std,so if this is wrong std is wrong.
let len = self.len();
let mut del_bytes = 0;
let mut idx = 0;
while idx < len {
let ch = unsafe {
self.get_unchecked(idx..len).chars().next().unwrap()
};
let ch_len = ch.len_utf8();
if !pred(ch) {
del_bytes += ch_len;
} else if del_bytes > 0 {
unsafe {
ptr::copy(
self.inner.as_ptr().add(idx),
self.inner.as_mut_ptr().add(idx - del_bytes),
ch_len
);
}
}
idx += ch_len;
}
if del_bytes > 0 {
unsafe { self.inner.set_len(len - del_bytes); }
}
}

These two implementations are copy-pasted from Rust's standard library, and unfortunately it turns out that std implementations were containing soundness bugs (rust-lang/rust#60977 and rust-lang/rust#78498, respectively). Could you check them and update the respective part of this crate?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions