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

Llint for casting between raw slice pointers with different element sizes #8445

Merged
merged 1 commit into from
Mar 6, 2022

Conversation

asquared31415
Copy link
Contributor

@asquared31415 asquared31415 commented Feb 18, 2022

This lint disallows using as to convert from a raw pointer to a slice (e.g. *const [i32], *mut [Foo]) to any other raw pointer to a slice if the element types have different sizes. When a raw slice pointer is cast, the data pointer and count metadata are preserved. This means that when the size of the inner slice's element type changes, the total number of bytes pointed to by the count changes. For example a *const [i32] with length 4 (four i32 elements) is cast as *const [u8] the resulting pointer points to four u8 elements at the same address, losing most of the data. When the size increases the resulting pointer will point to more data, and accessing that data will be UB.

On its own, producing the pointer isn't actually a problem, but because any use of the pointer as a slice will either produce surprising behavior or cause UB I believe this is a correctness lint. If the pointer is not intended to be used as a slice, the user should instead use any of a number of methods to produce just a data pointer including an as cast to a thin pointer (e.g. p as *const i32) or if the pointer is being created from a slice, the as_ptr method on slices. Detecting the intended use of the pointer is outside the scope of this lint, but I believe this lint will also lead users to realize that a slice pointer is only for slices.

There is an exception to this lint when either of the slice element types are zero sized (e.g *mut [()]). The total number of bytes pointed to by the slice with a zero sized element is zero. In that case preserving the length metadata is likely intended as a workaround to get the length metadata of a slice pointer though a zero sized slice.

The lint does not forbid casting pointers to slices with the same element size as the cast was likely intended to reinterpret the data in the slice as some equivalently sized data and the resulting pointer will behave as intended.


changelog: Added [`cast_slice_different_sizes`], a lint that disallows using as-casts to convert between raw pointers to slices when the elements have different sizes.

@rust-highfive
Copy link

r? @llogiq

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Feb 18, 2022
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.

This looks good, albeit a bit wordy. The help could be either more specific or removed wholesale, I don't think it's pulling it's weight.

clippy_lints/src/casts/cast_slice_different_sizes.rs Outdated Show resolved Hide resolved
@asquared31415 asquared31415 force-pushed the slice_ptr_cast branch 2 times, most recently from 40a9e7c to 387eff7 Compare February 24, 2022 15:45
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.

This looks good in general. Just a small style nit on the docs.

clippy_lints/src/casts/mod.rs Outdated Show resolved Hide resolved
/// ```
#[clippy::version = "1.60.0"]
pub CAST_SLICE_DIFFERENT_SIZES,
correctness,
Copy link
Contributor

@llogiq llogiq Feb 26, 2022

Choose a reason for hiding this comment

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

I wonder if there could be cases where the code is actually correct, even if surprising.

If that is the case, I worry that having a deny by default lint might lead to a downgrade to nursery. So in this case using the suspicious group might be a better choice.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The exceptions when one or both target slices have a zero sized inner type should cover what I believe are the only correct uses:

  • To get the length metadata of a slice pointer on stable Rust by going through a &[()] (because there's zero bytes operated on).
  • To come from a pointer like *const [()] that has the correct inner data and size metadata (would be really weird but probably not wrong)

I asked on the Rust community discord if anyone had any other ideas about possible correct uses of a cast like this and nobody had any ideas.

Any time that data is actually accessed behind the pointer it either can be done with a thin pointer or with a slice pointer with a correct length. While I suppose it's technically the dereference that could cause behavior, I don't think there's ever a way to correctly use a slice pointer with the incorrect length, so I believe that it should be deny by default.

@llogiq
Copy link
Contributor

llogiq commented Mar 4, 2022

Thank you!

@bors r+

@bors
Copy link
Contributor

bors commented Mar 4, 2022

📌 Commit cb88dd5 has been approved by llogiq

@bors
Copy link
Contributor

bors commented Mar 4, 2022

⌛ Testing commit cb88dd5 with merge 8ea6d97...

bors added a commit that referenced this pull request Mar 4, 2022
Llint for casting between raw slice pointers with different element sizes

This lint disallows using `as` to convert from a raw pointer to a slice (e.g. `*const [i32]`, `*mut [Foo]`) to any other raw pointer to a slice if the element types have different sizes.  When a raw slice pointer is cast, the data pointer and count metadata are preserved.  This means that when the size of the inner slice's element type changes, the total number of bytes pointed to by the count changes.  For example a `*const [i32]` with length 4 (four `i32` elements) is cast `as *const [u8]` the resulting pointer points to four `u8` elements at the same address, losing most of the data.  When the size *increases* the resulting pointer will point to *more* data, and accessing that data will be UB.

On its own, *producing* the pointer isn't actually a problem, but because any use of the pointer as a slice will either produce surprising behavior or cause UB I believe this is a correctness lint.  If the pointer is not intended to be used as a slice, the user should instead use any of a number of methods to produce just a data pointer including an `as` cast to a thin pointer (e.g. `p as *const i32`) or if the pointer is being created from a slice, the `as_ptr` method on slices.  Detecting the intended use of the pointer is outside the scope of this lint, but I believe this lint will also lead users to realize that a slice pointer is only for slices.

There is an exception to this lint when either of the slice element types are zero sized (e.g `*mut [()]`).  The total number of bytes pointed to by the slice with a zero sized element is zero.  In that case preserving the length metadata is likely intended as a workaround to get the length metadata of a slice pointer though a zero sized slice.

The lint does not forbid casting pointers to slices with the *same* element size as the cast was likely intended to reinterpret the data in the slice as some equivalently sized data and the resulting pointer will behave as intended.

---

changelog:
Added ``[`cast_slice_different_sizes`]``, a lint that disallows using `as`-casts to convert between raw pointers to slices when the elements have different sizes.
@bors
Copy link
Contributor

bors commented Mar 4, 2022

💔 Test failed - checks-action_test

@llogiq
Copy link
Contributor

llogiq commented Mar 4, 2022

@bors r+

@bors
Copy link
Contributor

bors commented Mar 4, 2022

📌 Commit f932c30 has been approved by llogiq

@bors
Copy link
Contributor

bors commented Mar 4, 2022

⌛ Testing commit f932c30 with merge bc8fee5...

bors added a commit that referenced this pull request Mar 4, 2022
Llint for casting between raw slice pointers with different element sizes

This lint disallows using `as` to convert from a raw pointer to a slice (e.g. `*const [i32]`, `*mut [Foo]`) to any other raw pointer to a slice if the element types have different sizes.  When a raw slice pointer is cast, the data pointer and count metadata are preserved.  This means that when the size of the inner slice's element type changes, the total number of bytes pointed to by the count changes.  For example a `*const [i32]` with length 4 (four `i32` elements) is cast `as *const [u8]` the resulting pointer points to four `u8` elements at the same address, losing most of the data.  When the size *increases* the resulting pointer will point to *more* data, and accessing that data will be UB.

On its own, *producing* the pointer isn't actually a problem, but because any use of the pointer as a slice will either produce surprising behavior or cause UB I believe this is a correctness lint.  If the pointer is not intended to be used as a slice, the user should instead use any of a number of methods to produce just a data pointer including an `as` cast to a thin pointer (e.g. `p as *const i32`) or if the pointer is being created from a slice, the `as_ptr` method on slices.  Detecting the intended use of the pointer is outside the scope of this lint, but I believe this lint will also lead users to realize that a slice pointer is only for slices.

There is an exception to this lint when either of the slice element types are zero sized (e.g `*mut [()]`).  The total number of bytes pointed to by the slice with a zero sized element is zero.  In that case preserving the length metadata is likely intended as a workaround to get the length metadata of a slice pointer though a zero sized slice.

The lint does not forbid casting pointers to slices with the *same* element size as the cast was likely intended to reinterpret the data in the slice as some equivalently sized data and the resulting pointer will behave as intended.

---

changelog:
Added ``[`cast_slice_different_sizes`]``, a lint that disallows using `as`-casts to convert between raw pointers to slices when the elements have different sizes.
@bors
Copy link
Contributor

bors commented Mar 4, 2022

💔 Test failed - checks-action_test

@asquared31415
Copy link
Contributor Author

Edited the PR description, I think it didn't like the newline right after the changelog:

@xFrednet
Copy link
Member

xFrednet commented Mar 4, 2022

Sounds correct, thanks for the change 🙃

@bors retry

@bors
Copy link
Contributor

bors commented Mar 4, 2022

⌛ Testing commit f932c30 with merge 147bbe2...

bors added a commit that referenced this pull request Mar 4, 2022
Llint for casting between raw slice pointers with different element sizes

This lint disallows using `as` to convert from a raw pointer to a slice (e.g. `*const [i32]`, `*mut [Foo]`) to any other raw pointer to a slice if the element types have different sizes.  When a raw slice pointer is cast, the data pointer and count metadata are preserved.  This means that when the size of the inner slice's element type changes, the total number of bytes pointed to by the count changes.  For example a `*const [i32]` with length 4 (four `i32` elements) is cast `as *const [u8]` the resulting pointer points to four `u8` elements at the same address, losing most of the data.  When the size *increases* the resulting pointer will point to *more* data, and accessing that data will be UB.

On its own, *producing* the pointer isn't actually a problem, but because any use of the pointer as a slice will either produce surprising behavior or cause UB I believe this is a correctness lint.  If the pointer is not intended to be used as a slice, the user should instead use any of a number of methods to produce just a data pointer including an `as` cast to a thin pointer (e.g. `p as *const i32`) or if the pointer is being created from a slice, the `as_ptr` method on slices.  Detecting the intended use of the pointer is outside the scope of this lint, but I believe this lint will also lead users to realize that a slice pointer is only for slices.

There is an exception to this lint when either of the slice element types are zero sized (e.g `*mut [()]`).  The total number of bytes pointed to by the slice with a zero sized element is zero.  In that case preserving the length metadata is likely intended as a workaround to get the length metadata of a slice pointer though a zero sized slice.

The lint does not forbid casting pointers to slices with the *same* element size as the cast was likely intended to reinterpret the data in the slice as some equivalently sized data and the resulting pointer will behave as intended.

---

changelog: Added ``[`cast_slice_different_sizes`]``, a lint that disallows using `as`-casts to convert between raw pointers to slices when the elements have different sizes.
@bors
Copy link
Contributor

bors commented Mar 4, 2022

💔 Test failed - checks-action_test

@xFrednet
Copy link
Member

xFrednet commented Mar 4, 2022

Downloading artifact 'target' to: '/home/runner/work/rust-clippy/rust-clippy/target'
Error: The HTTP request timed out after 00:01:40.
Error: Exit code 1 returned from process: file name '/home/runner/runners/2.288.1/bin/Runner.PluginHost', arguments 'action "GitHub.Runner.Plugins.Artifact.DownloadArtifact, Runner.Plugins"'.

The CI seams to be acting up. Here is one more try ^^

@bors retry

@bors
Copy link
Contributor

bors commented Mar 4, 2022

⌛ Testing commit f932c30 with merge f508ddb...

bors added a commit that referenced this pull request Mar 4, 2022
Llint for casting between raw slice pointers with different element sizes

This lint disallows using `as` to convert from a raw pointer to a slice (e.g. `*const [i32]`, `*mut [Foo]`) to any other raw pointer to a slice if the element types have different sizes.  When a raw slice pointer is cast, the data pointer and count metadata are preserved.  This means that when the size of the inner slice's element type changes, the total number of bytes pointed to by the count changes.  For example a `*const [i32]` with length 4 (four `i32` elements) is cast `as *const [u8]` the resulting pointer points to four `u8` elements at the same address, losing most of the data.  When the size *increases* the resulting pointer will point to *more* data, and accessing that data will be UB.

On its own, *producing* the pointer isn't actually a problem, but because any use of the pointer as a slice will either produce surprising behavior or cause UB I believe this is a correctness lint.  If the pointer is not intended to be used as a slice, the user should instead use any of a number of methods to produce just a data pointer including an `as` cast to a thin pointer (e.g. `p as *const i32`) or if the pointer is being created from a slice, the `as_ptr` method on slices.  Detecting the intended use of the pointer is outside the scope of this lint, but I believe this lint will also lead users to realize that a slice pointer is only for slices.

There is an exception to this lint when either of the slice element types are zero sized (e.g `*mut [()]`).  The total number of bytes pointed to by the slice with a zero sized element is zero.  In that case preserving the length metadata is likely intended as a workaround to get the length metadata of a slice pointer though a zero sized slice.

The lint does not forbid casting pointers to slices with the *same* element size as the cast was likely intended to reinterpret the data in the slice as some equivalently sized data and the resulting pointer will behave as intended.

---

changelog: Added ``[`cast_slice_different_sizes`]``, a lint that disallows using `as`-casts to convert between raw pointers to slices when the elements have different sizes.
@bors
Copy link
Contributor

bors commented Mar 4, 2022

💔 Test failed - checks-action_test

@llogiq
Copy link
Contributor

llogiq commented Mar 6, 2022

@bors retry

more CI flakyness...

@bors
Copy link
Contributor

bors commented Mar 6, 2022

⌛ Testing commit f932c30 with merge 0c483f6...

@bors
Copy link
Contributor

bors commented Mar 6, 2022

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

@bors bors merged commit 0c483f6 into rust-lang:master Mar 6, 2022
bors added a commit that referenced this pull request Apr 30, 2022
…ednet

fix ICE in `cast_slice_different_sizes`

fixes #8708

changelog: fixes an ICE introduced in #8445
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.

5 participants