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

unsoundness caused by hidden borrow in nightly match ergonomics #49631

Closed
bvinc opened this issue Apr 4, 2018 · 6 comments
Closed

unsoundness caused by hidden borrow in nightly match ergonomics #49631

bvinc opened this issue Apr 4, 2018 · 6 comments
Assignees
Labels
I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness P-high High priority regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Milestone

Comments

@bvinc
Copy link
Contributor

bvinc commented Apr 4, 2018

Playground

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Foo {
    ReallyReallyReallyLongName,
    Foo2,
    Foo3,
}

struct Iter {
    done: bool
}

impl Iterator for Iter {
    type Item = Result<Foo, String>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.done { return None; }
        self.done = true;
        Some(Ok(Foo::ReallyReallyReallyLongName))
    }
}

fn main() {
    let iter = Iter{done: false};
    let mut iter = iter.peekable();
    
    // peek() returns type Option<&Result<Foo, String>>
    // pattern Some(Ok(foo)) is used instead of Some(&Ok(foo))
    // This causes foo to be a hidden borrow of type &Foo
    while let Some(Ok(foo)) = iter.peek() {
        iter.next();  // destroys what foo is pointing to
        println!("foo={:?}", *foo);
    }
}

Output:

Illegal instruction (core dumped)

The above code should fail the borrow checker. They key line seems to be the pattern match. It creates a borrow that seems to be invisible to the borrow checker. This appears to only be possible in nightly due to the match_default_bindings feature.

@cramertj cramertj added P-high High priority regression-from-stable-to-beta Performance or correctness regression from stable to beta. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness labels Apr 4, 2018
@Mark-Simulacrum Mark-Simulacrum added this to the 1.26 milestone Apr 4, 2018
@varkor
Copy link
Member

varkor commented Apr 4, 2018

Note that this is not a problem when using NLL: playground link.

@cramertj cramertj added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 5, 2018
@nikomatsakis
Copy link
Contributor

Sigh. It works with an explicit ref, as well, which suggests that the problem is the ExprUseVisitor.

@nikomatsakis nikomatsakis self-assigned this Apr 5, 2018
@nikomatsakis
Copy link
Contributor

OK, so I found the bug. Not sure yet what is best fix. Let me write out what is going on:

  • ExprUseVisitor winds up aborting because it invokes the mem-categorization code on a pattern gets back an Err result. It assumes (incorrectly) that this indicates a compilation error was reported in typeck.
  • mem-categorization is correctly looking at the desugared pattern Some(&Ok(ref foo))
    • however, it is incorrectly tracking the type of the value being matched
    • that type starts out correct, as Option<&Result<..>>
    • but when we pass through the Some pattern to the subpatterns:
      • we incorrectly adjust the type to Result, not &Result
      • this is because we get the type from pat_ty:

let subpat_ty = self.pat_ty(&subpat)?; // see (*2)

So we need to stop doing that. Ah, I guess the pat_adjustments array stores the information we need:

/// Stores the types which were implicitly dereferenced in pattern binding modes
/// for later usage in HAIR lowering. For example,
///
/// ```
/// match &&Some(5i32) {
/// Some(n) => {},
/// _ => {},
/// }
/// ```
/// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
///
/// See:
/// https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions
pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,

@leoyvens
Copy link
Contributor

leoyvens commented Apr 5, 2018

I think we should not stabilize language features right before beta is branched. I don't know if this issue in particular is big deal to backport or not, but stabilizing things at the begging/middle of the cycle avoids rushing to stabilize and then rushing to fix and backport regressions.

@nikomatsakis
Copy link
Contributor

( Fix in #49714 )

@nikomatsakis
Copy link
Contributor

@leodasvacas

I don't know if this issue in particular is big deal to backport or not, but stabilizing things at the begging/middle of the cycle avoids rushing to stabilize and then rushing to fix and backport regressions.

In this case, the fix is trivial -- you can see #49714.

In general, we thought about trying to time landings into the middle of the cycle back in the early days, but we wound up concluding that there is no "right time" to land something. Any change can break stuff, of course, and wherever we draw the line, we've got a shot at getting something breaking.

So I don't know. Maybe it's worth putting rules against stabilizing, but I kinda don't think so. At worst we can "unstabilize" (which I fear we will have to do for !...)

bors added a commit that referenced this issue Apr 8, 2018
mem-categorization, coherence fix

make mem-categorization use adjusted type for patterns: Fixes #49631

do not propagate `Err` when determing causal info: Fixes #48728

r? @eddyb
alexcrichton pushed a commit to alexcrichton/rust that referenced this issue Apr 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness P-high High priority regression-from-stable-to-beta Performance or correctness regression from stable to beta. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants