Closed
Description
Looks like it's possible to impl Drop
for a stricter lifetime than the one used in the type:
struct Wrapper<'a, T>(&'a T)
where
T: 'a;
impl<'a, T> Drop for Wrapper<'a, T>
where
T: 'static, // ayy ayy
{
fn drop(&mut self) {
//
}
}
... which allows to essentially transmute from T: 'a
to T: 'static
, leading to unsoundness:
use std::{
fmt::Debug,
thread::{sleep, spawn},
time::Duration,
};
struct Wrapper<'a, T>(&'a T)
where
T: Clone + Debug + Send + 'a;
impl<'a, T> Drop for Wrapper<'a, T>
where
T: Clone + Debug + Send + 'static,
{
fn drop(&mut self) {
let value = self.0.to_owned();
spawn(move || {
// Wait for `main()` to finish dropping `self.0`
sleep(Duration::from_millis(100));
// Use-after-free
println!("value: {:?}", value);
});
}
}
#[derive(Clone, Copy, Debug)]
struct StringWrapper<'a>(&'a String);
fn main() {
let _ = Wrapper(&StringWrapper(&String::from("Hello!")));
// Wait for the thread to complete
sleep(Duration::from_secs(1));
}
On my machine, it prints:
value: StringWrapper("SU�Y\u{5}\u{0}")
Metadata
Metadata
Assignees
Labels
Area: Destructors (`Drop`, …)Area: Lifetimes / regionsCategory: This is a bug.Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessCritical priorityRelevant to the compiler team, which will review and decide on the PR/issue.Performance or correctness regression from one stable version to another.