-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Pointer casts allow switching trait parameters for trait objects, which doesn’t interact soundly with trait upcasting #120222
Comments
Between T-lang, T-compiler, and T-types [all 3 listed on the tracking issue], I’m not sure which (or which ones) to assign. |
lcnr on Zulip |
Yes, we should get a de-stabilization PR ASAP to avoid shipping this, and then assess the situation. Is someone working on that? This seems like @rust-lang/lang @rust-lang/types to me; there's no bug in the compiler that I can see. |
There's now a revert up at #120233. |
I think the bug is that we allow casting trait A {} impl<T> A for T {}
trait B {} impl<T> B for T {}
let a: *const dyn A = &();
let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid
trait Trait<G> {}
struct X; impl<T> Trait<X> for T {}
struct Y; impl<T> Trait<Y> for T {}
let x: *const dyn Trait<X> = &();
let y: *const dyn Trait<Y> = x as _; // ok??? (play) The check is here: rust/compiler/rustc_hir_typeck/src/cast.rs Lines 800 to 805 in 366d112
Note that we only compare trait def_id s:rust/compiler/rustc_hir_typeck/src/cast.rs Line 103 in 366d112
I wander how much breakage will cause the change to this... (upd: I'm working on trying this out) |
I believe this to be fairly straightforward by computing the vtable layout once for a fully generic princial, e.g. reusing the same vtable layout for all instances of I still think we should revert and also try @WaffleLapkin's approach. 2 weeks is not enough time to play with any non-trivial fixes 🤔 |
…abilization, r=lcnr Revert stabilization of trait_upcasting feature Reverts rust-lang#118133 This reverts commit 6d2b84b, reversing changes made to 73bc121. The feature has a soundness bug: * rust-lang#120222 It is unclear to me whether we'll actually want to destabilize, but I thought it was still prudent to open the PR for easy destabilization once we get there.
…r=<try> Make casts of pointers to trait objects stricter This is an attempt to `fix` rust-lang#120222 and rust-lang#120217. cc `@oli-obk` `@compiler-errors` `@lcnr`
…abilization, r=lcnr Revert stabilization of trait_upcasting feature Reverts rust-lang#118133 This reverts commit 6d2b84b, reversing changes made to 73bc121. The feature has a soundness bug: * rust-lang#120222 It is unclear to me whether we'll actually want to destabilize, but I thought it was still prudent to open the PR for easy destabilization once we get there.
Rollup merge of rust-lang#120233 - oli-obk:revert_trait_obj_upcast_stabilization, r=lcnr Revert stabilization of trait_upcasting feature Reverts rust-lang#118133 This reverts commit 6d2b84b, reversing changes made to 73bc121. The feature has a soundness bug: * rust-lang#120222 It is unclear to me whether we'll actually want to destabilize, but I thought it was still prudent to open the PR for easy destabilization once we get there.
Adjusting labels to reflect the reverted stabilization of the feature. |
And probably P-critical prioritization can go away eventually. |
dropping the t-types nomination. the stabilization has been reverted and we now have people working on this. While types team members may still be involved, this does not need any team input rn |
…r=<try> Make casts of pointers to trait objects stricter This is an attempt to `fix` rust-lang#120222 and rust-lang#120217. This is done by adding restrictions on casting pointers to trait objects. Currently the restriction is > When casting `*const X<dyn A>` -> `*const Y<dyn B>`, if `B` has a principal trait, `dyn A + 'erased: Unsize<dyn B + 'erased>` must hold This ensures that 1. Principal trait's generic arguments match (no `*const dyn Tr<A>` -> `*const dyn Tr<B>` casts, which are a problem for [rust-lang#120222](rust-lang#120222)) 2. Principal trait's lifetime arguments match (no `*const dyn Tr<'a>` -> `*const dyn Tr<'b>` casts, which are a problem for [rust-lang#120217](rust-lang#120217)) 3. No auto traits can be _added_ (this is a problem for arbitrary self types, see [this comment](rust-lang#120248 (comment))) Some notes: - We only care about the metadata/last field, so you can still cast `*const dyn T` to `*const WithHeader<dyn T>`, etc - The lifetime of the trait object itself (`dyn A + 'lt`) is not checked, so you can still cast `*mut FnOnce() + '_` to `*mut FnOnce() + 'static`, etc - This feels fishy, but I couldn't come up with a reason it must be checked - The new checks are only done if `B` has a principal, so you can still do any kinds of cast, if the target only has auto traits - This is because auto traits are not enough to get unsoundness issues that this PR fixes - ...and so it makes sense to minimize breakage The plan is to, ~~once the checks are properly implemented~~, run crate to determine how much damage does this do. The diagnostics are currently not great, to say the least, but as far as I can tell this correctly fixes the issues. cc `@oli-obk` `@compiler-errors` `@lcnr`
I ran into something where trait upcasting would be the perfect fit. As such I went to look for what was blocking in the tracking PR. It seems that this is the only real blocker? If so, what is the current progress on this (if any)? |
#120248 is making progress on this |
…, r=compiler-errors,oli-obk,lnicola Make casts of pointers to trait objects stricter This is an attempt to `fix` rust-lang#120222 and rust-lang#120217. This is done by adding restrictions on casting pointers to trait objects. Before this PR the rules were as follows: > When casting `*const X<dyn A>` -> `*const Y<dyn B>`, principal traits in `A` and `B` must refer to the same trait definition (or no trait). With this PR the rules are changed to > When casting `*const X<dyn Src>` -> `*const Y<dyn Dst>` > - if `Dst` has a principal trait `DstP`, > - `Src` must have a principal trait `SrcP` > - `dyn SrcP` and `dyn DstP` must be the same type (modulo the trait object lifetime, `dyn T+'a` -> `dyn T+'b` is allowed) > - Auto traits in `Dst` must be a subset of auto traits in `Src` > - Not adhering to this is currently a FCW (warn-by-default + `FutureReleaseErrorReportInDeps`), instead of an error > - if `Src` has a principal trait `Dst` must as well > - this restriction will be removed in a follow up PR This ensures that 1. Principal trait's generic arguments match (no `*const dyn Tr<A>` -> `*const dyn Tr<B>` casts, which are a problem for [rust-lang#120222](rust-lang#120222)) 2. Principal trait's lifetime arguments match (no `*const dyn Tr<'a>` -> `*const dyn Tr<'b>` casts, which are a problem for [rust-lang#120217](rust-lang#120217)) 3. No auto traits can be _added_ (this is a problem for arbitrary self types, see [this comment](rust-lang#120248 (comment))) Some notes: - We only care about the metadata/last field, so you can still cast `*const dyn T` to `*const WithHeader<dyn T>`, etc - The lifetime of the trait object itself (`dyn A + 'lt`) is not checked, so you can still cast `*mut FnOnce() + '_` to `*mut FnOnce() + 'static`, etc - This feels fishy, but I couldn't come up with a reason it must be checked The diagnostics are currently not great, to say the least, but as far as I can tell this correctly fixes the issues. cc `@oli-obk` `@compiler-errors` `@lcnr`
Rollup merge of rust-lang#120248 - WaffleLapkin:bonk-ptr-object-casts, r=compiler-errors,oli-obk,lnicola Make casts of pointers to trait objects stricter This is an attempt to `fix` rust-lang#120222 and rust-lang#120217. This is done by adding restrictions on casting pointers to trait objects. Before this PR the rules were as follows: > When casting `*const X<dyn A>` -> `*const Y<dyn B>`, principal traits in `A` and `B` must refer to the same trait definition (or no trait). With this PR the rules are changed to > When casting `*const X<dyn Src>` -> `*const Y<dyn Dst>` > - if `Dst` has a principal trait `DstP`, > - `Src` must have a principal trait `SrcP` > - `dyn SrcP` and `dyn DstP` must be the same type (modulo the trait object lifetime, `dyn T+'a` -> `dyn T+'b` is allowed) > - Auto traits in `Dst` must be a subset of auto traits in `Src` > - Not adhering to this is currently a FCW (warn-by-default + `FutureReleaseErrorReportInDeps`), instead of an error > - if `Src` has a principal trait `Dst` must as well > - this restriction will be removed in a follow up PR This ensures that 1. Principal trait's generic arguments match (no `*const dyn Tr<A>` -> `*const dyn Tr<B>` casts, which are a problem for [rust-lang#120222](rust-lang#120222)) 2. Principal trait's lifetime arguments match (no `*const dyn Tr<'a>` -> `*const dyn Tr<'b>` casts, which are a problem for [rust-lang#120217](rust-lang#120217)) 3. No auto traits can be _added_ (this is a problem for arbitrary self types, see [this comment](rust-lang#120248 (comment))) Some notes: - We only care about the metadata/last field, so you can still cast `*const dyn T` to `*const WithHeader<dyn T>`, etc - The lifetime of the trait object itself (`dyn A + 'lt`) is not checked, so you can still cast `*mut FnOnce() + '_` to `*mut FnOnce() + 'static`, etc - This feels fishy, but I couldn't come up with a reason it must be checked The diagnostics are currently not great, to say the least, but as far as I can tell this correctly fixes the issues. cc `@oli-obk` `@compiler-errors` `@lcnr`
This is believed to be fixed by: |
…ler-errors,oli-obk,lnicola Make casts of pointers to trait objects stricter This is an attempt to `fix` rust-lang/rust#120222 and rust-lang/rust#120217. This is done by adding restrictions on casting pointers to trait objects. Before this PR the rules were as follows: > When casting `*const X<dyn A>` -> `*const Y<dyn B>`, principal traits in `A` and `B` must refer to the same trait definition (or no trait). With this PR the rules are changed to > When casting `*const X<dyn Src>` -> `*const Y<dyn Dst>` > - if `Dst` has a principal trait `DstP`, > - `Src` must have a principal trait `SrcP` > - `dyn SrcP` and `dyn DstP` must be the same type (modulo the trait object lifetime, `dyn T+'a` -> `dyn T+'b` is allowed) > - Auto traits in `Dst` must be a subset of auto traits in `Src` > - Not adhering to this is currently a FCW (warn-by-default + `FutureReleaseErrorReportInDeps`), instead of an error > - if `Src` has a principal trait `Dst` must as well > - this restriction will be removed in a follow up PR This ensures that 1. Principal trait's generic arguments match (no `*const dyn Tr<A>` -> `*const dyn Tr<B>` casts, which are a problem for [#120222](rust-lang/rust#120222)) 2. Principal trait's lifetime arguments match (no `*const dyn Tr<'a>` -> `*const dyn Tr<'b>` casts, which are a problem for [#120217](rust-lang/rust#120217)) 3. No auto traits can be _added_ (this is a problem for arbitrary self types, see [this comment](rust-lang/rust#120248 (comment))) Some notes: - We only care about the metadata/last field, so you can still cast `*const dyn T` to `*const WithHeader<dyn T>`, etc - The lifetime of the trait object itself (`dyn A + 'lt`) is not checked, so you can still cast `*mut FnOnce() + '_` to `*mut FnOnce() + 'static`, etc - This feels fishy, but I couldn't come up with a reason it must be checked The diagnostics are currently not great, to say the least, but as far as I can tell this correctly fixes the issues. cc `@oli-obk` `@compiler-errors` `@lcnr`
…ler-errors,oli-obk,lnicola Make casts of pointers to trait objects stricter This is an attempt to `fix` rust-lang/rust#120222 and rust-lang/rust#120217. This is done by adding restrictions on casting pointers to trait objects. Before this PR the rules were as follows: > When casting `*const X<dyn A>` -> `*const Y<dyn B>`, principal traits in `A` and `B` must refer to the same trait definition (or no trait). With this PR the rules are changed to > When casting `*const X<dyn Src>` -> `*const Y<dyn Dst>` > - if `Dst` has a principal trait `DstP`, > - `Src` must have a principal trait `SrcP` > - `dyn SrcP` and `dyn DstP` must be the same type (modulo the trait object lifetime, `dyn T+'a` -> `dyn T+'b` is allowed) > - Auto traits in `Dst` must be a subset of auto traits in `Src` > - Not adhering to this is currently a FCW (warn-by-default + `FutureReleaseErrorReportInDeps`), instead of an error > - if `Src` has a principal trait `Dst` must as well > - this restriction will be removed in a follow up PR This ensures that 1. Principal trait's generic arguments match (no `*const dyn Tr<A>` -> `*const dyn Tr<B>` casts, which are a problem for [#120222](rust-lang/rust#120222)) 2. Principal trait's lifetime arguments match (no `*const dyn Tr<'a>` -> `*const dyn Tr<'b>` casts, which are a problem for [#120217](rust-lang/rust#120217)) 3. No auto traits can be _added_ (this is a problem for arbitrary self types, see [this comment](rust-lang/rust#120248 (comment))) Some notes: - We only care about the metadata/last field, so you can still cast `*const dyn T` to `*const WithHeader<dyn T>`, etc - The lifetime of the trait object itself (`dyn A + 'lt`) is not checked, so you can still cast `*mut FnOnce() + '_` to `*mut FnOnce() + 'static`, etc - This feels fishy, but I couldn't come up with a reason it must be checked The diagnostics are currently not great, to say the least, but as far as I can tell this correctly fixes the issues. cc `@oli-obk` `@compiler-errors` `@lcnr`
Pointer casts allow switching trait parameters for trait objects, which can change the set of supertraits (and thus the vtable layout), ultimately making upcasting of raw pointers quite unsound
This code reproduces a segfault, on upcoming stable Rust, starting in
1.76
(stabilization of trait object upcasting).Update: Stabilization was reverted,
1.76
stable Rust is good, the below code examples needs nightly Rust and#[feature(trait_upcasting)]
now.(playground, compiler explorer)
This issue exists next to #120217, but here I’ve found how the issue of overly liberal casting of raw pointers can be made into a concrete soundness issue, using no feature flags, producing an actual segfault.
Whether or now we need (to keep) two separate & somewhat similar GitHub issues can probably become clear eventually. If we don’t, we can always close one or the other.
Miri will already complain with a less sophisticated setup:
(playground)
Three possible ways of fixing this would be to
arbitrary_self_types
receiver…)11.2
, so some potential breakage and/or transition period, …!?)I’m marking as regression in beta as this is newly introduced unsoundness; and an approach like temporarily removing raw pointers again from our upcasting feature (assuming that’s technically possible in the first place) and/or delaying the stabilization are options, in case this soundness issue is perceived as sufficiently relevant not to be “ignored”.
@rustbot label +regression-from-stable-to-beta +F-trait_upcasting +A-coercions +A-trait-objects +I-unsound
Footnotes
my thought here is that e.g. it seems like missing methods are replaced with zeroes already, too, instead of skipped, and that pattern could be extended so that in the case of different sets of supertraits (like the
Super<u8>
==Super<u8> + Super<u8>
vs.Super<u8> + Super<u16>
above) could thus perhaps also avoid supertrait pointers appearing in inconsistent places between an applied trait constructor [Trait<Args1…>
vsTraits<Args2…>
] with different parameters ↩The text was updated successfully, but these errors were encountered: