Skip to content

Check discriminant during const eval #73146

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

Closed
Aaron1011 opened this issue Jun 8, 2020 · 6 comments
Closed

Check discriminant during const eval #73146

Aaron1011 opened this issue Jun 8, 2020 · 6 comments
Labels
A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html A-miri Area: The miri tool C-enhancement Category: An issue proposing an enhancement or a PR with one.

Comments

@Aaron1011
Copy link
Member

In #73137 (comment), an invalid Downcast is being generated for the generator state enum (the wrong variant is used). The MIR interpreter code doesn't actually verify that the expected and actual discriminants match when performing a Downcast. While doing this would not have caught the previous issue, it would allow us to detect U.B. at the point where it actually occurs, rather than needing to wait for invalid data to be read due to the wrong downcast.

This would require us to do several operations where we currently just change the layout of an MPlaceTy, so it might make sense to only run this check in Miri (not normal const-eval).

@Aaron1011 Aaron1011 added C-bug Category: This is a bug. A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html A-miri Area: The miri tool C-enhancement Category: An issue proposing an enhancement or a PR with one. and removed C-bug Category: This is a bug. labels Jun 8, 2020
@tmandry
Copy link
Member

tmandry commented Jun 9, 2020

The generator MIR does this intentionally. Situations can arise where a piece of code won't know which variant a generator is in, but does know it's valid to project through a downcast to get to a particular field. That's because the field exists in multiple variants, and is in the same location regardless of which variant you access it through.

Example:

let _ = || {
  let mut count = 0usize;
  loop {
    count += 1; // <-- What variant should we use?
    if count % 2 == 0 {
      yield 2;  // Suspend0
    }
    yield count;  // Suspend1
  }
}

At the point where count is incremented, our generator could either be in the Unresumed for Suspend1 state, going into either Suspend0 or Suspend1. The code we generate should be able to access count regardless.

@tmandry
Copy link
Member

tmandry commented Jun 9, 2020

Also, I think MIR usually initializes fields of a variant before setting the discriminant, so we would have to reverse that.

@RalfJung
Copy link
Member

RalfJung commented Jun 10, 2020

@Aaron1011 I am not sure I fully understand what you are suggesting to check here (and this two-line snippet is not very readable and about 4 times as wide as my screen^^).

Is the proposal to alter the semantics of Downcast to also read the current discriminant and compare that to the discriminant of the downcast-to variant? Is that what you mean by "expected discriminant"? As @tmandry pointed out, that is clearly not the intended behavior of the current Downcast -- currently it is just meant to be changing the type of a place without any side-effects. So this would be a major change and introduce a new kind of UB on the MIR level. Not that that's bad, but it seems non-trivial.

@Aaron1011
Copy link
Member Author

Is the proposal to alter the semantics of Downcast to also read the current discriminant and compare that to the discriminant of the downcast-to variant?

Yes, that's correct

So this would be a major change and introduce a new kind of UB on the MIR level. Not that that's bad, but it seems non-trivial.

My intention was for this to catch 'obviously wrong' downcasts, like None.downcast(Some(_)). I just learned that generators can use the 'wrong' variant when downcasting, so this kind of a check might not make sense for generators (unless we introduce some notion of 'compatible variants').

@RalfJung
Copy link
Member

IMO UB should be motivated by optimizations. Catching bugs in our MIR building is not a good enough reason to add a new class of UB.

@RalfJung
Copy link
Member

RalfJung commented Nov 1, 2020

Given what I said above, I am in favor of closing this issue -- currently the intended semantics of Downcast clearly involve it being legal to downcast to "other" variants as long as you only access fields common to both the actual and the downcast-to variant.

@oli-obk oli-obk closed this as completed Nov 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html A-miri Area: The miri tool C-enhancement Category: An issue proposing an enhancement or a PR with one.
Projects
None yet
Development

No branches or pull requests

4 participants