mirror of https://github.com/rust-lang/rust.git
CFI: Strip auto traits off Self for virtual calls
Additional trait bounds beyond the principal trait and its implications are not possible in the vtable. This means that if a receiver is `&dyn Foo + Send`, the function will only be expecting `&dyn Foo`. This strips those auto traits off before CFI encoding.
This commit is contained in:
parent
7967915c7b
commit
f434c27067
|
@ -36,7 +36,7 @@ pub fn typeid_for_instance<'tcx>(
|
|||
instance: &Instance<'tcx>,
|
||||
options: TypeIdOptions,
|
||||
) -> String {
|
||||
typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options)
|
||||
typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options)
|
||||
}
|
||||
|
||||
/// Returns a KCFI type metadata identifier for the specified FnAbi.
|
||||
|
@ -61,6 +61,6 @@ pub fn kcfi_typeid_for_instance<'tcx>(
|
|||
// A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
|
||||
// xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
|
||||
let mut hash: XxHash64 = Default::default();
|
||||
hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes());
|
||||
hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options).as_bytes());
|
||||
hash.finish() as u32
|
||||
}
|
||||
|
|
|
@ -1088,11 +1088,15 @@ pub fn typeid_for_fnabi<'tcx>(
|
|||
/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary.
|
||||
pub fn typeid_for_instance<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: &Instance<'tcx>,
|
||||
mut instance: Instance<'tcx>,
|
||||
options: TypeIdOptions,
|
||||
) -> String {
|
||||
if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
|
||||
instance.args = strip_receiver_auto(tcx, instance.args)
|
||||
}
|
||||
|
||||
let fn_abi = tcx
|
||||
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, ty::List::empty())))
|
||||
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
|
||||
.unwrap_or_else(|instance| {
|
||||
bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
|
||||
});
|
||||
|
@ -1138,3 +1142,23 @@ pub fn typeid_for_instance<'tcx>(
|
|||
|
||||
typeid_for_fnabi(tcx, fn_abi, options)
|
||||
}
|
||||
|
||||
fn strip_receiver_auto<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> ty::GenericArgsRef<'tcx> {
|
||||
let ty = args.type_at(0);
|
||||
let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
|
||||
bug!("Tried to strip auto traits from non-dynamic type {ty}");
|
||||
};
|
||||
let filtered_preds =
|
||||
if preds.principal().is_some() {
|
||||
tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
|
||||
!matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
|
||||
}))
|
||||
} else {
|
||||
ty::List::empty()
|
||||
};
|
||||
let new_rcvr = Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind);
|
||||
tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Tests that calling a trait object method on a trait object with additional auto traits works.
|
||||
|
||||
//@ needs-sanitizer-cfi
|
||||
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
|
||||
//@ only-linux
|
||||
//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi
|
||||
//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0
|
||||
//@ run-pass
|
||||
|
||||
trait Foo {
|
||||
fn foo(&self);
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
impl Foo for Bar {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let x: &(dyn Foo + Send) = &Bar;
|
||||
x.foo();
|
||||
}
|
Loading…
Reference in New Issue