Skip to content

Commit 54b15b0

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 c74b018 commit 54b15b0

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs

+24
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,10 @@ pub fn typeid_for_instance<'tcx>(
11531153
instance.args = tcx.mk_args_trait(invoke_ty, instance.args.into_iter().skip(1));
11541154
}
11551155

1156+
if matches!(instance.def, InstanceDef::Virtual(..)) {
1157+
instance.args = strip_receiver_auto(tcx, instance.args)
1158+
}
1159+
11561160
let fn_abi = tcx
11571161
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
11581162
.unwrap_or_else(|instance| {
@@ -1161,3 +1165,23 @@ pub fn typeid_for_instance<'tcx>(
11611165

11621166
typeid_for_fnabi(tcx, fn_abi, options)
11631167
}
1168+
1169+
fn strip_receiver_auto<'tcx>(
1170+
tcx: TyCtxt<'tcx>,
1171+
args: ty::GenericArgsRef<'tcx>,
1172+
) -> ty::GenericArgsRef<'tcx> {
1173+
let ty = args.type_at(0);
1174+
let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
1175+
bug!("Tried to strip auto traits from non-dynamic type {ty}");
1176+
};
1177+
let filtered_preds =
1178+
if preds.principal().is_some() {
1179+
tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
1180+
!matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
1181+
}))
1182+
} else {
1183+
ty::List::empty()
1184+
};
1185+
let new_rcvr = Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind);
1186+
tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1))
1187+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Test that we can promote closures / fns to trait objects, and call them despite a marker trait.
2+
3+
//@ needs-sanitizer-cfi
4+
//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi
5+
//@ compile-flags: -C codegen-units=1 -C opt-level=0
6+
//@ run-pass
7+
8+
9+
fn foo() {}
10+
11+
static FOO: &'static (dyn Fn() + Sync) = &foo;
12+
static BAR: &(dyn Fn() -> i32 + Sync) = &|| 3;
13+
14+
fn main() {
15+
FOO();
16+
BAR();
17+
}

0 commit comments

Comments
 (0)