Hello, I created a new crate called extend_mut, which allows you to temporary extend exclusive lifetime. Can you please review it for unsoundness, or maybe there already are alternative crates/patterns?
This is unsound in combination with crates which uses a ZST as a token for permission to access something. It's allowed to have two &muts to the same address for ZSTs, so the pointer equality check you did doesn't prevent the closure from storing the &mut it got somewhere globally.
Thank you for a great catch! I will think about solution for this. I guess with generic_const_exprs
there can be a trait implemented for size_of::<T>() != 0
, or just add post-monomorphization const { assert!(size_of::<T>() != 0) }
It would probably be unsoud with Tracking Issue for RFC 3467: UnsafePinned · Issue #125735 · rust-lang/rust · GitHub too, as types with UnsafePinned
inside are allowed to &mut
alias. But I am not sure how to safely exploit this yet.
Thinking about it again, I'm not sure if the ZST thing is actually unsound. The best I could do is write this function, which I'm unsure whether it's sound or not.
use extend_mut::extend_mut;
// Given two references with the same address,
// returns a reference with the first one's provenance but the second one's lifetime.
fn silly<'a, 'b, T>(x: &'a mut T, y: &'b mut T) -> &'b mut T {
assert!(size_of::<T>() == 0);
assert!(std::ptr::eq(x, y));
let mut x_holder: Option<&'b mut T> = None;
extend_mut(x, |x_arg: &'b mut T| {
x_holder = Some(x_arg);
y
});
x_holder.unwrap()
}
I found a simpler unsoundness. This code segfaults
use extend_mut::{extend_mut, IntoExtendMutReturn};
struct Weird;
impl<'a, T> IntoExtendMutReturn<'a, T, i64> for Weird {
fn into_extend_mut_return(self) -> (&'a mut T, i64) {
panic!()
}
}
struct PrintOnDrop<'a>(Option<&'a Box<i32>>);
impl Drop for PrintOnDrop<'_> {
fn drop(&mut self) {
println!("Dropping: {:?}", self.0);
}
}
fn main() {
let mut holder = PrintOnDrop(None);
{
let mut x = Box::new(Box::new(123));
extend_mut(&mut *x, |x_arg| {
holder.0 = Some(x_arg);
Weird
});
}
}
Oh, I forgot to seal that trait . Nice catch!
I think nesting two extend_mut
may be a way to zst exploit