Skip to content

Commit 4aed74f

Browse files
committed
Fix: ErasedPtr::with_mut()
- using scopeguard to write the pointer back into its original place - correct the ManuallyDrop() to wrap the actual value and take it out in the scopeguard
1 parent cd77ea9 commit 4aed74f

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

crates/erasable/src/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,12 @@ pub unsafe trait ErasablePtr {
232232
Self: Sized,
233233
F: FnOnce(&mut Self) -> T,
234234
{
235-
f(&mut ManuallyDrop::new(&mut Self::unerase(*this)))
235+
// SAFETY: guard is required to write potentially changed pointer value, even on unwind
236+
let mut that = scopeguard::guard(ManuallyDrop::new(Self::unerase(*this)), |unerased| {
237+
ptr::write(this, ErasablePtr::erase(ManuallyDrop::into_inner(unerased)));
238+
});
239+
240+
f(&mut that)
236241
}
237242
}
238243

crates/erasable/tests/smoke.rs

+25
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,29 @@ fn with_mut_fn() {
6161
assert_ne!(*bigbox, Default::default());
6262
})
6363
}
64+
65+
// drop it, otherwise we would leak memory here
66+
unsafe { <Box<Big> as ErasablePtr>::unerase(erased) };
67+
}
68+
69+
#[test]
70+
fn with_mut_fn_replacethis() {
71+
let boxed: Box<Big> = Default::default();
72+
73+
let mut erased: ErasedPtr = ErasablePtr::erase(boxed);
74+
let e1 = erased.as_ptr() as usize;
75+
unsafe {
76+
<Box<Big> as ErasablePtr>::with_mut(&mut erased, |bigbox| {
77+
let mut newboxed: Box<Big> = Default::default();
78+
newboxed.0[0] = 123456;
79+
*bigbox = newboxed;
80+
assert_ne!(*bigbox, Default::default());
81+
})
82+
}
83+
84+
let e2 = erased.as_ptr() as usize;
85+
assert_ne!(e1, e2);
86+
87+
// drop it, otherwise we would leak memory here
88+
unsafe { <Box<Big> as ErasablePtr>::unerase(erased) };
6489
}

0 commit comments

Comments
 (0)