-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Lint against getting pointers from immediately dropped temporaries #128985
Lint against getting pointers from immediately dropped temporaries #128985
Conversation
r? @wesleywiser rustbot has assigned @wesleywiser. Use |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
FYI this probably needs T-lang approval and a crater run |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
ddf0d12
to
34c4b17
Compare
This comment has been minimized.
This comment has been minimized.
34c4b17
to
f403c05
Compare
This probably needs a crater run. Check-only should suffice. However, the lint should probably be denied for the run, but I am not sure if crater has such an option. Maybe I will just temporary change the default level in code. Anyways, neither do I have permissions for |
tests/ui/lint/dangling-ptr/instantly-dangling-pointer-issue123613.rs
Outdated
Show resolved
Hide resolved
|
||
const MAX_PATH: usize = 260; | ||
fn main() { | ||
let str1 = String::with_capacity(MAX_PATH).as_mut_ptr(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it would make sense to suggest introducing a second binding in those simple let
cases, aka.
let str1 = String::with_capacity(MAX_PATH);
let str1 = str1.as_mut_ptr();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably yes, but I would prefer to do this as a separate follow-up PR if possible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it would make sense to suggest introducing a second binding in those simple
let
cases, aka.let str1 = String::with_capacity(MAX_PATH); let str1 = str1.as_mut_ptr();
After looking at the "regressed" code from crater, I can say that a lot of the time this suggestion will not fix the problem, and will just result in code like
let vec = some_iter.collect();
let ptr = vec.as_ptr();
return ptr;
or similar where the pointer still dangles eventually, even though we binded the temporary for now.
Sometimes it would make sense to suggest things like .into_raw_parts()
instead of .as_ptr()
, but then the user has to remember to do ::from_raw_parts()
if they want to avoid leaking...
Most of the places where this lint fires are not trivial to fix and actually require the person writing the code to be more cautious & knowledgeable about what they are doing, which can only be achieved through more experience of writing unsafe
, as well as some punches from the compiler, miri, or sanitizers.
I think that not providing this suggestion in places where it would help is less bad than improperly providing it in places where it wouldn't help but would just further obscure and hide the issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still feel like we should point users towards doing something, even if it's not a general solution, and not a a structured suggestion.
It's really a shame to tell users something but not how to fix it.
Opened #132283 to track this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's really a shame to tell users something but not how to fix it.
It's even worse to suggest something that is no a fix. So if you are sure you have a correct suggestion, then sure, please make it -- but never do this unless you are sure. People will trust the suggestion and then be worse off than before.
EDIT: Sorry, I should have posted in the issue. Here we go.
This comment has been minimized.
This comment has been minimized.
Some changes occurred in src/tools/clippy cc @rust-lang/clippy |
This comment has been minimized.
This comment has been minimized.
Looks like this caught an actual mistake in miri tests. However, the test in question was added after this PR had been opened, so I will have to rebase now to be able to fix the test. |
8139b97
to
cb3d924
Compare
Rebased |
The Miri subtree was changed cc @rust-lang/miri |
It did. That's a good demo for the lint being quite useful indeed. :) |
This comment has been minimized.
This comment has been minimized.
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. This will be merged soon. |
|
||
fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { | ||
if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind | ||
&& matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want to do it in this PR (otherwise in a follow-up), we could add an rustc
attribute to those as_ptr
/as_mut_ptr
methods.
You can follow afcb09b and 2a930d3 (from a PR of mine) with check_applied_to_fn_or_method
instead, and something similar to this to check the attribute
rust/compiler/rustc_lint/src/ptr_nulls.rs
Lines 49 to 50 in e454c45
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) | |
&& cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to do this as a follow-up, just not to stall this one any longer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've created #132281 to track the use of a rustc
attr for this lint.
Feel free to assign it to your-self (@rustbot assign
I think).
78a0c89
to
c69894e
Compare
.label_ptr = this pointer will immediately be invalid | ||
.label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | ||
.note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned | ||
.help = for more information, see <https://doc.rust-lang.org/reference/destructors.html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's too bad that we don't have place explaining what a "dangling pointer" is, we could have linked it here.
Opened #132286 about that.
☀️ Test successful - checks-actions |
Finished benchmarking commit (a9d1762): comparison URL. Overall result: ❌ regressions - no action needed@rustbot label: -perf-regression Instruction countThis is the most reliable metric that we have; it was used to determine the overall result at the top of this comment. However, even this metric can sometimes exhibit noise.
Max RSS (memory usage)Results (primary 2.1%, secondary 4.0%)This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResults (secondary -3.0%)This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 782.325s -> 783.339s (0.13%) |
Lint against getting pointers from immediately dropped temporaries Fixes #123613 ## Changes: 1. New lint: `dangling_pointers_from_temporaries`. Is a generalization of `temporary_cstring_as_ptr` for more types and more ways to get a temporary. 2. `temporary_cstring_as_ptr` is removed and marked as renamed to `dangling_pointers_from_temporaries`. 3. `clippy::temporary_cstring_as_ptr` is marked as renamed to `dangling_pointers_from_temporaries`. 4. Fixed a false positive[^fp] for when the pointer is not actually dangling because of lifetime extension for function/method call arguments. 5. `core::cell::Cell` is now `rustc_diagnostic_item = "Cell"` ## Questions: - [ ] Instead of manually checking for a list of known methods and diagnostic items, maybe add some sort of annotation to those methods in library and check for the presence of that annotation? rust-lang/rust#128985 (comment) ## Known limitations: ### False negatives[^fn]: See the comments in `compiler/rustc_lint/src/dangling.rs` 1. Method calls that are not checked for: - `temporary_unsafe_cell.get()` - `temporary_sync_unsafe_cell.get()` 2. Ways to get a temporary that are not recognized: - `owning_temporary.field` - `owning_temporary[index]` 3. No checks for ref-to-ptr conversions: - `&raw [mut] temporary` - `&temporary as *(const|mut) _` - `ptr::from_ref(&temporary)` and friends [^fn]: lint **should** be emitted, but **is not** [^fp]: lint **should not** be emitted, but **is**
Lint against getting pointers from immediately dropped temporaries Fixes #123613 ## Changes: 1. New lint: `dangling_pointers_from_temporaries`. Is a generalization of `temporary_cstring_as_ptr` for more types and more ways to get a temporary. 2. `temporary_cstring_as_ptr` is removed and marked as renamed to `dangling_pointers_from_temporaries`. 3. `clippy::temporary_cstring_as_ptr` is marked as renamed to `dangling_pointers_from_temporaries`. 4. Fixed a false positive[^fp] for when the pointer is not actually dangling because of lifetime extension for function/method call arguments. 5. `core::cell::Cell` is now `rustc_diagnostic_item = "Cell"` ## Questions: - [ ] Instead of manually checking for a list of known methods and diagnostic items, maybe add some sort of annotation to those methods in library and check for the presence of that annotation? rust-lang/rust#128985 (comment) ## Known limitations: ### False negatives[^fn]: See the comments in `compiler/rustc_lint/src/dangling.rs` 1. Method calls that are not checked for: - `temporary_unsafe_cell.get()` - `temporary_sync_unsafe_cell.get()` 2. Ways to get a temporary that are not recognized: - `owning_temporary.field` - `owning_temporary[index]` 3. No checks for ref-to-ptr conversions: - `&raw [mut] temporary` - `&temporary as *(const|mut) _` - `ptr::from_ref(&temporary)` and friends [^fn]: lint **should** be emitted, but **is not** [^fp]: lint **should not** be emitted, but **is**
Lint against getting pointers from immediately dropped temporaries Fixes #123613 ## Changes: 1. New lint: `dangling_pointers_from_temporaries`. Is a generalization of `temporary_cstring_as_ptr` for more types and more ways to get a temporary. 2. `temporary_cstring_as_ptr` is removed and marked as renamed to `dangling_pointers_from_temporaries`. 3. `clippy::temporary_cstring_as_ptr` is marked as renamed to `dangling_pointers_from_temporaries`. 4. Fixed a false positive[^fp] for when the pointer is not actually dangling because of lifetime extension for function/method call arguments. 5. `core::cell::Cell` is now `rustc_diagnostic_item = "Cell"` ## Questions: - [ ] Instead of manually checking for a list of known methods and diagnostic items, maybe add some sort of annotation to those methods in library and check for the presence of that annotation? rust-lang/rust#128985 (comment) ## Known limitations: ### False negatives[^fn]: See the comments in `compiler/rustc_lint/src/dangling.rs` 1. Method calls that are not checked for: - `temporary_unsafe_cell.get()` - `temporary_sync_unsafe_cell.get()` 2. Ways to get a temporary that are not recognized: - `owning_temporary.field` - `owning_temporary[index]` 3. No checks for ref-to-ptr conversions: - `&raw [mut] temporary` - `&temporary as *(const|mut) _` - `ptr::from_ref(&temporary)` and friends [^fn]: lint **should** be emitted, but **is not** [^fp]: lint **should not** be emitted, but **is**
Fixes #123613
Changes:
dangling_pointers_from_temporaries
. Is a generalization oftemporary_cstring_as_ptr
for more types and more ways to get a temporary.temporary_cstring_as_ptr
is removed and marked as renamed todangling_pointers_from_temporaries
.clippy::temporary_cstring_as_ptr
is marked as renamed todangling_pointers_from_temporaries
.core::cell::Cell
is nowrustc_diagnostic_item = "Cell"
Questions:
Known limitations:
False negatives2:
See the comments in
compiler/rustc_lint/src/dangling.rs
temporary_unsafe_cell.get()
temporary_sync_unsafe_cell.get()
owning_temporary.field
owning_temporary[index]
&raw [mut] temporary
&temporary as *(const|mut) _
ptr::from_ref(&temporary)
and friendsFootnotes
lint should not be emitted, but is ↩
lint should be emitted, but is not ↩