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

Flag bufreader.lines().filter_map(Result::ok) as suspicious #10534

Merged
merged 1 commit into from
Apr 1, 2023

Conversation

samueltardieu
Copy link
Contributor

This lint detects a problem that happened recently in https://github.com/uutils/coreutils and is described in rust-lang/rust#64144.

changelog: [lines_filter_map_ok]: new lint

@rustbot
Copy link
Collaborator

rustbot commented Mar 23, 2023

r? @flip1995

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Mar 23, 2023
@samueltardieu samueltardieu force-pushed the lines-filter-map-ok branch 2 times, most recently from eb59e32 to 1f4c5a2 Compare March 23, 2023 01:04
@tertsdiepraam
Copy link

tertsdiepraam commented Mar 23, 2023

Wow this is awesome! Thanks!

I'm new to clippy lints but if I understand correctly, this checks that there is a BufRead on which the lines() and filter_map(Result::ok) methods are called right?

There is a variation of this that I've seen with .filter_map(|l| l.ok()). That is not covered by this implementation, is it? It might not be super important as other lints might already suggest rewriting the closure into Result::ok, which will in turn trigger this lint.

The same pattern also happens with Stdin, which has a separate lines method and does not implement BufRead. It does however return the same Lines struct. I'm not sure it's really an issue with Stdin though as I haven't gotten it to get into an infinite loop yet, but I think it's possible.

@samueltardieu
Copy link
Contributor Author

I'm new to clippy lints but if I understand correctly, this checks that there is a BufRead on which the lines() and filter_map(Result::ok) methods are called right?

Yes.

There is a variation of this that I've seen with .filter_map(|l| l.ok()). That is not covered by this implementation, is it? It might not be super important as other lints might already suggest rewriting the closure into Result::ok, which will in turn trigger this lint.

I'll have a look, as there is a lint for possible η-reduction but it is activated only in pedantic mode.

The same pattern also happens with Stdin, which has a separate lines method and does not implement BufRead. It does however return the same Lines struct. I'm not sure it's really an issue with Stdin though as I haven't gotten it to get into an infinite loop yet, but I think it's possible.

Indeed. stdin().lock().lines() is covered, as the lines() method comes from BufRead, but stdin.lines() is a special case which could be easily integrated by checking for the Lines type. I'll put this PR in draft mode until I implement it.

@samueltardieu samueltardieu marked this pull request as draft March 23, 2023 12:14
@bors
Copy link
Collaborator

bors commented Mar 24, 2023

☔ The latest upstream changes (presumably #10489) made this pull request unmergeable. Please resolve the merge conflicts.

@samueltardieu samueltardieu force-pushed the lines-filter-map-ok branch 2 times, most recently from 32ff41c to 1023cf0 Compare March 24, 2023 17:37
@samueltardieu samueltardieu marked this pull request as ready for review March 24, 2023 17:37
@samueltardieu
Copy link
Contributor Author

The proposed lint now triggers with anything returning std::io::Lines (including std::io::stdin().lines()), and detects |x| x.ok() in addition to Result::ok.

A lintcheck with the 500 top most downloaded recent crates shows no hit.

@samueltardieu samueltardieu force-pushed the lines-filter-map-ok branch 2 times, most recently from d04dab1 to 51b6693 Compare March 24, 2023 17:41
@bors
Copy link
Collaborator

bors commented Mar 30, 2023

☔ The latest upstream changes (presumably #9102) made this pull request unmergeable. Please resolve the merge conflicts.

@samueltardieu samueltardieu force-pushed the lines-filter-map-ok branch 3 times, most recently from a2e445a to b3bff31 Compare March 30, 2023 10:53
@samueltardieu
Copy link
Contributor Author

r? @llogiq

@rustbot rustbot assigned llogiq and unassigned flip1995 Mar 30, 2023
@llogiq
Copy link
Contributor

llogiq commented Mar 30, 2023

I wonder why we should lint stdin.lines(). The infinite loop problem only appears on reading directories, and I haven't yet been able to pipe one to stdin.

@samueltardieu
Copy link
Contributor Author

I wonder why we should lint stdin.lines(). The infinite loop problem only appears on reading directories, and I haven't yet been able to pipe one to stdin.

On Linux :

$ cat t.rs
fn main() {
    for l in std::io::stdin().lines() {
        println!("l = {l:?}");
    }
}
$ rustc t.rs
$ ./t < /
l = Err(Os { code: 21, kind: IsADirectory, message: "Is a directory" })
l = Err(Os { code: 21, kind: IsADirectory, message: "Is a directory" })
l = Err(Os { code: 21, kind: IsADirectory, message: "Is a directory" })
l = Err(Os { code: 21, kind: IsADirectory, message: "Is a directory" })
l = Err(Os { code: 21, kind: IsADirectory, message: "Is a directory" })
l = Err(Os { code: 21, kind: IsADirectory, message: "Is a directory" })
l = Err(Os { code: 21, kind: IsADirectory, message: "Is a directory" })
l = Err(Os { code: 21, kind: IsADirectory, message: "Is a directory" })
l = Err(Os { code: 21, kind: IsADirectory, message: "Is a directory" })
l = Err(Os { code: 21, kind: IsADirectory, message: "Is a directory" })
^C

@llogiq
Copy link
Contributor

llogiq commented Mar 30, 2023

Ok then. I think the docs could use some editing for wording, otherwise it looks ok.

@samueltardieu
Copy link
Contributor Author

Ok then. I think the docs could use some editing for wording, otherwise it looks ok.

I have reworked the wording, tell me if you'd change other things.

Copy link
Contributor

@llogiq llogiq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only possible problem is that the user could check for in.is_file() manually, in which case we'd have a false positive. That said, I'd be ok with just adding that to the "known problems" section, as the code to check for this case could be quite hairy

@samueltardieu
Copy link
Contributor Author

Note that even if in.is_file(), an I/O error while reading the file (e.g., a USB key removed while reading) will likely persist, in which case the implementation of Lines.next() will return an Err forever (I have also verified this experimentally by creating a small fuse FS returning a read error).

I've added a "Known problems" section to the lint.

I've used "suspicious" as a category. Is that ok, or do you prefer it to be put in the "nursery"?

@llogiq
Copy link
Contributor

llogiq commented Apr 1, 2023

I think suspicious is likely fine, as the lint highlights a real problem and I haven't encountered a case where ignoring an error on one line would have produced a good outcome.

@bors r+

@bors
Copy link
Collaborator

bors commented Apr 1, 2023

📌 Commit 6601d85 has been approved by llogiq

It is now in the queue for this repository.

@bors
Copy link
Collaborator

bors commented Apr 1, 2023

⌛ Testing commit 6601d85 with merge ac4838c...

@bors
Copy link
Collaborator

bors commented Apr 1, 2023

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: llogiq
Pushing ac4838c to master...

1 similar comment
@bors
Copy link
Collaborator

bors commented Apr 1, 2023

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: llogiq
Pushing ac4838c to master...

@bors bors merged commit ac4838c into rust-lang:master Apr 1, 2023
@samueltardieu samueltardieu deleted the lines-filter-map-ok branch May 10, 2023 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants