1
Fork 0

Rollup merge of #91426 - eggyal:idfunctor-panic-safety, r=lcnr

Make IdFunctor::try_map_id panic-safe

Addresses FIXME comment created in #78313

r? ```@lcnr```
This commit is contained in:
Matthias Krüger 2021-12-11 08:22:32 +01:00 committed by GitHub
commit 7e18b79c77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 24 deletions

View file

@ -34,38 +34,43 @@ impl<T> IdFunctor for Vec<T> {
type Inner = T; type Inner = T;
#[inline] #[inline]
fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E> fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
where where
F: FnMut(Self::Inner) -> Result<Self::Inner, E>, F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{ {
// FIXME: We don't really care about panics here and leak struct HoleVec<T> {
// far more than we should, but that should be fine for now. vec: Vec<mem::ManuallyDrop<T>>,
let len = self.len(); hole: Option<usize>,
unsafe { }
self.set_len(0);
let start = self.as_mut_ptr();
for i in 0..len {
let p = start.add(i);
match f(p.read()) {
Ok(val) => p.write(val),
Err(err) => {
// drop all other elements in self
// (current element was "moved" into the call to f)
for j in (0..i).chain(i + 1..len) {
start.add(j).drop_in_place();
}
// returning will drop self, releasing the allocation impl<T> Drop for HoleVec<T> {
// (len is 0 so elements will not be re-dropped) fn drop(&mut self) {
return Err(err); unsafe {
for (index, slot) in self.vec.iter_mut().enumerate() {
if self.hole != Some(index) {
mem::ManuallyDrop::drop(slot);
}
} }
} }
} }
// Even if we encountered an error, set the len back
// so we don't leak memory.
self.set_len(len);
} }
Ok(self)
unsafe {
let (ptr, length, capacity) = self.into_raw_parts();
let vec = Vec::from_raw_parts(ptr.cast(), length, capacity);
let mut hole_vec = HoleVec { vec, hole: None };
for (index, slot) in hole_vec.vec.iter_mut().enumerate() {
hole_vec.hole = Some(index);
let original = mem::ManuallyDrop::take(slot);
let mapped = f(original)?;
*slot = mem::ManuallyDrop::new(mapped);
hole_vec.hole = None;
}
mem::forget(hole_vec);
Ok(Vec::from_raw_parts(ptr, length, capacity))
}
} }
} }

View file

@ -23,6 +23,7 @@
#![feature(once_cell)] #![feature(once_cell)]
#![feature(test)] #![feature(test)]
#![feature(thread_id_value)] #![feature(thread_id_value)]
#![feature(vec_into_raw_parts)]
#![allow(rustc::default_hash_types)] #![allow(rustc::default_hash_types)]
#![deny(unaligned_references)] #![deny(unaligned_references)]