-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Unconstrained lifetime in associated type using trait object leads to unsound lifetime extension and ICE #130347
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Comments
@rustbot labels +I-unsound |
Another variant: #![feature(type_alias_impl_trait)]
trait A<T>: B<T = T> {}
trait B {
type T;
}
struct Erase<T: ?Sized + B>(T::T);
type Alias = impl for<'a> A<&'a str> + ?Sized;
fn conjure() -> &'static dyn for<'a> A<&'a str> {
unimplemented!()
}
fn dummy() -> &'static Alias {
conjure()
}
fn main() {
let x = {
let x = String::from("hello");
Erase::<Alias>(x.as_str())
};
dbg!(x.0);
} |
With more testing the struct type struct Erase<T: ?Sized + B>(T::T); is important for this issue to be seen. Rustc seems to not have a consistent lifetime given to the |
Obligatory lifetime transmute example. fn make_static<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
trait A<T>: B<T = T> {}
trait B {
type T;
}
struct Erase<T: ?Sized + B>(T::T);
Erase::<dyn for<'c> A<&'c T>>(x).0
}
fn main() {
let s = {
make_static(String::from("hello").as_str())
};
dbg!(s);
} |
A variant that doesn't use the trait A<T>: B<T = T> {}
trait B {
type T;
}
fn foo(a: <dyn for<'a> A<&'a str> as B>::T) -> &'static str {
a
}
fn main() {
let x = foo(String::from("hello").as_str());
dbg!(x);
} |
Also works the other way around: trait A<T>: B<T = T> {}
trait B {
type T;
}
fn foo<'b>(a: &'b str) -> <dyn for<'a> A<&'a str> as B>::T {
a
}
fn main() {
let x = foo(String::from("hello").as_str());
dbg!(x);
} |
The function seems to play the same role of allowing rustc a space to have an undefined lifetime it can assign to anything. |
More experimentation resulted in a ICE. trait A<'a, T: 'a>: B<T, T = &'a T> {
}
trait B<U> {
type T;
}
type Magic<T> = <dyn for<'a> A<'a, T> as B<T>>::T;
fn make_static<'b, T: ?Sized>(a: Magic<T>) -> &'b T {
a
}
fn main() {
let x = make_static(String::from("hello").as_str());
dbg!(x);
} note: no errors encountered even though delayed bugs were created
note: those delayed bugs will now be shown as internal compiler errors
error: internal compiler error: error performing operation: fully_perform
--> src/main.rs:16:13
|
16 | let x = make_static(String::from("hello").as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: delayed at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs:85:25 - disabled backtrace
--> src/main.rs:16:13
|
16 | let x = make_static(String::from("hello").as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md
note: rustc 1.81.0 (eeb90cda1 2024-09-04) running on x86_64-unknown-linux-gnu
note: compiler flags: --crate-type bin -C embed-bitcode=no -C codegen-units=1 -C debuginfo=2
note: some of the compiler flags provided by cargo are hidden
query stack during panic:
end of query stack |
@rustbot labels +I-ICE |
An ICE appears to happen on every version after 1.65.0, but with different messages and locations for almost every version. |
The ice is very old, see #103899 |
I took a quick look at this, and I've got the vague idea of a check to close this soundness hole. I'll put it up for crater soon. |
… r=<try> Check elaborated projections from dyn don't mention unconstrained late bound lifetimes Check that the projections that are *not* explicitly written but which we deduce from elaborating the principal of a `dyn` *also* do not reference unconstrained late-bound lifetimes, just like the ones that the user writes by hand. Fixes rust-lang#130347
WG-prioritization assigning priority (Zulip discussion). @rustbot label -I-prioritize +P-high |
Rollup merge of rust-lang#130367 - compiler-errors:super-unconstrained, r=spastorino Check elaborated projections from dyn don't mention unconstrained late bound lifetimes Check that the projections that are *not* explicitly written but which we deduce from elaborating the principal of a `dyn` *also* do not reference unconstrained late-bound lifetimes, just like the ones that the user writes by hand. That is to say, given: ``` trait Foo<T>: Bar<Assoc = T> {} trait Bar { type Assoc; } ``` The type `dyn for<'a> Foo<&'a T>` (basically) elaborates to `dyn for<'a> Foo<&'a T> + for<'a> Bar<Assoc = &'a T>`[^1]. However, the `Bar` projection predicate is not well-formed, since `'a` must show up in the trait's arguments to be referenced in the term of a projection. We must error in this situation[^well], or else `dyn for<'a> Foo<&'a T>` is unsound. We already detect this for user-written projections during HIR->rustc_middle conversion, so this largely replicates that logic using the helper functions that were already conveniently defined. --- I'm cratering this first to see the fallout; if it's minimal or zero, then let's land it as-is. If not, the way that this is implemented is very conducive to an FCW. --- Fixes rust-lang#130347 [^1]: We don't actually elaborate it like that in rustc; we only keep the principal trait ref `Foo<&'a T>` and the projection part of `Bar<Assoc = ...>`, but it's useful to be a bit verbose here for the purpose of explaining the issue. [^well]: Well, we could also make `dyn for<'a> Foo<&'a T>` *not* implement `for<'a> Bar<Assoc = &'a T>`, but this is inconsistent with the case where the user writes `Assoc = ...` in the type itself, and it overly complicates the implementation of trait objects' built-in impls.
I was playing around with defining higher ranked types using trait objects and tried the following pattern.
To my surprise trait objects of the form
dyn for<'a> A<&'a T>
were allowed. After some experimentation I found that this leads to UB in safe rust.playground
This is likely related to 25860 somehow, but I haven't seen this flavor before.
Meta
This effects all versions from latest nightly to 1.33.0 (on 1.32.0 it causes a ICE, and before it wasn't allowed).
The text was updated successfully, but these errors were encountered: