Skip to content

Commit c7df23d

Browse files
committed
CFI: Strip auto traits from Virtual receivers
As the instance being called is behind a vtable, it cannot depend on auto traits on the receiver (unless the principal trait requires them, in which case the additional constraint is not needed). Removing this causes the type signature of the `Virtual` instance to match the type signature of the `CfiShim`-wrapped entry in the vtable.
1 parent 18d731e commit c7df23d

File tree

4 files changed

+49
-5
lines changed

4 files changed

+49
-5
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
495495
//
496496
let virtual_drop = Instance {
497497
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
498-
args: drop_fn.args,
498+
args: bx.tcx().strip_receiver_auto(drop_fn.args),
499499
};
500500
debug!("ty = {:?}", ty);
501501
debug!("drop_fn = {:?}", drop_fn);
@@ -535,7 +535,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
535535
// SO THEN WE CAN USE THE ABOVE CODE.
536536
let virtual_drop = Instance {
537537
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
538-
args: drop_fn.args,
538+
args: bx.tcx().strip_receiver_auto(drop_fn.args),
539539
};
540540
debug!("ty = {:?}", ty);
541541
debug!("drop_fn = {:?}", drop_fn);

compiler/rustc_middle/src/query/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -2256,6 +2256,13 @@ rustc_queries! {
22562256
query trait_object_ty(trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> {
22572257
desc { "Compute the trait object type for calling a method on a trait" }
22582258
}
2259+
2260+
/// Strip auto traits off the first parameter in the parametr list. Intended for use when
2261+
/// constructing `InstanceDef::Virtual`, as auto traits won't be part of the vtable's `Self`
2262+
/// types.
2263+
query strip_receiver_auto(args: ty::GenericArgsRef<'tcx>) -> ty::GenericArgsRef<'tcx> {
2264+
desc { "Strip auto traits off the first type arg" }
2265+
}
22592266
}
22602267

22612268
rustc_query_append! { define_callbacks! }

compiler/rustc_ty_utils/src/instance.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt;
55
use rustc_middle::query::Providers;
66
use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError};
77
use rustc_middle::ty::GenericArgsRef;
8-
use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt};
8+
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitableExt};
99
use rustc_span::sym;
1010
use rustc_trait_selection::traits;
1111
use traits::{translate_args, Reveal};
@@ -199,7 +199,7 @@ fn resolve_associated_item<'tcx>(
199199
traits::get_vtable_index_of_object_method(tcx, *vtable_base, trait_item_id).map(
200200
|index| Instance {
201201
def: ty::InstanceDef::Virtual(trait_item_id, index),
202-
args: rcvr_args,
202+
args: tcx.strip_receiver_auto(rcvr_args),
203203
},
204204
)
205205
}
@@ -339,6 +339,26 @@ fn resolve_associated_item<'tcx>(
339339
})
340340
}
341341

342+
fn strip_receiver_auto<'tcx>(
343+
tcx: TyCtxt<'tcx>,
344+
args: ty::GenericArgsRef<'tcx>,
345+
) -> ty::GenericArgsRef<'tcx> {
346+
let ty = args.type_at(0);
347+
let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
348+
bug!("Tried to strip auto traits from non-dynamic type {ty}");
349+
};
350+
let filtered_preds =
351+
if preds.principal().is_some() {
352+
tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
353+
!matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
354+
}))
355+
} else {
356+
ty::List::empty()
357+
};
358+
let new_rcvr = Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind);
359+
tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1))
360+
}
361+
342362
pub(crate) fn provide(providers: &mut Providers) {
343-
*providers = Providers { resolve_instance, ..*providers };
363+
*providers = Providers { resolve_instance, strip_receiver_auto, ..*providers };
344364
}
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)