HRTB on subtrait unsoundly provides HTRB on supertrait with weaker implied bounds · Issue #84591 · rust-lang/rust (original) (raw)
I’m giving an exploitation below at the end of this description. This is my interpretation of where exactly the unsoundness lies:
If I have a trait hierarchy
trait Subtrait<'a, 'b, R>: Supertrait<'a, 'b> {} trait Supertrait<'a, 'b> {}
then a higher ranked trait bound (HRTB) like this
for<'a, 'b> Subtrait<'a, 'b, &'b &'a ()>
does/should only apply to such lifetimes 'a
, 'b
that fulfill the outlives-relation 'a: 'b
.
('a: 'b
is needed for &'b &'a ()
to be a valid type.)
However, the bound
for<'a, 'b> Subtrait<'a, 'b, &'b &'a ()>
appears to imply the bound
for<'a, 'b> Supertrait<'a, 'b>,
and in this one, the lifetimes 'a
and 'b
are universally quantified without any implicit outlives-relation.
This implication is demonstrated below:
fn need_hrtb_subtrait()
where
S: for<'a, 'b> Subtrait<'a, 'b, &'b &'a ()>,
{
need_hrtb_supertrait::() // <- this call works
}
fn need_hrtb_supertrait()
where
S: for<'a, 'b> Supertrait<'a, 'b>,
{
}
One could of course debate whether for<'a, 'b> Subtrait<'a, 'b, &'b &'a ()>
should perhaps in-fact include a for<'a, 'b> Supertrait<'a, 'b>
bound, but that seems kind-of weird IMO, and also the following code demonstrates that you only need Supertrait<'a, 'b>
with 'a: 'b
for a fully generic Subtrait<'a, 'b, &'b &'a ()>
implementation:
struct MyStruct; impl<'a: 'b, 'b> Supertrait<'a, 'b> for MyStruct {} impl<'a, 'b> Subtrait<'a, 'b, &'b &'a ()> for MyStruct {}
fn main() { need_hrtb_subtrait::(); }
Finally, here’s how to turn this into actual UB:
trait Subtrait<'a, 'b, R>: Supertrait<'a, 'b> {} trait Supertrait<'a, 'b> { fn convert<T: ?Sized>(x: &'a T) -> &'b T; }
fn need_hrtb_subtrait<'a_, 'b_, S, T: ?Sized>(x: &'a_ T) -> &'b_ T where S: for<'a, 'b> Subtrait<'a, 'b, &'b &'a ()>, { need_hrtb_supertrait::<S, T>(x) // <- this call works }
fn need_hrtb_supertrait<'a_, 'b_, S, T: ?Sized>(x: &'a_ T) -> &'b_ T where S: for<'a, 'b> Supertrait<'a, 'b>, { S::convert(x) }
struct MyStruct; impl<'a: 'b, 'b> Supertrait<'a, 'b> for MyStruct { fn convert<T: ?Sized>(x: &'a T) -> &'b T { x } } impl<'a, 'b> Subtrait<'a, 'b, &'b &'a ()> for MyStruct {}
fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { need_hrtb_subtrait::<MyStruct, T>(x) }
fn main() { let d; { let x = "Hello World".to_string(); d = extend_lifetime(&x); } println!("{}", d); }
This demonstration compiles since Rust 1.7
.
@rustbot modify labels: T-compiler, A-traits, A-lifetimes, A-typesystem
and someone please add “I-unsound 💥”.