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

Borrow checker unsoundness with unions #45157

Closed
petrochenkov opened this issue Oct 9, 2017 · 11 comments · Fixed by #47689 or #64221
Closed

Borrow checker unsoundness with unions #45157

petrochenkov opened this issue Oct 9, 2017 · 11 comments · Fixed by #47689 or #64221
Labels
A-borrow-checker Area: The borrow checker C-bug Category: This is a bug. fixed-by-NLL Bugs fixed, but only when NLL is enabled. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@petrochenkov
Copy link
Contributor

petrochenkov commented Oct 9, 2017

#![allow(unused)]

#[derive(Clone, Copy, Default)]
struct S {
    a: u8,
    b: u8,
}
#[derive(Clone, Copy, Default)]
struct Z {
    c: u8,
    d: u8,
}

union U {
    s: S,
    z: Z,
}

fn main() { unsafe {
    let mut u = U { s: Default::default() };
    
    let mref = &mut u.s.a;
    let err = &u.z.c; // This line compiles, but it certainly shouldn't ...
    drop(mref); // ... (at least if `mref` is used after `err`)
}}

"Cousins" of borrowed union sub-fields (and their further children) are not marked as borrowed.
The same bug should happen with move checking as well, but I haven't made an example yet.

@petrochenkov petrochenkov added A-borrow-checker Area: The borrow checker I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness labels Oct 9, 2017
@TimNN TimNN added the C-bug Category: This is a bug. label Oct 10, 2017
@pnkfelix pnkfelix added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Oct 13, 2017
@nikomatsakis
Copy link
Contributor

This is still true in NLL, though I sort of thought we had tried to fix this.

@nikomatsakis
Copy link
Contributor

I'm tagging this as WG-compiler-nll; I think it's something we should fix there.

@joshtriplett
Copy link
Member

For the sake of potential testsuite additions: this also should not compile with a simultaneous borrow of u.s.a and u.z.d.

@davidtwco
Copy link
Member

I'll take a look at this one.

@nikomatsakis
Copy link
Contributor

I'm not really sure what the bug is here, but I can explain what I think should be happening. This function:

fn place_element_conflict(&self, elem1: &Place<'tcx>, elem2: &Place<'tcx>) -> Overlap {

is responsible for determining when two Place values overlap. I expect us to say that two fields from a union are always considered to potentially overlap. In this case, u.s and u.z would be considered to overlap. Specifically, comparing those two fields would return Arbitrary:

This is the code that I think should be responsible for doing that:

ty::TyAdt(def, _) if def.is_union() => {
// Different fields of a union, we are basically stuck.
debug!("place_element_conflict: STUCK-UNION");
Overlap::Arbitrary
}

It already looks a little fishy to me; in particular, it is returning Arbitrary if pi1 is a union, but I guess it should be equally true if pi2 is a union. Anyway, something here seems to be going awry!

@nikomatsakis
Copy link
Contributor

So it seems like I forgot about how smart the compiler is now. This version of the test does error, as expected:

https://play.rust-lang.org/?gist=86c25066ab9197ebfd7a91b573f97595&version=nightly

davidtwco added a commit to davidtwco/rust that referenced this issue Jan 24, 2018
@davidtwco davidtwco self-assigned this Jan 25, 2018
Manishearth added a commit to Manishearth/rust that referenced this issue Feb 24, 2018
Fix borrow checker unsoundness with unions

Fixes rust-lang#45157. After discussion with @nikomatsakis on Gitter, this PR only adds a test since the original issue was resolved elsewhere.

r? @nikomatsakis
@nikomatsakis
Copy link
Contributor

I think the policy is that we will keep this bug open, but file it under #47366

@nikomatsakis
Copy link
Contributor

(Since it is only fixed when NLL is enabled)

@Centril
Copy link
Contributor

Centril commented Nov 20, 2018

@nikomatsakis should this be NLL-fixed-by-NLL?

@arielb1 arielb1 added the fixed-by-NLL Bugs fixed, but only when NLL is enabled. label Jan 25, 2019
@arielb1
Copy link
Contributor

arielb1 commented Jan 25, 2019

Note that to get an NLL test failure, you have to use mref after declaring err:

#![allow(unused)]

#[derive(Clone, Copy, Default)]
struct S {
    a: u8,
    b: u8,
}
#[derive(Clone, Copy, Default)]
struct Z {
    c: u8,
    d: u8,
}

union U {
    s: S,
    z: Z,
}



fn main() { unsafe {
    let mut u = U { s: Default::default() };
    
    let mref = &mut u.s.a;
    let err = &u.z.c; // This line compiles, but it certainly shouldn't 
    drop(mref);
}}

@davidtwco davidtwco removed their assignment Mar 12, 2019
@pnkfelix
Copy link
Member

NLL (migrate mode) is enabled in all editions as of PR #59114.

The only policy question is that, under migrate mode, we only emit a warning on this (unsound) test case. Therefore, I am not 100% sure whether we should close this until that warning has been turned into a hard-error under our (still in development) future-compatibility lint policy.

Centril added a commit to Centril/rust that referenced this issue Sep 25, 2019
Centril added a commit to Centril/rust that referenced this issue Sep 26, 2019
…hewjasper

 Rust 2015: No longer downgrade NLL errors

As per decision on a language team meeting as described in rust-lang#63565 (comment), in Rust 2015, we refuse to downgrade NLL errors, that AST borrowck accepts, into warnings and keep them as hard errors.

The remaining work to throw out AST borrowck and adjust some tests still remains after this PR.

Fixes rust-lang#38899
Fixes rust-lang#53432
Fixes rust-lang#45157
Fixes rust-lang#31567
Fixes rust-lang#27868
Fixes rust-lang#47366

r? @matthewjasper
Centril added a commit to Centril/rust that referenced this issue Sep 26, 2019
…hewjasper

 Rust 2015: No longer downgrade NLL errors

As per decision on a language team meeting as described in rust-lang#63565 (comment), in Rust 2015, we refuse to downgrade NLL errors, that AST borrowck accepts, into warnings and keep them as hard errors.

The remaining work to throw out AST borrowck and adjust some tests still remains after this PR.

Fixes rust-lang#38899
Fixes rust-lang#53432
Fixes rust-lang#45157
Fixes rust-lang#31567
Fixes rust-lang#27868
Fixes rust-lang#47366

r? @matthewjasper
Centril added a commit to Centril/rust that referenced this issue Sep 26, 2019
Centril added a commit to Centril/rust that referenced this issue Sep 26, 2019
…hewjasper

 Rust 2015: No longer downgrade NLL errors

As per decision on a language team meeting as described in rust-lang#63565 (comment), in Rust 2015, we refuse to downgrade NLL errors, that AST borrowck accepts, into warnings and keep them as hard errors.

The remaining work to throw out AST borrowck and adjust some tests still remains after this PR.

Fixes rust-lang#38899
Fixes rust-lang#53432
Fixes rust-lang#45157
Fixes rust-lang#31567
Fixes rust-lang#27868
Fixes rust-lang#47366

r? @matthewjasper
@bors bors closed this as completed in 3b5fbb6 Sep 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-borrow-checker Area: The borrow checker C-bug Category: This is a bug. fixed-by-NLL Bugs fixed, but only when NLL is enabled. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
9 participants