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 &T to &mut T and &T to &UnsafeCell<T> transmutes #118446

Conversation

ChayimFriedman2
Copy link
Contributor

@ChayimFriedman2 ChayimFriedman2 commented Nov 29, 2023

This adds the lint against &T->&UnsafeCell<T> transmutes, and also check in struct fields.

The code is quite complex; I've tried my best to simplify and comment it.

This is missing one parts: array transmutes. When transmuting an array, this only consider the first element. The reason for that is that the code is already quite complex, and I didn't want to complicate it more. This catches the most common pattern of transmuting an array into an array of the same length with type of the same size; more complex cases are likely not properly handled. We could take a bigger sample, for example the first and last elements to increase the chance that the lint will catch mistakes, but then the runtime complexity becomes exponential with the nesting of the arrays ([[[[[T; 2]; 2]; 2]; 2]; 2] has complexity of O(2**5), for instance).

Fixes #111229.

I've made this a deny-by-default and the wording says it's immediate UB, but from what I understand, under Tree Borrows this is not UB? CC rust-lang/unsafe-code-guidelines#303. So maybe we should make this warn-by-default and make the wording less strong. But #111229 says it causes miscompilations... So I'm not sure what is really the situation.

This also doesn't handle other ways of doing the transmute, such as via pointer casts. A fix for that should be quite simple, but I left it out for future PR.

This adds the lint against `&T`->`&UnsafeCell<T>` transmutes, and also check in struct fields.

The code is quite complex; I've tried my best to simplify and comment it.

This is missing one parts: array transmutes. When transmuting an array, this only consider the first element. The reason for that is that the code is already quite complex, and I didn't want to complicate it more.
This catches the most common pattern of transmuting an array into an array of the same length with type of the same size; more complex cases are likely not properly handled.
We could take a bigger sample, for example the first and last elements to increase the chance that the lint will catch mistakes, but then the runtime complexity becomes exponential with the nesting of the arrays (`[[[[[T; 2]; 2]; 2]; 2]; 2]` has complexity of O(2**5), for instance).
@rustbot
Copy link
Collaborator

rustbot commented Nov 29, 2023

r? @cjgillot

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

@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. labels Nov 29, 2023
@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-tools failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
GITHUB_ACTION=__run_7
GITHUB_ACTIONS=true
GITHUB_ACTION_REF=
GITHUB_ACTION_REPOSITORY=
GITHUB_ACTOR=ChayimFriedman2
GITHUB_API_URL=https://api.github.com
GITHUB_BASE_REF=master
GITHUB_ENV=/home/runner/work/_temp/_runner_file_commands/set_env_08680374-fb7f-4ae3-9e47-6cadf7b2b942
GITHUB_EVENT_NAME=pull_request
---
GITHUB_SERVER_URL=https://github.com
GITHUB_SHA=4b924d61db7951d081d729b64c63d81ea5025db0
GITHUB_STATE=/home/runner/work/_temp/_runner_file_commands/save_state_08680374-fb7f-4ae3-9e47-6cadf7b2b942
GITHUB_STEP_SUMMARY=/home/runner/work/_temp/_runner_file_commands/step_summary_08680374-fb7f-4ae3-9e47-6cadf7b2b942
GITHUB_TRIGGERING_ACTOR=ChayimFriedman2
GITHUB_WORKFLOW_REF=rust-lang/rust/.github/workflows/ci.yml@refs/pull/118446/merge
GITHUB_WORKFLOW_SHA=4b924d61db7951d081d729b64c63d81ea5025db0
GITHUB_WORKSPACE=/home/runner/work/rust/rust
GOROOT_1_19_X64=/opt/hostedtoolcache/go/1.19.13/x64
---
## Running ui tests in tests/pass against miri for x86_64-unknown-linux-gnu
   Compiler: "MIRI_ENV_VAR_TEST"="0" "MIRI_TEMP"="/tmp" /checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/miri "--error-format=json" "-Dwarnings" "-Dunused" "-Ainternal_features" "-Zui-testing" "--target" "x86_64-unknown-linux-gnu" "--out-dir" OUT_DIR

FAILED TEST: tests/pass/tree_borrows/transmute-unsafecell.rs
command: MIRI_ENV_VAR_TEST="0" MIRI_TEMP="/tmp" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/miri" "--error-format=json" "-Dwarnings" "-Dunused" "-Ainternal_features" "-Zui-testing" "--target" "x86_64-unknown-linux-gnu" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools/ui/tests/pass/tree_borrows" "tests/pass/tree_borrows/transmute-unsafecell.rs" "-Zmiri-tree-borrows" "--edition" "2021"
   0: tests failed


Backtrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it.
Run with RUST_BACKTRACE=full to include source snippets.
error: pass test got exit status: 1, but expected 0

error: actual output differed from expected
Execute `./miri test --bless` to update `tests/pass/tree_borrows/transmute-unsafecell.stderr` to the actual output
Execute `./miri test --bless` to update `tests/pass/tree_borrows/transmute-unsafecell.stderr` to the actual output
--- tests/pass/tree_borrows/transmute-unsafecell.stderr
+++ <stderr output>
+error: transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
+   |
+   |
+LL |     let cell_x: &UnsafeCell<i32> = mem::transmute(x);
+   |
+   |
+   = note: transmute from `*&i32` to `*&std::cell::UnsafeCell<i32>`
+
+
+error: miri cannot be run on programs that fail compilation
+error: aborting due to 2 previous errors
+



error: there were 1 unmatched diagnostics that occurred outside the testfile and had no pattern
error: test failed, to rerun pass `--test compiletest`

Caused by:
  process didn't exit successfully: `/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools/x86_64-unknown-linux-gnu/release/deps/compiletest-fbfb30b2bd27303a --quiet` (exit status: 1)
    Error: miri cannot be run on programs that fail compilation
error: there were 1 unmatched diagnostics
##[error]  --> tests/pass/tree_borrows/transmute-unsafecell.rs:21:36
   |
   |
21 |     let cell_x: &UnsafeCell<i32> = mem::transmute(x);
   |                                    ^^^^^^^^^^^^^^ Error: transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data

full stderr:
full stderr:
error: transmuting &T to &UnsafeCell<T> is undefined behavior, even if the reference is unused, consider using UnsafeCell on the original data
   |
   |
LL |     let cell_x: &UnsafeCell<i32> = mem::transmute(x);
   |
   |
   = note: transmute from `*&i32` to `*&std::cell::UnsafeCell<i32>`


error: miri cannot be run on programs that fail compilation
error: aborting due to 2 previous errors


full stdout:

@ChayimFriedman2
Copy link
Contributor Author

ChayimFriedman2 commented Nov 29, 2023

The CI failure is exactly the Tree Borrows problem I was talking about... Apparently it is checked in a test. What am I supposed to do? Downgrade it to warn by default? Allow the lint in the test?

@Noratrieb
Copy link
Member

I see significant overlap with the invalid_reference_casting lint.

@ChayimFriedman2
Copy link
Contributor Author

@Nilstrieb Indeed; that is why I said

This also doesn't handle other ways of doing the transmute, such as via pointer casts. A fix for that should be quite simple, but I left it out for future PR.

Do you prefer to fix this on this PR?

@Noratrieb
Copy link
Member

I think it would be nice if this logic could be shared between mutable_transmutes and invalid_reference_casting so they both have this detection.

@ChayimFriedman2
Copy link
Contributor Author

@Nilstrieb It turns out there isn't much to share: Only one function is similar enough, and even it is different enough to make sharing not worth it. I'm already on it, though, so I'll push this addition to this PR soon.

Comment on lines +142 to +144
let mut breadcrumbs = self.0.as_slice();
while let &[current_breadcrumb, ref rest_breadcrumbs @ ..] = breadcrumbs {
breadcrumbs = rest_breadcrumbs;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
let mut breadcrumbs = self.0.as_slice();
while let &[current_breadcrumb, ref rest_breadcrumbs @ ..] = breadcrumbs {
breadcrumbs = rest_breadcrumbs;
for &current_breadcrumb in &self.0 {

?

while let &[current_breadcrumb, ref rest_breadcrumbs @ ..] = breadcrumbs {
breadcrumbs = rest_breadcrumbs;

match ty.kind() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
match ty.kind() {
ty = match ty.kind() {

to make the code flow a bit clearer

Comment on lines +199 to +200
CheckFields,
DoNotCheckFields,
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes/No should be enough.

Comment on lines +270 to +271
CheckFields,
DoNotCheckFields,
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes/No should be enough here too.

@bors
Copy link
Contributor

bors commented Jan 22, 2024

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

@cjgillot cjgillot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 27, 2024
@Dylan-DPC
Copy link
Member

@ChayimFriedman2 any updates on the changes requested above? thanks

@Dylan-DPC
Copy link
Member

Closing this as inactive. Feel free to reöpen this pr or create a new pr if you get the time to work on this. Thanks

@Dylan-DPC Dylan-DPC closed this Apr 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

mutable_transmutes lint should catch transmutes from a type without interior mutability to one with
7 participants