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

Do not consider match/let/ref of place that evaluates to ! to diverge, disallow coercions from them too #129392

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

compiler-errors
Copy link
Member

@compiler-errors compiler-errors commented Aug 22, 2024

Fixes #117288.

This PR implements a heuristic which disables two things that are currently being performed on the HIR when we have expressions that involve place-like expressions that point to !. Specifically, it will (in certain cases explained below):

(1.) Disable the NeverToAny coercion we implicitly insert for !.

Which fixes this inadvertent, sneaky unsoundness:

unsafe {
    let x: *const ! = &0 as *const u8 as *const !;
    let _: () = *x;
}

which is UB because currently rust emits an implicit NeverToAny coercion even though we really shouldn't be, since there's no read of the value pointed by x.

(2.) Disable the logic which considers expression which evaluate to ! to diverge, which affects the type returned by the containing block.

Which fixes this unsoundness:

fn make_up_a_value<T>() -> T {
    unsafe {
        let x: *const ! = &0 as *const u8 as *const !;
        let _ = *x;
    }
}

We disable these two operations if the expression is a place-like expression (locals, statics, field projections, index operations, and deref operations), and if the parent expression is either:
(1.) the LHS of an assignment
(2.) AddrOf
(3.) A match or let unless all of the patterns consitute a read, which is explained below:

And finally, a pattern currently is considered to constitute a read unless it is a wildcard, or an OR pattern. An OR pattern is considered to constitute a read if all of its subpatterns constitute a read, to remain as conservative as possible in cases like _ | subpat or subpat | _.

All other patterns are considered currently to constitute a read. Specifically, because NeverToAny is a coercion performed on a value and not a place, Struct { .. } on a ! type must be a coercion currently, and we currently rely on this behavior to allow us to perform coercions like let _: i32 = x; where x: !.

This is already considered UB by miri, but also means it does not affect the preexisting UB in this case:

let Struct { .. } = *never_ptr;

Even though it's likely up for debate since we're not actually reading any data out of the struct, it almost certainly causes inference changes which I do NOT want to fix in this PR.

@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 Aug 22, 2024
@compiler-errors
Copy link
Member Author

@bors try

bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 22, 2024
…verge-but-more, r=<try>

[EXPERIMENT] Do not consider match/let/raw-ref of deref that evalautes to ! to diverge

This is the more involved version of rust-lang#129371. It doesn't fully fix rust-lang#117288, since we still need to fix the fact that never type fallback can cause an unintended load via the `NeverToAny` coercion. But I did want to probe crater to see if anyone relies on this behavior currently, since that's almost certainly UB.

r? `@ghost`
@bors
Copy link
Contributor

bors commented Aug 22, 2024

⌛ Trying commit 5250e5d with merge 4096397...

@bors
Copy link
Contributor

bors commented Aug 22, 2024

☀️ Try build successful - checks-actions
Build commit: 4096397 (4096397122f3daf755d7a75d9716317f02ae7690)

@compiler-errors
Copy link
Member Author

@bors try

@bors
Copy link
Contributor

bors commented Aug 22, 2024

⌛ Trying commit 1ee0400 with merge 3254088...

bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 22, 2024
…verge-but-more, r=<try>

[EXPERIMENT] Do not consider match/let/raw-ref of deref that evalautes to ! to diverge

This is the more involved version of rust-lang#129371. It's pretty ugly rn.

r? `@ghost`
@compiler-errors
Copy link
Member Author

@bors try

bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 22, 2024
…verge-but-more, r=<try>

[EXPERIMENT] Do not consider match/let/raw-ref of deref that evalautes to ! to diverge

This is the more involved version of rust-lang#129371. It's pretty ugly rn.

r? `@ghost`
@bors
Copy link
Contributor

bors commented Aug 22, 2024

⌛ Trying commit 9bb136b with merge de0e806...

@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Aug 22, 2024

☀️ Try build successful - checks-actions
Build commit: de0e806 (de0e80659cee4f27282e60d63bbb8c5271a0d147)

@compiler-errors
Copy link
Member Author

@craterbot check

@craterbot
Copy link
Collaborator

👌 Experiment pr-129392 created and queued.
🤖 Automatically detected try build de0e806
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 22, 2024
bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 27, 2024
[CRATER] Crater Rollup

This is a " crater rollup" of:
* rust-lang#126452
* rust-lang#128784
* rust-lang#129392
* rust-lang#129422
* rust-lang#129543

**What is a crater rollup?** It's simply a crater job that is run on all of the containing PRs *together*, and then we can set the crates list for each of these jobs to just the failures after it's done. It should cut out on the bulk of "normal" crates that do nothing and simply just take time to build.

r? `@ghost`
bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 28, 2024
[CRATER] Crater Rollup

This is a " crater rollup" of:
* rust-lang#126452
* rust-lang#128784
* rust-lang#129392
* rust-lang#129422
* rust-lang#129543
* rust-lang#129604

**What is a crater rollup?** It's simply a crater job that is run on all of the containing PRs *together*, and then we can set the crates list for each of these jobs to just the failures after it's done. It should cut out on the bulk of "normal" crates that do nothing and simply just take time to build.

r? `@ghost`
bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 28, 2024
[CRATER] Crater Rollup

This is a " crater rollup" of:
* rust-lang#126452
* rust-lang#128784
* rust-lang#129392
* rust-lang#129422
* rust-lang#129543
* rust-lang#129604

**What is a crater rollup?** It's simply a crater job that is run on all of the containing PRs *together*, and then we can set the crates list for each of these jobs to just the failures after it's done. It should cut out on the bulk of "normal" crates that do nothing and simply just take time to build.

r? `@ghost`
@craterbot
Copy link
Collaborator

📝 Configuration of the pr-129392 experiment changed.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@traviscross
Copy link
Contributor

@craterbot p=1

(Bump priority is this will run quickly.)

@craterbot
Copy link
Collaborator

📝 Configuration of the pr-129392 experiment changed.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🚧 Experiment pr-129392 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🎉 Experiment pr-129392 is completed!
📊 0 regressed and 1 fixed (98236 total)
📰 Open the full report.

⚠️ If you notice any spurious failure please add them to the blacklist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

bors added a commit to rust-lang-ci/rust that referenced this pull request Sep 6, 2024
…verge-but-more, r=<try>

Do not consider match/let/ref of place that evaluates to `!` to diverge, disallow coercions from them too

Fixes rust-lang#117288.

This PR does two things:

### Don't consider `match`/`let`/`ref`/assignment-LHS of a place expression that evaluates to `!` to diverge.

Which fixes this unsoundness:

```
fn make_up_a_value<T>() -> T {
    unsafe {
        let x: *const ! = &0 as *const u8 as *const !;
        let _ = *x;
    }
}
```

Before this PR, it was UB since we consider the `unsafe` block to diverge which means the outer block evalutes to `!`, even though we've never actually *read* a value of type `!`.

### Do not perform coercions of those same place expressions.

Which fixes this inadvertent, sneaky unsoundness:

```
unsafe {
    let x: *const ! = &0 as *const u8 as *const !;
    let _: () = *x;
}
```

which is UB because currently rust emits an *implicit* NeverToAny coercion even though we really shouldn't be, since there's no read of the value pointed by `x`.

---

Detecting both of these situations is implemented in a heuristic function called `expr_consitutes_read`. It is tasked with detecting the situations where we have a place expression being passed to some parent expression that would not constitute a read necessarily, like a `let _ = *never_ptr` where `never_ptr: *const !`.

---

Specifically, for `let` and `match`, we don't consider it to be a read unless any of the subpatterns (i.e. the LHS of the `let` or the arms of the match) constitute a read. Almost all patterns constitute a read except for `_`, an `|` pattern, or the currently experimental `!` pattern.

---

I'm not totally certain that this deserves an FCP, since it's really a bugfix for UB. If it does, I'd be comfortable with it being a T-types FCP since we should be responsible with determining which coercions in the type system are sound (similar to how we adjusted subtyping behavior in rust-lang#118247 to be more sound).
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Sep 6, 2024

💔 Test failed - checks-actions

@bors bors 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 Sep 6, 2024
@compiler-errors compiler-errors force-pushed the raw-ref-op-doesnt-diverge-but-more branch from 26ae1b3 to a0179f5 Compare September 6, 2024 15:50
@compiler-errors
Copy link
Member Author

@bors try

@bors
Copy link
Contributor

bors commented Sep 6, 2024

⌛ Trying commit a0179f5 with merge 19c0326...

bors added a commit to rust-lang-ci/rust that referenced this pull request Sep 6, 2024
…verge-but-more, r=<try>

Do not consider match/let/ref of place that evaluates to `!` to diverge, disallow coercions from them too

Fixes rust-lang#117288.

This PR does two things:

### Don't consider `match`/`let`/`ref`/assignment-LHS of a place expression that evaluates to `!` to diverge.

Which fixes this unsoundness:

```
fn make_up_a_value<T>() -> T {
    unsafe {
        let x: *const ! = &0 as *const u8 as *const !;
        let _ = *x;
    }
}
```

Before this PR, it was UB since we consider the `unsafe` block to diverge which means the outer block evalutes to `!`, even though we've never actually *read* a value of type `!`.

### Do not perform coercions of those same place expressions.

Which fixes this inadvertent, sneaky unsoundness:

```
unsafe {
    let x: *const ! = &0 as *const u8 as *const !;
    let _: () = *x;
}
```

which is UB because currently rust emits an *implicit* NeverToAny coercion even though we really shouldn't be, since there's no read of the value pointed by `x`.

---

Detecting both of these situations is implemented in a heuristic function called `expr_consitutes_read`. It is tasked with detecting the situations where we have a place expression being passed to some parent expression that would not constitute a read necessarily, like a `let _ = *never_ptr` where `never_ptr: *const !`.

---

Specifically, for `let` and `match`, we don't consider it to be a read unless any of the subpatterns (i.e. the LHS of the `let` or the arms of the match) constitute a read. Almost all patterns constitute a read except for `_`, an `|` pattern, or the currently experimental `!` pattern.

---

I'm not totally certain that this deserves an FCP, since it's really a bugfix for UB. If it does, I'd be comfortable with it being a T-types FCP since we should be responsible with determining which coercions in the type system are sound (similar to how we adjusted subtyping behavior in rust-lang#118247 to be more sound).
@bors
Copy link
Contributor

bors commented Sep 6, 2024

☀️ Try build successful - checks-actions
Build commit: 19c0326 (19c032689f1eaa3070436eefb48228917adf58fa)

@compiler-errors
Copy link
Member Author

@craterbot check

@craterbot
Copy link
Collaborator

👌 Experiment pr-129392-1 created and queued.
🤖 Automatically detected try build 19c0326
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Sep 6, 2024
@traviscross traviscross added the F-never_type `#![feature(never_type)]` label Sep 11, 2024
@craterbot
Copy link
Collaborator

🚧 Experiment pr-129392-1 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🎉 Experiment pr-129392-1 is completed!
📊 13 regressed and 2 fixed (509855 total)
📰 Open the full report.

⚠️ If you notice any spurious failure please add them to the blacklist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Sep 16, 2024
@compiler-errors
Copy link
Member Author

@craterbot
Copy link
Collaborator

👌 Experiment pr-129392-2 created and queued.
🤖 Automatically detected try build 19c0326
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 16, 2024
@compiler-errors
Copy link
Member Author

I think all of the crater failures are spurious, including qroc which does look like it's failing for some reason but it doesn't seem to be due to any never type dereferencing 🤔 https://crater-reports.s3.amazonaws.com/pr-129392-1/try%2319c032689f1eaa3070436eefb48228917adf58fa/reg/qroc-0.1.0/log.txt

If it shows up again in the failure list after this retry, then I'll look a bit more into it.

@craterbot
Copy link
Collaborator

🚧 Experiment pr-129392-2 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🎉 Experiment pr-129392-2 is completed!
📊 0 regressed and 0 fixed (528 total)
📰 Open the full report.

⚠️ If you notice any spurious failure please add them to the blacklist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Sep 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. F-never_type `#![feature(never_type)]` proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

incorrect UB when when a ! place is constructed (but not loaded!)