You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The general pattern of the code this should complain about is something like
let x = &(some expression that is stored in a temporary variable on the stack)as*constT;
Similar with using addr_of! instead of & and casts, etc.
Concrete examples this would catch are
let x = &(1 + 2)as*consti32;let x = &(x as*consti32)as*const*consti32;
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
let x = &(*ptr).xas*constT;let x = &(some_variable)as*constT;
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.
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).
Hmm, is this actually UB? It seems to me like let x = &(temporary) as *const _ specifically is ok because of Temporary Lifetime Extension (the temporary gets promoted to its own binding). Much like how you can also write something like let x = &mut String::new(); and use that x then.
Regardless though, it seems like a safety hazard and a lint for this seems nice.
For example:
structNoisyDrop;implDropforNoisyDrop{fndrop(&mutself){println!("drop!");}}fntemporary() -> NoisyDrop{NoisyDrop}fnmain(){let x = &(temporary())as*constNoisyDrop;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 &((*ptr).x as *const _) as *const _ (the part inside the parenthesis becomes a temporary on the stack), but that then was converted into a reference and actually returned from the function (the lifetime of ptr and the returned reference are bound correctly, but the returned reference is actually pointing to the temporary!). And that then did anything from crashes to asan/valgrind warnings. (The code in question should've been &(*ptr).x as *const _)
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.
Activity
addr_of!
instead of&x as *const _
#10872Centri3 commentedon Jun 15, 2023
This would be very nice. I've written code like
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
ptr_to_temporary
] #10962y21 commentedon Jun 15, 2023
Hmm, is this actually UB? It seems to me like
let x = &(temporary) as *const _
specifically is ok because of Temporary Lifetime Extension (the temporary gets promoted to its own binding). Much like how you can also write something likelet x = &mut String::new();
and use that x then.Regardless though, it seems like a safety hazard and a lint for this seems nice.
For example:
This prints "after declaration of x!", "drop!" in that order, implying that it is in fact not dropped immediately and has its lifetime extended
sdroege commentedon Jun 15, 2023
That's interesting. The case I had that prompted me to create this issue was something like
&((*ptr).x as *const _) as *const _
(the part inside the parenthesis becomes a temporary on the stack), but that then was converted into a reference and actually returned from the function (the lifetime ofptr
and the returned reference are bound correctly, but the returned reference is actually pointing to the temporary!). And that then did anything from crashes to asan/valgrind warnings. (The code in question should've been&(*ptr).x as *const _
)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.
Centri3 commentedon Jun 15, 2023
Yeah, looks like that in particular (
let x = &(temporary) as *const _
) is fine. Though something likeis UB.
playground link