Skip to content
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

Open
wants to merge 30 commits into
base: master
Choose a base branch
from

Conversation

GrigorenkoPV
Copy link
Contributor

@GrigorenkoPV GrigorenkoPV commented Aug 11, 2024

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 positive1 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:

Known limitations:

False negatives2:

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

Footnotes

  1. lint should not be emitted, but is

  2. lint should be emitted, but is not

@rustbot
Copy link
Collaborator

rustbot commented Aug 11, 2024

r? @wesleywiser

rustbot has assigned @wesleywiser.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. labels Aug 11, 2024
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@jieyouxu
Copy link
Member

FYI this probably needs T-lang approval and a crater run

@traviscross traviscross added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Aug 12, 2024
@GrigorenkoPV GrigorenkoPV marked this pull request as ready for review August 12, 2024 19:36
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@GrigorenkoPV
Copy link
Contributor Author

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 bors try, nor for a crater run.

compiler/rustc_lint/src/dangling.rs Outdated Show resolved Hide resolved
compiler/rustc_lint/src/dangling.rs Outdated Show resolved Hide resolved
compiler/rustc_lint/src/dangling.rs Outdated Show resolved Hide resolved

const MAX_PATH: usize = 260;
fn main() {
let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
Copy link
Member

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();

Copy link
Contributor Author

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

Copy link
Contributor Author

@GrigorenkoPV GrigorenkoPV Sep 9, 2024

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.

@rust-log-analyzer

This comment has been minimized.

@rustbot
Copy link
Collaborator

rustbot commented Aug 20, 2024

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

@rust-log-analyzer

This comment has been minimized.

@GrigorenkoPV
Copy link
Contributor Author

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.

@GrigorenkoPV
Copy link
Contributor Author

Rebased

@rustbot
Copy link
Collaborator

rustbot commented Aug 21, 2024

The Miri subtree was changed

cc @rust-lang/miri

@RalfJung
Copy link
Member

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.

It did. That's a good demo for the lint being quite useful indeed. :)

@rust-log-analyzer

This comment has been minimized.

1. Fix `is_temporary_rvalue` for:
   - Unary operations (such as dereference)
   - `yield`
   - Literals, array literals, repeat array literals
   - `DropTemps`
2. Fix typecheck to account for `T` in `Box<T>`
Turns out you cannot format Ty's you won't emit in unsuppressed diagnostics
The solution is hacky and itroduces more false negatives.

Also added some docs and tests.
Sometimes we need to BOTH pop a `LifetimeExtension::Enable`
AND change the now-top-of-the-stack `EnableLater` to `Enable`
during the same `check_expr_post`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. I-lang-nominated Nominated for discussion during a lang team meeting. S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Lint against instantly-dangling pointers like String::with_capacity(MAX_PATH).as_mut_ptr()