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

(Selectively) turn on validation in const eval #95377

Closed
wants to merge 1 commit into from

Conversation

saethlin
Copy link
Member

@saethlin saethlin commented Mar 27, 2022

Normally we tell people that CTFE may detect UB, but it doesn't have to. RFC 3016 documents this explicitly: https://rust-lang.github.io/rfcs/3016-const-ub.html. But until I dug into #95332 I didn't realize how limited the UB checks in CTFE actually are: Invalid bit patterns are not checked for until we create an actual const. Thus, this code (from the linked issue) is not detected as UB:

use std::num::NonZeroU8;
pub const UNDEFINED: Option<NonZeroU8> = Some(unsafe { NonZeroU8::new_unchecked(0) });

and that is because in the Machine that rustc uses for CTFE, we have this:

    #[inline(always)]
    fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
        false // for now, we don't enforce validity
    }

The general idea of this PR is to add some state to Machine which indicates whether or not we may be executing unsafe code, and if we are, return true.

Since there is no unsafe in MIR, we're left analyzing HIR which is only available for the current crate. So currently this makes the defensive assumption that any MIR loaded from a non-local crate contains unsafe. This assumption could be inverted, I'm preferring the closer-to-sound option here but of course we have no obligation to detect UB here.

In this PR, the Machine used for CTFE detects unsafe in one of two ways. If there is a call to load_mir, we walk all the MIR looking for any unsafe blocks. But if the Machine sees a call to enforce_validity without a previous call to load_mir, it runs the same search but only on the current stack frame. This second case is very common when we are evaluating a trivial const. Each Machine instance will only search for unsafe blocks once.

r? @oli-obk

@rust-highfive
Copy link
Collaborator

Some changes occured to the CTFE / Miri engine

cc @rust-lang/miri

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Mar 27, 2022
@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 27, 2022
@RalfJung
Copy link
Member

@bors try @rust-timer queue
(FWIW, to my knowledge benchmarking like this will work even when the test suite still fails, so you don't have to get it all green just to collect some data.)

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 27, 2022
@bors
Copy link
Contributor

bors commented Mar 27, 2022

⌛ Trying commit 8ff27dec01384ec6769b77591e6cc8a01f9dd2dd with merge a5f01f22c3b8dccfe9fbeb6ae38c833309d3bf55...

@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Mar 27, 2022

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

@rust-timer
Copy link
Collaborator

Queued a5f01f22c3b8dccfe9fbeb6ae38c833309d3bf55 with parent d7aca22, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (a5f01f22c3b8dccfe9fbeb6ae38c833309d3bf55): comparison url.

Summary: This benchmark run shows 82 relevant regressions 😿 to instruction counts.

  • Arithmetic mean of relevant regressions: 6.7%
  • Arithmetic mean of all relevant changes: 6.6%
  • Largest regression in instruction counts: 50.6% on full builds of ctfe-stress-4 check

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR led to changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please fix the regressions and do another perf run. If the next run shows neutral or positive results, the label will be automatically removed.

@bors rollup=never
@rustbot label: +S-waiting-on-review -S-waiting-on-perf +perf-regression

@rustbot rustbot added perf-regression Performance regression. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels Mar 28, 2022
@oli-obk
Copy link
Contributor

oli-obk commented Mar 28, 2022

Just 50% isn't too bad 😆 I expected worse.

@saethlin
Copy link
Member Author

Hah! I should have known to just grab the ctfe stress test and run it locally. I'll try out some ideas over the coming days, to see if I can knock that down to a reasonable number.

@saethlin
Copy link
Member Author

🙈 don't look too closely at the code I'm just trying to see if this is in the domain of reasonable

@compiler-errors
Copy link
Member

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 29, 2022
@bors
Copy link
Contributor

bors commented Mar 29, 2022

⌛ Trying commit 27035bee70f89bfd0c6b753c0741439e24b11a95 with merge c0b2255faeb7c7432570244574d65ba1f5419512...

@bors
Copy link
Contributor

bors commented Mar 29, 2022

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

@rust-timer
Copy link
Collaborator

Queued c0b2255faeb7c7432570244574d65ba1f5419512 with parent ee915c3, future comparison URL.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (c0b2255faeb7c7432570244574d65ba1f5419512): comparison url.

Summary: This benchmark run shows 61 relevant regressions 😿 to instruction counts.

  • Arithmetic mean of relevant regressions: 5.1%
  • Arithmetic mean of all relevant changes: 5.0%
  • Largest regression in instruction counts: 23.9% on full builds of coercions check

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR led to changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please fix the regressions and do another perf run. If the next run shows neutral or positive results, the label will be automatically removed.

@bors rollup=never
@rustbot label: +S-waiting-on-review -S-waiting-on-perf +perf-regression

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 29, 2022
@oli-obk
Copy link
Contributor

oli-obk commented Mar 30, 2022

@bors try @rust-timer queue

@rust-timer
Copy link
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Mar 30, 2022
@oli-obk
Copy link
Contributor

oli-obk commented Apr 30, 2022

Hmm... we could totally make validation errors print the memory dump, too. Not possible for things represented as immediate, but everything else at least

@saethlin
Copy link
Member Author

@oli-obk Can you offer any guidance on how to add code to print the memory dump? Or is that something you are planning to land in a different PR before this one?

@oli-obk
Copy link
Contributor

oli-obk commented May 12, 2022

We have the display_allocation function for rendering these.

Basically we'd need to teach the validator to make throw_validation_failure also pass an Operand in addition to the self.path argument that is being used to print the field names of where things went wrong. We can then forward the operand via the ValidationFailure error type and use it in the diagnostic printing of ValidationFailure to produce a more detailed message (as a first step, maybe just print the memory of Indirect operands and Immediate(Scalar(Pointer)) operands.

This is a bit more involved and I'm fine regression those diagnostics for now and instead opening an issue about the above

@bors
Copy link
Contributor

bors commented May 14, 2022

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

@saethlin saethlin force-pushed the ctfe-validation branch 2 times, most recently from 29433d7 to be9b70c Compare May 16, 2022 04:41
@bors
Copy link
Contributor

bors commented May 20, 2022

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

@saethlin saethlin changed the title Try turning on validation in CTFE (Selectively) turn on validation in const eval May 21, 2022
Instead of only validating values which actually get stored to a const,
this PR attempts to turn on full validation in the presence of unsafe
code, as detected by walking HIR when available.
@saethlin
Copy link
Member Author

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 21, 2022
@oli-obk
Copy link
Contributor

oli-obk commented May 24, 2022

I'm conflicted on this. On the one hand it catches a bit more UB, on the other, this is a perf regression even without unsafe code, and makes the code more complex. With unsafe code the regression is massive (+50%).

Maybe we should really look into the lint direction: adding a lint and making the Machine::enable_validation solely depend on whether the MIR body has the lint enabled (and thus not permitting fine-grained lint allowing)

@saethlin
Copy link
Member Author

Do you mean something like #[forbid(const_ub)] ? Would users be able to use that as an inner attribute in the crate root?

@oli-obk
Copy link
Contributor

oli-obk commented May 24, 2022

Yea, the only weird thing would be that we have no concept for warn(const_ub) and that you can't use it within functions on expressions, only on functions.

@clarfonthey
Copy link
Contributor

So, I have an alternative idea I decided to turn into a PR: #97467

My change is comically simpler, which is why I don't have a lot of faith it's a good idea. But since proper UB detection is incredibly costly from the looks of it, might be worth exploring.

@saethlin
Copy link
Member Author

saethlin commented Jun 2, 2022

@rustbot label +S-waiting-on-author -S-waiting-on-review

@rustbot rustbot 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 Jun 2, 2022
@bors
Copy link
Contributor

bors commented Jun 6, 2022

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

@JohnCSimon
Copy link
Member

Ping from triage:
@saethlin - what is the status of this PR? can you address the merge conflicts?

@saethlin saethlin marked this pull request as draft July 3, 2022 02:39
@saethlin
Copy link
Member Author

saethlin commented Jul 3, 2022

@JohnCSimon I think I will soon be rewriting this into a different PR. Does marking this as a draft at least get it out of triage for now? (this was not blocked on merge conflicts, it is blocked on me deciding what approach to take)

@JohnCSimon
Copy link
Member

@saethlin Closing is preferable, but I try to triage anything that is over 15 days old

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
perf-regression Performance regression. 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.