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

borrowed referent of a `&T` sometimes incorrectly allowed #38899

Open
nikomatsakis opened this Issue Jan 7, 2017 · 37 comments

Comments

Projects
None yet
@nikomatsakis
Contributor

nikomatsakis commented Jan 7, 2017

@jorendorf asks on the users forum about a curious discrepancy around fields. It seems that implicit borrows sometimes seem to get overlooked in the borrow checker. This seems like a kind of bad bug, though it's exact scope is unclear until we investigate a bit more.

Here is a variant of @jorendorf's example which is pretty clearly wrong. Here, the block variable is mutably borrowed into x, so it should not be accessible via let p:

#![allow(dead_code)]
pub struct Block<'a> {
    current: &'a u8,
    unrelated: &'a u8,
}

fn bump<'a>(mut block: &mut Block<'a>) {
    let x = &mut block;
    let p: &'a u8 = &*block.current;
}

fn main() {}

I'm guessing that the problem has to do with the logic around borrowing the referent of an &T (in this case, we are borrowing *block.current). In particular, we deem that to be "safe" for the scope of 'a because the data is independently guaranteed to be valid that long (this is reasonable). But we still need to validate that block.current can be (instantaneously) read. It seems we are not doing that. But this is all a hypothesis: I've not dug into the code to validate it.

@nikomatsakis nikomatsakis changed the title from implicit coercions sometimes incorrectly allow reads from borrowed fields to borrowed referent of a `&T` sometimes incorrectly allowed Jan 7, 2017

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 7, 2017

Contributor

I have a fix locally. I'm going to try and evaluate the impact.

Contributor

nikomatsakis commented Jan 7, 2017

I have a fix locally. I'm going to try and evaluate the impact.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 7, 2017

Contributor

This is gonna' be bad unless we address the problem that makes vec.push(vec.len()) an error.

Contributor

nikomatsakis commented Jan 7, 2017

This is gonna' be bad unless we address the problem that makes vec.push(vec.len()) an error.

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Jan 8, 2017

Contributor

How bad?

Contributor

arielb1 commented Jan 8, 2017

How bad?

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 9, 2017

Contributor

@arielb1 I don't know. I'm working through the bootstrap process now, then I'll try to do some sort of crater run to get an idea.

As an aside, this bug dates back to Rust 1.0.0 from what I can tell.

Contributor

nikomatsakis commented Jan 9, 2017

@arielb1 I don't know. I'm working through the bootstrap process now, then I'll try to do some sort of crater run to get an idea.

As an aside, this bug dates back to Rust 1.0.0 from what I can tell.

nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Jan 9, 2017

check that the path from which we borrow is readable
The old code incorrectly assumed that the borrow would always generate a
loan. In that case, we will check if that loan conflicts with other
loans and hence get an error if the path we borrowed is mutably
borrowed. But this is not true if we are borrowing the referent of an
`&T` reference.

Fixes #38899.
@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 11, 2017

Contributor

Branch in my repo is nikomatsakis/issue-38899 btw. I did a crater run which showed 160 root regressions: https://gist.github.com/nikomatsakis/9279f3023ecbec3d1f09730671c7884b

Contributor

nikomatsakis commented Jan 11, 2017

Branch in my repo is nikomatsakis/issue-38899 btw. I did a crater run which showed 160 root regressions: https://gist.github.com/nikomatsakis/9279f3023ecbec3d1f09730671c7884b

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 11, 2017

Contributor

I don't know what percentage of those would be fixed by the method call temporary thing. Certainly not all (I just opened one at random and found it would not have been).

Contributor

nikomatsakis commented Jan 11, 2017

I don't know what percentage of those would be fixed by the method call temporary thing. Certainly not all (I just opened one at random and found it would not have been).

@aidanhs

This comment has been minimized.

Show comment
Hide comment
@aidanhs

aidanhs Jan 13, 2017

Member

Not sure why ayzim is listed as a root regression when the log shows the culprit is lazy_static (same is true of a few other crates I clicked at random).

Member

aidanhs commented Jan 13, 2017

Not sure why ayzim is listed as a root regression when the log shows the culprit is lazy_static (same is true of a few other crates I clicked at random).

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 13, 2017

Contributor

@aidanhs yeah, it seems like it gets a bit goofy sometimes in that respect.

Contributor

nikomatsakis commented Jan 13, 2017

@aidanhs yeah, it seems like it gets a bit goofy sometimes in that respect.

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Jan 14, 2017

Contributor

@nikomatsakis

If only say 20% of these examples are fixed by method call temporaries, I don't see why we shouldn't do the normal lint -> hard error sequence here.

Sure it's sad to break basically every non-trivial rust project ever, but method call temporaries won't help/

Contributor

arielb1 commented Jan 14, 2017

@nikomatsakis

If only say 20% of these examples are fixed by method call temporaries, I don't see why we shouldn't do the normal lint -> hard error sequence here.

Sure it's sad to break basically every non-trivial rust project ever, but method call temporaries won't help/

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 17, 2017

Contributor

@arielb1 it seems worth trying to investigate a bit more deeply. However, the experience in rustc was quite different -- the majority of errors were fixed. I think I had only one problem (out of ... 10 or so?) that was fixed a different way.

Contributor

nikomatsakis commented Jan 17, 2017

@arielb1 it seems worth trying to investigate a bit more deeply. However, the experience in rustc was quite different -- the majority of errors were fixed. I think I had only one problem (out of ... 10 or so?) that was fixed a different way.

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Jan 18, 2017

Contributor

The lazy_static example looks like it's tracking a borrow of the dereference of an unsafe pointer *self.0 for some reason - that's a false positive.

In rustc, it seems that:
2 error can't be fixed by multiphase borrows (rustc_resolve::macros, getopts), of them the rustc_resolve::macros issue is a "hard-to-fix" false positive and the getopts fix is a "technically UB" case.
19 errors are of the foo.mutate(&*foo.field) kind.
1 errors will be fixed by making reborrows multiphase, but will not be fixed by changing order of evaluation (rustc_typeck::check::upvar)

Contributor

arielb1 commented Jan 18, 2017

The lazy_static example looks like it's tracking a borrow of the dereference of an unsafe pointer *self.0 for some reason - that's a false positive.

In rustc, it seems that:
2 error can't be fixed by multiphase borrows (rustc_resolve::macros, getopts), of them the rustc_resolve::macros issue is a "hard-to-fix" false positive and the getopts fix is a "technically UB" case.
19 errors are of the foo.mutate(&*foo.field) kind.
1 errors will be fixed by making reborrows multiphase, but will not be fixed by changing order of evaluation (rustc_typeck::check::upvar)

@aidanhs

This comment has been minimized.

Show comment
Hide comment
@aidanhs

aidanhs Jan 18, 2017

Member

@arielb1 isn't it tracking the mutable borrow of the pointer itself rather than its dereference? Which then conflicts with dereferencing the pointer later on.

Member

aidanhs commented Jan 18, 2017

@arielb1 isn't it tracking the mutable borrow of the pointer itself rather than its dereference? Which then conflicts with dereferencing the pointer later on.

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Jan 18, 2017

Contributor

@aidanhs

After looking at it again, sure. It's just another case of #6393.

Contributor

arielb1 commented Jan 18, 2017

@aidanhs

After looking at it again, sure. It's just another case of #6393.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 19, 2017

Contributor

@arielb1 right; so 19/23 (80%) seems pretty significant.

Contributor

nikomatsakis commented Jan 19, 2017

@arielb1 right; so 19/23 (80%) seems pretty significant.

@Ms2ger

This comment has been minimized.

Show comment
Hide comment
@Ms2ger

Ms2ger Mar 1, 2017

Contributor
Contributor

Ms2ger commented Mar 1, 2017

@bstrie

This comment has been minimized.

Show comment
Hide comment
@bstrie

bstrie Mar 9, 2017

Contributor

This is gonna' be bad unless we address the problem that makes vec.push(vec.len()) an error.

@nikomatsakis does this imply that NLL would allow us to fix this without breakage?

Contributor

bstrie commented Mar 9, 2017

This is gonna' be bad unless we address the problem that makes vec.push(vec.len()) an error.

@nikomatsakis does this imply that NLL would allow us to fix this without breakage?

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Mar 16, 2017

Contributor

@bstrie

does this imply that NLL would allow us to fix this without breakage?

No, some things would still break.

Contributor

nikomatsakis commented Mar 16, 2017

@bstrie

does this imply that NLL would allow us to fix this without breakage?

No, some things would still break.

@bstrie

This comment has been minimized.

Show comment
Hide comment
@bstrie

bstrie Jun 20, 2017

Contributor

@nikomatsakis I see that you removed your nomination from this bug without assigning it a priority, was that intentional?

Contributor

bstrie commented Jun 20, 2017

@nikomatsakis I see that you removed your nomination from this bug without assigning it a priority, was that intentional?

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Aug 14, 2017

Contributor

@bstrie

This is "waiting for 2φB", which is waiting for an RFC + MIR borrowck.

Contributor

arielb1 commented Aug 14, 2017

@bstrie

This is "waiting for 2φB", which is waiting for an RFC + MIR borrowck.

@bstrie bstrie added the P-high label Sep 14, 2017

@bstrie

This comment has been minimized.

Show comment
Hide comment
@bstrie

bstrie Sep 14, 2017

Contributor

This is gonna' be bad unless we address the problem that makes vec.push(vec.len()) an error.

The "Enable nested method calls" RFC (a.k.a. "two-phase borrows", which is what I presume @arielb1 meant by "2φB") was recently accepted: rust-lang/rfcs#2025 .

Even considering MIR borrowck as a blocker, given that that RFC seems to be a high priority for the forthcoming three-month impl period, is it safe to assume that we'll have something in nightly by December with which we can start doing cargobomb runs to determine exactly how painful this bug will be to fix?

Possibly overstepping my bounds my assigning this a P-high, but it really does concern me the most of all the open and in-stable soundness bugs, and I have a longstanding pet peeve concerning unprioritized soundness bugs. :P

Contributor

bstrie commented Sep 14, 2017

This is gonna' be bad unless we address the problem that makes vec.push(vec.len()) an error.

The "Enable nested method calls" RFC (a.k.a. "two-phase borrows", which is what I presume @arielb1 meant by "2φB") was recently accepted: rust-lang/rfcs#2025 .

Even considering MIR borrowck as a blocker, given that that RFC seems to be a high priority for the forthcoming three-month impl period, is it safe to assume that we'll have something in nightly by December with which we can start doing cargobomb runs to determine exactly how painful this bug will be to fix?

Possibly overstepping my bounds my assigning this a P-high, but it really does concern me the most of all the open and in-stable soundness bugs, and I have a longstanding pet peeve concerning unprioritized soundness bugs. :P

@arielb1 arielb1 added P-medium and removed P-high labels Sep 14, 2017

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Sep 14, 2017

Contributor

@bstrie

There's no point prioritizing this bug. It will be fixed by 2-phase borrows, and not beforehand. And I'm quite sure we decided to wait on 2-phase borrows until MIR borrowck.

Contributor

arielb1 commented Sep 14, 2017

@bstrie

There's no point prioritizing this bug. It will be fixed by 2-phase borrows, and not beforehand. And I'm quite sure we decided to wait on 2-phase borrows until MIR borrowck.

@briansmith

This comment has been minimized.

Show comment
Hide comment
@briansmith

briansmith Sep 15, 2017

@arielb1 How can l-unsound bugs be anything other than high priority? As a matter of policy it shouldn't take over a year (or, IMO, more than one release) for l-unsound bugs to be fixed.

briansmith commented Sep 15, 2017

@arielb1 How can l-unsound bugs be anything other than high priority? As a matter of policy it shouldn't take over a year (or, IMO, more than one release) for l-unsound bugs to be fixed.

@bstrie

This comment has been minimized.

Show comment
Hide comment
@bstrie

bstrie Sep 17, 2017

Contributor

How can l-unsound bugs be anything other than high priority?

@briansmith:

  • Some soundness bugs exist only via unstable features on nightly (e.g. #44367)
  • Not all soundness bugs affect all platforms (#43241)
  • Some soundness bugs are vague and unreproducible (#18072)
  • Some soundness bugs are because of LLVM bugs that people are loathe to work around rather than waiting on LLVM to properly address the issue (#28728)
  • Not all soundness bugs present backcompat hazards (e.g. #10389)
  • Some soundness bugs are simply contrived enough that nobody has prioritized plugging them yet (#41799)

(Many of the open soundness bugs fall into multiple of the above categories, too.)

That said, I think that this particular bug falls into none of those categories, hence my earlier statement that this "really does concern me the most of all the open and in-stable soundness bugs". However, P-high tends to mean "there is someone actively taking steps to address this", which in this case is technically true (someone's working on MIR borrowck, which is a prereq for two-phase borrows, which is a prereq for this bug) but I get the impression that arielb1 simply disagrees that completing those orthogonal tasks count as "working on" this bug.

As a matter of policy it shouldn't take over a year (or, IMO, more than one release) for l-unsound bugs to be fixed.

I'm hopeful that such a policy will eventually manifest, once we have both MIR borrowck and Chalk (most of the interesting open soundness bugs are waiting on these two initiatives, AFAICT: #27282, #27868, #29723, #25860, #44454, #27675, plus this issue itself), especially now that Rust code is about to be in stable Firefox. But especially with LLVM bugs we don't always have the combination of manpower and LLVM expertise to make this a strict rule.

Contributor

bstrie commented Sep 17, 2017

How can l-unsound bugs be anything other than high priority?

@briansmith:

  • Some soundness bugs exist only via unstable features on nightly (e.g. #44367)
  • Not all soundness bugs affect all platforms (#43241)
  • Some soundness bugs are vague and unreproducible (#18072)
  • Some soundness bugs are because of LLVM bugs that people are loathe to work around rather than waiting on LLVM to properly address the issue (#28728)
  • Not all soundness bugs present backcompat hazards (e.g. #10389)
  • Some soundness bugs are simply contrived enough that nobody has prioritized plugging them yet (#41799)

(Many of the open soundness bugs fall into multiple of the above categories, too.)

That said, I think that this particular bug falls into none of those categories, hence my earlier statement that this "really does concern me the most of all the open and in-stable soundness bugs". However, P-high tends to mean "there is someone actively taking steps to address this", which in this case is technically true (someone's working on MIR borrowck, which is a prereq for two-phase borrows, which is a prereq for this bug) but I get the impression that arielb1 simply disagrees that completing those orthogonal tasks count as "working on" this bug.

As a matter of policy it shouldn't take over a year (or, IMO, more than one release) for l-unsound bugs to be fixed.

I'm hopeful that such a policy will eventually manifest, once we have both MIR borrowck and Chalk (most of the interesting open soundness bugs are waiting on these two initiatives, AFAICT: #27282, #27868, #29723, #25860, #44454, #27675, plus this issue itself), especially now that Rust code is about to be in stable Firefox. But especially with LLVM bugs we don't always have the combination of manpower and LLVM expertise to make this a strict rule.

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Sep 17, 2017

Contributor

As a matter of policy it shouldn't take over a year (or, IMO, more than one release) for l-unsound bugs to be fixed.

This is generally the case. Except that rustc's borrowck is fatally broken in several ways, and we're working on a replacement.

Contributor

arielb1 commented Sep 17, 2017

As a matter of policy it shouldn't take over a year (or, IMO, more than one release) for l-unsound bugs to be fixed.

This is generally the case. Except that rustc's borrowck is fatally broken in several ways, and we're working on a replacement.

@erickt

This comment has been minimized.

Show comment
Hide comment
@erickt

erickt Sep 27, 2017

Contributor

FYI this bug was exploited by @aidanhs in his entry for the 2016 underhanded rust contest.

Contributor

erickt commented Sep 27, 2017

FYI this bug was exploited by @aidanhs in his entry for the 2016 underhanded rust contest.

@Ixrec

This comment has been minimized.

Show comment
Hide comment
@Ixrec

Ixrec Oct 4, 2017

Contributor

Is this one of the borrow checking soundness bugs that's likely to get fixed "for free" or close-to-free by the move to MIR borrowck, two-phase borrows and/or NLL?

Contributor

Ixrec commented Oct 4, 2017

Is this one of the borrow checking soundness bugs that's likely to get fixed "for free" or close-to-free by the move to MIR borrowck, two-phase borrows and/or NLL?

@bstrie

This comment has been minimized.

Show comment
Hide comment
@bstrie

bstrie Oct 9, 2017

Contributor

@Ixrec It seems that the plan is that NLL will get us most of the way towards fixing this bug.

Contributor

bstrie commented Oct 9, 2017

@Ixrec It seems that the plan is that NLL will get us most of the way towards fixing this bug.

@Manishearth

This comment has been minimized.

Show comment
Hide comment
@Manishearth

Manishearth Nov 8, 2017

Member

Given that NLL happened, where are we on this bug?

Member

Manishearth commented Nov 8, 2017

Given that NLL happened, where are we on this bug?

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Nov 8, 2017

Contributor

@Manishearth

MIR borrowck doesn't have this bug. When it will be enabled by default, this bug will be fixed.

Contributor

arielb1 commented Nov 8, 2017

@Manishearth

MIR borrowck doesn't have this bug. When it will be enabled by default, this bug will be fixed.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 4, 2018

Contributor

I propose that we add a test file (with #![feature(nll)]) documenting that this is fixed, so I've labeled this as E-needstest.

Contributor

nikomatsakis commented Jan 4, 2018

I propose that we add a test file (with #![feature(nll)]) documenting that this is fixed, so I've labeled this as E-needstest.

@nikomatsakis nikomatsakis added this to the NLL Future Compat Warnings milestone Jan 4, 2018

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
Contributor

nikomatsakis commented Jan 4, 2018

chrisvittal added a commit to chrisvittal/rust that referenced this issue Jan 11, 2018

Add NLL tests for #46557 and #38899
Closes #47366

Adapt the sample code from the issues into mir-borrowck/nll test cases.

kennytm added a commit to kennytm/rust that referenced this issue Jan 15, 2018

Rollup merge of #47368 - chrisvittal:nll-tests, r=nikomatsakis
Add NLL tests for #46557 and #38899

This adapts the sample code from the two issues into test code.

Closes #46557
Closes #38899

r? @nikomatsakis

kennytm added a commit to kennytm/rust that referenced this issue Jan 15, 2018

Rollup merge of #47368 - chrisvittal:nll-tests, r=nikomatsakis
Add NLL tests for #46557 and #38899

This adapts the sample code from the two issues into test code.

Closes #46557
Closes #38899

r? @nikomatsakis

@bors bors closed this in #47368 Jan 15, 2018

@aidanhs

This comment has been minimized.

Show comment
Hide comment
@aidanhs

aidanhs Jan 15, 2018

Member

Per #46557 (comment): I think it's reasonable to say this is a P-medium issue until the fix is in master and enabled by default (I'm open to disagreement though!).

Member

aidanhs commented Jan 15, 2018

Per #46557 (comment): I think it's reasonable to say this is a P-medium issue until the fix is in master and enabled by default (I'm open to disagreement though!).

@aidanhs aidanhs reopened this Jan 15, 2018

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 16, 2018

Contributor

@aidanhs and I discussed. Since there is a test and this is fixed in MIR borrow check, closing as duplicate of #47366.

Contributor

nikomatsakis commented Jan 16, 2018

@aidanhs and I discussed. Since there is a test and this is fixed in MIR borrow check, closing as duplicate of #47366.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 16, 2018

Contributor

Er, perhaps that was premature. =)

Contributor

nikomatsakis commented Jan 16, 2018

Er, perhaps that was premature. =)

@nikomatsakis nikomatsakis reopened this Jan 16, 2018

@pnkfelix

This comment has been minimized.

Show comment
Hide comment
@pnkfelix

pnkfelix Jan 18, 2018

Member

@nikomatsakis so wait, what is the policy then for #47366? Are we closing issues that are fixed by #![feature(nll)] as long as they have a test? Or are we just downgrading them to P-medium?

(And either way, should this bug be linked from checklist in #47366 description?)

Member

pnkfelix commented Jan 18, 2018

@nikomatsakis so wait, what is the policy then for #47366? Are we closing issues that are fixed by #![feature(nll)] as long as they have a test? Or are we just downgrading them to P-medium?

(And either way, should this bug be linked from checklist in #47366 description?)

@pnkfelix

This comment has been minimized.

Show comment
Hide comment
@pnkfelix

pnkfelix Jan 18, 2018

Member

Ah according to #46557 (comment) the policy is that we're removing WG-compiler-nll label from such issues? That seems ... reasonable. Since then the work queue (either in-progress or to-do) should be identifiable from that label?

Member

pnkfelix commented Jan 18, 2018

Ah according to #46557 (comment) the policy is that we're removing WG-compiler-nll label from such issues? That seems ... reasonable. Since then the work queue (either in-progress or to-do) should be identifiable from that label?

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis
Contributor

nikomatsakis commented Jan 18, 2018

@pnkfelix yeah

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment