Skip to content

Commit 042e05b

Browse files
committed
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.
1 parent 90e363a commit 042e05b

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

compiler/rustc_symbol_mangling/src/typeid.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub fn typeid_for_instance<'tcx>(
3636
instance: &Instance<'tcx>,
3737
options: TypeIdOptions,
3838
) -> String {
39-
typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options)
39+
typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options)
4040
}
4141

4242
/// Returns a KCFI type metadata identifier for the specified FnAbi.
@@ -61,6 +61,6 @@ pub fn kcfi_typeid_for_instance<'tcx>(
6161
// A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
6262
// xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
6363
let mut hash: XxHash64 = Default::default();
64-
hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes());
64+
hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options).as_bytes());
6565
hash.finish() as u32
6666
}

compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -1087,11 +1087,15 @@ pub fn typeid_for_fnabi<'tcx>(
10871087
/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary.
10881088
pub fn typeid_for_instance<'tcx>(
10891089
tcx: TyCtxt<'tcx>,
1090-
instance: &Instance<'tcx>,
1090+
mut instance: Instance<'tcx>,
10911091
options: TypeIdOptions,
10921092
) -> String {
1093+
if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
1094+
instance.args = strip_receiver_auto(tcx, instance.args)
1095+
}
1096+
10931097
let fn_abi = tcx
1094-
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, ty::List::empty())))
1098+
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
10951099
.unwrap_or_else(|instance| {
10961100
bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
10971101
});
@@ -1137,3 +1141,23 @@ pub fn typeid_for_instance<'tcx>(
11371141

11381142
typeid_for_fnabi(tcx, fn_abi, options)
11391143
}
1144+
1145+
fn strip_receiver_auto<'tcx>(
1146+
tcx: TyCtxt<'tcx>,
1147+
args: ty::GenericArgsRef<'tcx>,
1148+
) -> ty::GenericArgsRef<'tcx> {
1149+
let ty = args.type_at(0);
1150+
let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
1151+
bug!("Tried to strip auto traits from non-dynamic type {ty}");
1152+
};
1153+
let filtered_preds =
1154+
if preds.principal().is_some() {
1155+
tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
1156+
!matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
1157+
}))
1158+
} else {
1159+
ty::List::empty()
1160+
};
1161+
let new_rcvr = Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind);
1162+
tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1))
1163+
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Tests that calling a trait object method on a trait object with additional auto traits works.
2+
3+
//@ needs-sanitizer-cfi
4+
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
5+
//@ only-linux
6+
//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi
7+
//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0
8+
//@ run-pass
9+
10+
trait Foo {
11+
fn foo(&self);
12+
}
13+
14+
struct Bar;
15+
impl Foo for Bar {
16+
fn foo(&self) {}
17+
}
18+
19+
pub fn main() {
20+
let x: &(dyn Foo + Send) = &Bar;
21+
x.foo();
22+
}

0 commit comments

Comments
 (0)