-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Lint for returning raw pointers to temporary stack locations that don't outlive the statement that creates them #10959
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This would be very nice. I've written code like EnumProcessModules(
/*
etc...
*/
&mut 0 as _,
); way too many times, since it both compiles and almost always causes nothing out of the ordinary due to it still pointing at allocated memory (though is of course UB). @rustbot claim |
Hmm, is this actually UB? It seems to me like For example: struct NoisyDrop;
impl Drop for NoisyDrop {
fn drop(&mut self) {
println!("drop!");
}
}
fn temporary() -> NoisyDrop {
NoisyDrop
}
fn main() {
let x = &(temporary()) as *const NoisyDrop;
println!("after declaration of x");
} This prints "after declaration of x!", "drop!" in that order, implying that it is in fact not dropped immediately and has its lifetime extended |
That's interesting. The case I had that prompted me to create this issue was something like So maybe the problem is actually a bit more narrow here: the lifetime of the temporary is extended until the end up the scope, but it's not obvious that a temporary is involved here and the lifetime of the pointer is actually bound to the temporary. |
Yeah, looks like that in particular ( #[derive(Debug)]
#[repr(transparent)]
struct A(usize);
impl Drop for A {
fn drop(&mut self) {
println!("dropped! {self:?}");
}
}
fn main() {
const PS: [A; 3] = [A(2usize), A(3usize), A(11usize)];
let mut ps = vec![];
for p in PS {
ps.push(&p as *const A);
}
for p in ps {
println!("read! {:?}", unsafe { p.read() });
}
} is UB. |
What it does
The general pattern of the code this should complain about is something like
Similar with using
addr_of!
instead of&
and casts, etc.Concrete examples this would catch are
In both cases the part in the parenthesis is stored in a temporary stack location that is no longer valid after the whole statement.
It should however not catch
Advantage
Whatever pointer is created there is pointing to no longer valid stack memory, so any usage afterwards will be unsound
Drawbacks
Theoretically this could cause false positives but the only case I can see where the resulting code is not unsound is if you cast the pointer to an
usize
and do some calculations with it. I don't see how that could lead to any useful results in such a context though.Example
See examples above
The text was updated successfully, but these errors were encountered: