-
Notifications
You must be signed in to change notification settings - Fork 13k
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
interpret: adjust vtable validity check for higher-ranked types #135296
base: master
Are you sure you want to change the base?
Conversation
Some changes occurred to the CTFE machinery cc @rust-lang/wg-const-eval The Miri subtree was changed cc @rust-lang/miri Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri |
dcdc06e
to
0536ee7
Compare
This comment has been minimized.
This comment has been minimized.
0536ee7
to
a7d6eae
Compare
#[instrument(level = "trace", skip(self), ret)] | ||
pub(super) fn eq_in_param_env<T>(&self, a: T, b: T) -> bool | ||
pub(super) fn relate_dyn_predicates_bivariantly<T>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bivariance is different from being bidirectional subtypes
change it to eq_modulo_regions
? 🤔
👍 on manually adding the leak-check here. The alternative would be to instantiate all regions with existentials and do a proper region check at the end, not totally sure whether a leak-check will always be sufficient given that it doesn't have to be catch all errors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bivariance is different from being bidirectional subtypes
Hm, this comment here made me believe that they are supposed to be the same:
rust/compiler/rustc_infer/src/infer/at.rs
Lines 241 to 246 in 336209e
// We could make this make sense but it's not readily | |
// exposed and I don't feel like dealing with it. Note | |
// that bivariance in general does a bit more than just | |
// *nothing*, it checks that the types are the same | |
// "modulo variance" basically. | |
ty::Bivariant => panic!("Bivariant given to `relate()`"), |
I see now that bivariance as implemented does indeed just do nothing, so 👍 on renaming this to avoid confusion.
Also, after thinking about this more, I think we can also just structurally compare the predicates (after instantiating the binder + normalizing), no leak check required, because the soundness of TypeId
requires structural equality anyway (#97156).
Is there any reason why this would be a bad idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, this comment here made me believe that they are supposed to be the same:
This comment is wrong then 😁
Also, after thinking about this more, I think we can also just structurally compare the predicates (after instantiating the binder + normalizing), no leak check required, because the soundness of TypeId requires structural equality anyway (#97156).
Is there any reason why this would be a bad idea?
don't think so, would have some false negatives in generic code, but 🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, replaced this with just ==
now.
#[instrument(level = "trace", skip(self), ret)] | ||
pub(super) fn eq_in_param_env<T>(&self, a: T, b: T) -> bool | ||
pub(super) fn relate_dyn_predicates_bivariantly<T>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a better place for this function? Somewhere in rustc_ty_utils or whatever? I am entirely clueless about its implementation so maybe const_eval is the wrong crate for this. ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is gone now, because turns out that this entire complicated operation is (almost) just equivalent to ==
^^
src/tools/miri/tests/pass/validity/dyn-trait-bivariant-transmutes.rs
Outdated
Show resolved
Hide resolved
src/tools/miri/tests/pass/validity/dyn-trait-bivariant-transmutes.rs
Outdated
Show resolved
Hide resolved
a7d6eae
to
a7c9e79
Compare
The rustc-dev-guide subtree was changed. If this PR only touches the dev guide consider submitting a PR directly to rust-lang/rustc-dev-guide otherwise thank you for updating the dev guide with your changes. cc @BoxyUwU, @jieyouxu, @Kobzol Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 Some changes occurred in compiler/rustc_codegen_gcc |
(this now includes #135318 to avoid conflicts, sorry for the pings) |
a7c9e79
to
cc20826
Compare
cc20826
to
ed1eb06
Compare
What
Transmuting between trait objects where a generic argument or associated type only differs in bound regions (not bound at or above the trait object's binder) is now UB. For example
&dyn Trait<for<'a> fn(&'a u8)>
and&dyn Trait<fn(&'static u8)>
is UB.&dyn Trait<Assoc = for<'a> fn(&'a u8)>
and&dyn Trait<Assoc = fn(&'static u8)>
is UB.&dyn Trait<for<'a> fn(&'a u8) -> (&'a u8, &'static u8)>
and&dyn Trait<for<'a> fn(&'a u8) -> (&'static u8, &'a u8)>
is UB.Transmuting between subtypes (in either direction) is still allowed, which means that bound regions that are bound at or above the trait object's binder can still be changed:
&dyn for<'a> Trait<fn(&'a u8)>
and&dyn for Trait<fn(&'static u8)>
is fine.&dyn for<'a> Trait<dyn Trait<fn(&'a u8)>>
and&dyn for Trait<dyn Trait<fn(&'static u8)>>
is fine.Why
Very similar to #120217 and #120222, changing a trait object's generic argument to a type that only differs in bound regions can still affect the vtable layout and lead to segfaults at runtime (for an example see
src/tools/miri/tests/fail/validity/dyn-trait-leak-check.rs
).Since we already already require that the trait object predicates must be equal modulo bound regions, it is only natural to extend this check to also require type equality considering bound regions.
However, it also makes sense to allow transmutes between a type and a subtype thereof. For example
&dyn for<'a> Trait<&'a u8>
is a subtype of&dyn Trait<&'static ()>
and they are guaranteed to have the same vtable, so it makes sense to allow this transmute. So that's why bound lifetimes that are bound to the trait object itself are treated as free lifetime for the purpose of this check.Note that codegen already relies on the property that subtyping cannot change the the vtable and this is asserted here (note the leak check):
rust/compiler/rustc_codegen_ssa/src/base.rs
Lines 106 to 153 in 251206c
Furthermore, we allow some pointer-to-pointer casts like
*const dyn for<'a> Trait<&'a u8>
to*const Wrapper<dyn Trait<&'static u8>>
that instantiate the trait object binder and are currently lowered to a single pointer-to-pointer cast in MIR (CastKind::PtrToPtr
) and not an unsizing coercion (CastKind::PointerCoercion(Unsize)
), so the current MIR lowering of these would be UB if we didn't allow subtyping transmutes.fixes #135230
cc @rust-lang/opsem
r? @compiler-errors for the implementation