Skip to content

Commit c010e99

Browse files
Replace mem::forget with ManuallyDrop::new (#3515)
* Replace `mem::forget` with `ManuallyDrop::new` It's way less footgunny w.r.t. pointer aliasing: - At worst, it's equivalent; - But the advantage of `ManuallyDrop::new()`, is that it can be used _before_ extracting data off the value, such as pointers, thereby avoiding the danger of aliasing invalidation that `mem::forget` may apply. Co-authored-by: Daniel Henry-Mantilla <[email protected]>
1 parent e000bcc commit c010e99

File tree

4 files changed

+35
-39
lines changed

4 files changed

+35
-39
lines changed

utils/zerovec/src/ule/encode.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,11 @@ pub fn encode_varule_to_box<S: EncodeAsVarULE<T>, T: VarULE + ?Sized>(x: &S) ->
8686
// zero-fill the vector to avoid uninitialized data UB
8787
vec.resize(x.encode_var_ule_len(), 0);
8888
x.encode_var_ule_write(&mut vec);
89-
let boxed = vec.into_boxed_slice();
89+
let boxed = mem::ManuallyDrop::new(vec.into_boxed_slice());
9090
unsafe {
9191
// Safety: `ptr` is a box, and `T` is a VarULE which guarantees it has the same memory layout as `[u8]`
9292
// and can be recouped via from_byte_slice_unchecked()
9393
let ptr: *mut T = T::from_byte_slice_unchecked(&boxed) as *const T as *mut T;
94-
mem::forget(boxed);
9594

9695
// Safety: we can construct an owned version since we have mem::forgotten the older owner
9796
Box::from_raw(ptr)

utils/zerovec/src/ule/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,13 +357,12 @@ pub unsafe trait VarULE: 'static {
357357
#[inline]
358358
fn to_boxed(&self) -> Box<Self> {
359359
let bytesvec = self.as_byte_slice().to_owned().into_boxed_slice();
360+
let bytesvec = mem::ManuallyDrop::new(bytesvec);
360361
unsafe {
361362
// Get the pointer representation
362363
let ptr: *mut Self =
363364
Self::from_byte_slice_unchecked(&bytesvec) as *const Self as *mut Self;
364-
assert_eq!(Layout::for_value(&*ptr), Layout::for_value(&*bytesvec));
365-
// Forget the allocation
366-
mem::forget(bytesvec);
365+
assert_eq!(Layout::for_value(&*ptr), Layout::for_value(&**bytesvec));
367366
// Transmute the pointer to an owned pointer
368367
Box::from_raw(ptr)
369368
}

utils/zerovec/src/yoke_impls.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ unsafe impl<'a, T: 'static + AsULE + ?Sized> Yokeable<'a> for ZeroVec<'static, T
3333
#[inline]
3434
unsafe fn make(from: Self::Output) -> Self {
3535
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
36-
let ptr: *const Self = (&from as *const Self::Output).cast();
37-
mem::forget(from);
36+
let from = mem::ManuallyDrop::new(from);
37+
let ptr: *const Self = (&*from as *const Self::Output).cast();
3838
ptr::read(ptr)
3939
}
4040
#[inline]
@@ -61,8 +61,8 @@ unsafe impl<'a, T: 'static + VarULE + ?Sized> Yokeable<'a> for VarZeroVec<'stati
6161
#[inline]
6262
unsafe fn make(from: Self::Output) -> Self {
6363
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
64-
let ptr: *const Self = (&from as *const Self::Output).cast();
65-
mem::forget(from);
64+
let from = mem::ManuallyDrop::new(from);
65+
let ptr: *const Self = (&*from as *const Self::Output).cast();
6666
ptr::read(ptr)
6767
}
6868
#[inline]
@@ -89,8 +89,8 @@ unsafe impl<'a> Yokeable<'a> for FlexZeroVec<'static> {
8989
#[inline]
9090
unsafe fn make(from: Self::Output) -> Self {
9191
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
92-
let ptr: *const Self = (&from as *const Self::Output).cast();
93-
mem::forget(from);
92+
let from = mem::ManuallyDrop::new(from);
93+
let ptr: *const Self = (&*from as *const Self::Output).cast();
9494
ptr::read(ptr)
9595
}
9696
#[inline]
@@ -127,16 +127,16 @@ where
127127
unsafe {
128128
// Similar problem as transform(), but we need to use ptr::read since
129129
// the compiler isn't sure of the sizes
130-
let ptr: *const Self::Output = (&self as *const Self).cast();
131-
mem::forget(self);
130+
let this = mem::ManuallyDrop::new(self);
131+
let ptr: *const Self::Output = (&*this as *const Self).cast();
132132
ptr::read(ptr)
133133
}
134134
}
135135
#[inline]
136136
unsafe fn make(from: Self::Output) -> Self {
137137
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
138-
let ptr: *const Self = (&from as *const Self::Output).cast();
139-
mem::forget(from);
138+
let from = mem::ManuallyDrop::new(from);
139+
let ptr: *const Self = (&*from as *const Self::Output).cast();
140140
ptr::read(ptr)
141141
}
142142
#[inline]
@@ -173,16 +173,16 @@ where
173173
unsafe {
174174
// Similar problem as transform(), but we need to use ptr::read since
175175
// the compiler isn't sure of the sizes
176-
let ptr: *const Self::Output = (&self as *const Self).cast();
177-
mem::forget(self);
176+
let this = mem::ManuallyDrop::new(self);
177+
let ptr: *const Self::Output = (&*this as *const Self).cast();
178178
ptr::read(ptr)
179179
}
180180
}
181181
#[inline]
182182
unsafe fn make(from: Self::Output) -> Self {
183183
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
184-
let ptr: *const Self = (&from as *const Self::Output).cast();
185-
mem::forget(from);
184+
let from = mem::ManuallyDrop::new(from);
185+
let ptr: *const Self = (&*from as *const Self::Output).cast();
186186
ptr::read(ptr)
187187
}
188188
#[inline]
@@ -221,16 +221,16 @@ where
221221
unsafe {
222222
// Similar problem as transform(), but we need to use ptr::read since
223223
// the compiler isn't sure of the sizes
224-
let ptr: *const Self::Output = (&self as *const Self).cast();
225-
mem::forget(self);
224+
let this = mem::ManuallyDrop::new(self);
225+
let ptr: *const Self::Output = (&*this as *const Self).cast();
226226
ptr::read(ptr)
227227
}
228228
}
229229
#[inline]
230230
unsafe fn make(from: Self::Output) -> Self {
231231
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
232-
let ptr: *const Self = (&from as *const Self::Output).cast();
233-
mem::forget(from);
232+
let from = mem::ManuallyDrop::new(from);
233+
let ptr: *const Self = (&*from as *const Self::Output).cast();
234234
ptr::read(ptr)
235235
}
236236
#[inline]
@@ -269,16 +269,16 @@ where
269269
unsafe {
270270
// Similar problem as transform(), but we need to use ptr::read since
271271
// the compiler isn't sure of the sizes
272-
let ptr: *const Self::Output = (&self as *const Self).cast();
273-
mem::forget(self);
272+
let this = mem::ManuallyDrop::new(self);
273+
let ptr: *const Self::Output = (&*this as *const Self).cast();
274274
ptr::read(ptr)
275275
}
276276
}
277277
#[inline]
278278
unsafe fn make(from: Self::Output) -> Self {
279279
debug_assert!(mem::size_of::<Self::Output>() == mem::size_of::<Self>());
280-
let ptr: *const Self = (&from as *const Self::Output).cast();
281-
mem::forget(from);
280+
let from = mem::ManuallyDrop::new(from);
281+
let ptr: *const Self = (&*from as *const Self::Output).cast();
282282
ptr::read(ptr)
283283
}
284284
#[inline]

utils/zerovec/src/zerovec/mod.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use core::marker::PhantomData;
2222
use core::mem;
2323
use core::num::NonZeroUsize;
2424
use core::ops::Deref;
25+
use core::ptr;
2526

2627
/// A zero-copy, byte-aligned vector for fixed-width types.
2728
///
@@ -286,14 +287,14 @@ where
286287
/// If you have a slice of `&[T]`s, prefer using
287288
/// [`Self::alloc_from_slice()`].
288289
#[inline]
289-
pub fn new_owned(mut vec: Vec<T::ULE>) -> Self {
290+
pub fn new_owned(vec: Vec<T::ULE>) -> Self {
290291
// Deconstruct the vector into parts
291292
// This is the only part of the code that goes from Vec
292293
// to ZeroVec, all other such operations should use this function
293-
let slice: &mut [T::ULE] = &mut vec;
294-
let slice = slice as *mut [_];
295294
let capacity = vec.capacity();
296-
mem::forget(vec);
295+
let len = vec.len();
296+
let ptr = mem::ManuallyDrop::new(vec).as_mut_ptr();
297+
let slice = ptr::slice_from_raw_parts_mut(ptr, len);
297298
Self {
298299
vector: EyepatchHackVector {
299300
buf: slice,
@@ -894,21 +895,18 @@ where
894895
/// the logical equivalent of this type's internal representation
895896
#[inline]
896897
pub fn into_cow(self) -> Cow<'a, [T::ULE]> {
897-
if self.is_owned() {
898+
let this = mem::ManuallyDrop::new(self);
899+
if this.is_owned() {
898900
let vec = unsafe {
899901
// safe to call: we know it's owned,
900-
// and we mem::forget self immediately afterwards
901-
self.vector.get_vec()
902+
// and `self`/`this` are thenceforth no longer used or dropped
903+
{ this }.vector.get_vec()
902904
};
903-
mem::forget(self);
904905
Cow::Owned(vec)
905906
} else {
906907
// We can extend the lifetime of the slice to 'a
907908
// since we know it is borrowed
908-
let slice = unsafe { self.vector.as_arbitrary_slice() };
909-
// The borrowed destructor is a no-op, but we want to prevent
910-
// the check being run
911-
mem::forget(self);
909+
let slice = unsafe { { this }.vector.as_arbitrary_slice() };
912910
Cow::Borrowed(slice)
913911
}
914912
}

0 commit comments

Comments
 (0)