Repository: rust
Issue: Functions, closures, and HRTB-trait-objects can implement traits such that validity of associated types is never checked.
Labels: A-type-system,A-lifetimes,A-trait-system,P-medium,A-closures,A-DSTs,A-associated-items,T-compiler,I-unsound,C-bug,S-bug-has-test,T-types,A-trait-objects,A-higher-ranked

*edit: while this issue has been mostly fixed by #115538, the underlying issue still exists for higher ranked function pointers. It feels highly likely that it can still be exploited, even if the exploit will now be even more involved.*

---

_Make sure to also read through the next few comments of mine, where I present some other, significantly different examples of related problems (that’s where HRTBs become relevant, and closures, fn-pointers and trait objects play a role). I also explain the T-lang tag there with a question on changing the meaning of HRTBs that include associated types. Possibly it’s even a sensible thing to split this issue up into two issues._

So if I write a function such as
```rust
fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> {
    PhantomData
}
```
then `foo`’s return type is only valid if `'a: 'b`. When we call the function this is enforced a the call site, e.g.
```rust
fn caller<'b, 'a>() {
    foo::<'b, 'a>();
}
```
doesn’t work, with
```rust
error[E0491]: in type `&'b &'a ()`, reference has a longer lifetime than the data it references
 --> src/lib.rs:8:5
  |
8 |     foo::<'b, 'a>();
  |     ^^^^^^^^^^^^^^^
  |
note: the pointer is valid for the lifetime `'b` as defined on the function body at 7:11
 --> src/lib.rs:7:11
  |
7 | fn caller<'b, 'a>() {
  |           ^^
note: but the referenced data is only valid for the lifetime `'a` as defined on the function body at 7:15
 --> src/lib.rs:7:15
  |
7 | fn caller<'b, 'a>() {
  |               ^^

error: aborting due to previous error
```
([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0735b1090d7b275ab12a940867788c5f))

However, if we _just_ instantiate the lifetime parameters, there’s apparently no check being performed at all, i.e.
```rust
fn caller<'b, 'a>() {
    foo::<'b, 'a>;
}
```
compiles just fine. ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=efe80b69733df331716f18eea6f4130c)).

This seems questionable, the type of `foo::<'b, 'a>` implements `FnOnce` with `Output = PhantomData<&'b &'a ()>`, and it is in fact possible to use this output type to circumvent the borrow checker:
```rust
use std::marker::PhantomData;

fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> {
    PhantomData
}

fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
    let f = foo::<'b, 'a>;
    f.baz(x)
}

trait Foo<'a, 'b, T: ?Sized> {
    fn baz(self, s: &'a T) -> &'b T;
}
impl<'a, 'b, R, F, T: ?Sized> Foo<'a, 'b, T> for F
where
    F: Fn() -> R,
    R: ProofForConversion<'a, 'b, T>,
{
    fn baz(self, s: &'a T) -> &'b T {
        self().convert(s)
    }
}

trait ProofForConversion<'a, 'b, T: ?Sized> {
    fn convert(self, s: &'a T) -> &'b T;
}
impl<'a, 'b, T: ?Sized> ProofForConversion<'a, 'b, T> for PhantomData<&'b &'a ()> {
    fn convert(self, s: &'a T) -> &'b T {
        s
    }
}

fn main() {
    let d;
    {
        let x = "Hello World".to_string();
        d = extend_lifetime(&x);
    }
    println!("{}", d);
}
```
```
�ZV&V
```
([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5167c528f2e0dfa4a4fbe5af4e20c081))

@rustbot modify labels: A-lifetimes, A-typesystem, T-compiler
and someone please add “I-unsound 💥”.