Skip to content

Borrow checker incorrectly accepts code when calling function with complex lifetime bounds through a fn pointer #57170

Closed

Description

@ennis

The following code compiles and prints a bogus value:

fn shorten_lifetime<'a, 'b, 'min>(a: &'a i32, b: &'b i32) -> &'min i32
where 'a: 'min, 'b: 'min
{
    if *a < *b {
        &a
    } else {
        &b
    }
}


fn main()
{
    let fnptr = &shorten_lifetime;
    
    let a = &5;
    let ptr = {
        let b = 3;
        let b = &b;
        //let c = shorten_lifetime(a, b);
        let c = fnptr(a, b);
        c
    };
    
    println!("ptr = {:?}", ptr);
    
}

Output (release mode):

ptr = -1876488848

(playground: https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=048d856b4689599b1e35f0a44ebe629f)

Expected result: a borrow checker error, the same as the one obtained when calling shorten_lifetime directly.

I accidentally ran into this issue when trying to spell the fn pointer type of fnptr (I'm not sure how to add constraints to the lifetimes of a higher-ranked fn type like for<'a, 'b> fn(...) -> T)

Activity

  1. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
    on Dec 28, 2018
  2. jonas-schievink commented on Dec 28, 2018

    @jonas-schievink
    Contributor

    The 2015 edition correctly rejects this (which doesn't yet have NLL)

  3. added
    A-NLLArea: Non-lexical lifetimes (NLL)
    on Dec 28, 2018
  4. nagisa commented on Dec 28, 2018

    @nagisa
    Member
  5. nagisa commented on Dec 28, 2018

    @nagisa
    Member

    @rust-lang/wg-compiler-nll

  6. added
    NLL-soundWorking towards the "invalid code does not compile" goal
    on Dec 28, 2018
  7. matthewjasper commented on Dec 28, 2018

    @matthewjasper
    Contributor

    It appears that we lose the function bounds when we promote shorten_lifetime. Relavant FIXME:

    // FIXME -- promoted MIR return types reference
    // various "free regions" (e.g., scopes and things)
    // that they ought not to do. We have to figure out
    // how best to handle that -- probably we want treat
    // promoted MIR much like closures, renumbering all
    // their free regions and propagating constraints
    // upwards. We have the same acyclic guarantees, so
    // that should be possible. But for now, ignore them.
    //
    // let promoted_mir = &self.mir.promoted[index];
    // promoted_mir.return_ty()

  8. pnkfelix commented on Feb 27, 2019

    @pnkfelix
    Contributor

    triage: P-high. Hopefully fix in PR #57202 lands very soon.

  9. added a commit that references this issue on Mar 2, 2019
    a21d824
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-NLLArea: Non-lexical lifetimes (NLL)I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessNLL-soundWorking towards the "invalid code does not compile" goalP-highHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions