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

Implement basic lint detecting manual slice copy #1937

Closed

Conversation

marcusklaas
Copy link
Contributor

This lint detects manual sequential memory copies between slices.

Should address #1831.

Copy link
Contributor

@oli-obk oli-obk left a comment

Choose a reason for hiding this comment

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

This is an absolutely awesome lint. Could you also add some nearly slice copies to the tests that should not be linted about? Just to make sure we don't have any false positives or introduce any in the future.

/// **Why is this bad?** It is not as fast as a memcpy.
///
/// **Known problems:** The lint assumes the data structure being indexed is
/// slice-like and will produce false positives when it is not.
Copy link
Contributor

Choose a reason for hiding this comment

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

What properties of slice are required? Can we simply check whether one of the following is true

  1. The type impls Deref<Target=[T]>
  2. The type impls Index<usize> and has a len method

@@ -83,7 +103,8 @@ declare_lint! {
/// implements `IntoIterator`, so that possibly one value will be iterated,
/// leading to some hard to find bugs. No one will want to write such code
/// [except to win an Underhanded Rust
/// Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr).
/// Contest](https://www.reddit.
/// com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr).
Copy link
Contributor

Choose a reason for hiding this comment

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

I ran rustfmt on master, so you can just rebase over master in order to separate the rustfmt changes from your actual changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are you sure this affected the clippy_lints directory as well? In my experience, cargo fmt does not touch these by default..

Copy link
Contributor

Choose a reason for hiding this comment

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

We have a script which runs recursively

408 | / for i in 11..src.len() {
409 | | dst[i] = src[i - 10];
410 | | }
| |_____^ help: try replacing the loop by: `dst[11..].clone_from_slice(&src[(11 + -10)..(src.len() + -10)])`
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should not produce output like a + -b, can you try to detect this situation, as it seems to be rather common.

427 | | dst[i] = src[i - 5];
428 | | dst2[i + 500] = src[i]
429 | | }
| |_____^ help: try replacing the loop by: `dst[10..].clone_from_slice(&src[(10 + -5)..(256 + -5)])`
Copy link
Contributor

Choose a reason for hiding this comment

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

same as above.

@marcusklaas marcusklaas force-pushed the needless-range-loop-fix branch from 2b18964 to e9991c7 Compare August 9, 2017 20:20
@marcusklaas
Copy link
Contributor Author

Updated the PR!

@marcusklaas marcusklaas force-pushed the needless-range-loop-fix branch from d397075 to 3eec23b Compare August 9, 2017 22:57
let is_slice = match ty.sty {
ty::TyRef(_, ref subty) => is_slice_like(cx, subty.ty),
ty::TySlice(..) => true,
ty::TyArray(..) => true,
Copy link
Contributor

Choose a reason for hiding this comment

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

rewrite as

        ty::TySlice(..) | ty::TyArray(..) => true,

(this was caught by travis. You can check such things yourself by running cargo test dogfood)

// "try replacing the loop by",
// format!("{}.clone_from_slice(&{}[{}..{}])", dst, src_var.var_name,
// src_offset, src_limit),
// );
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove the commented out code.

})
.join("\n ");

if big_sugg.len() > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you create a test that shows this with multiple suggestions?

Copy link
Contributor

Choose a reason for hiding this comment

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

also, replace it with !big_sugg.is_empty()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is such a test already :-)

Copy link
Contributor

Choose a reason for hiding this comment

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

oh... why didn't a test change after your changes then?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It was in there from the start. The test output did change, though.

This should make it play more nicely with tools like rustfix.
@marcusklaas marcusklaas force-pushed the needless-range-loop-fix branch from 3eec23b to 748e8c6 Compare August 10, 2017 18:12
|
help: try replacing the loop by
|
426 | dst[10..].clone_from_slice(&src[(10 - 5)..(256 - 5)])
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the test I was referring to.

@marcusklaas
Copy link
Contributor Author

Thanks for the review @oli-obk!

After a more detailed inspection of the documentation on clone_from_slice, I think the current lint suggestions may cause panics. The destination slice must apparently be exactly as long as the source. Also, it may be preferable to use copy_from_slice when T: Copy, although in my experience clone_from_slice also compiles to a memcpy in release builds.

I'll update this PR shortly.

@oli-obk
Copy link
Contributor

oli-obk commented Aug 14, 2017

Are you sure this affected the clippy_lints directory as well? In my experience, cargo fmt does not touch these by default..

I screwed up even more (I forgot to push the changes!). Please rebase over master now. If you want I can do the rebase, just ping me. Sorry about the trouble.

@marcusklaas
Copy link
Contributor Author

Hey @oli-obk - I'm still getting many style conflicts :-(

What command are you using to do the reformat?

@oli-obk
Copy link
Contributor

oli-obk commented Aug 17, 2017

@marcusklaas you seem to have included my commits in your PR now. I'm not sure how that happened. Try rebasing over the master branch.

What command are you using to do the reformat?

cargo fmt, run in clippy_lints and in the root directory

@llogiq
Copy link
Contributor

llogiq commented Aug 17, 2017

Note that there may be differences between "stable" rustfmt and rustfmt-nightly.

@oli-obk
Copy link
Contributor

oli-obk commented Aug 21, 2017

Our current code base is formatted with stable rustfmt. We could move to rustfmt-nighty. It's not like anyone building clippy doesn't have a nightly lying around somewhere

@marcusklaas
Copy link
Contributor Author

This PR is a mess. #2021 is a clean new PR.

@marcusklaas marcusklaas closed this Sep 5, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants