rust-lang / rust-lang/rust-clippy

Better "escaping raw pointer" lint

Open
#2,045 2 comments 7 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

E-hard L-correctness T-MIR
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

This is supposed to catch cases such as https://github.com/rust-lang/rust/issues/44473.

Raw pointers + destructors interact in an annoying way, where an unaware user can easily create a raw pointer to a value that is invisibly destroyed:

let  pixel_ptr : *const u8 = match pixels {
    image::DecodingResult::U8(v) => v.as_ptr(),
    image::DecodingResult::U16(v) => v.as_ptr() as *const u8,
};

We currently have a lint for CString, but it specifically looks for CString::new(...).unwrap().as_ptr() and can't handle more complicated patterns as the above.

A better version that would also catch this example would be:

When we see a call to an as_ptr-like function on an autoref of a local or temporary, find

  1. the scope of that local or temporary.
  2. the scope the returned value escapes to. I think that heuristically we should just go through "value-preserving" expressions such as match, if and let for that.

And if (2) is larger than (1), the code is definitely guilty of use-after-free (thats it, if it uses the returned raw pointer) and we can lint against it.

This does not try to handle "borrow" conflicts (where the raw pointer is invalidated without going out of scope), and also does not try to track the raw pointer very far:

fn foo() -> *const () {
    let x = vec![];
    let p = x.as_ptr();
    p // We don't try to lint against this for now (but we *could* try to play
       // with it - that analysis could be as complicated as we want it
       // to be, but I suspect it's the "small-scope" cases that are the most confusing).
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the existing CString::new(...).unwrap().as_ptr() lint and study how it is tested. Use the provided match example to define the desired coverage: detect raw pointers escaping the local or temporary's scope, while leaving borrow conflicts and longer pointer tracking out of scope.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.