Skip to content

Commit c9ff274

Browse files
committed
CFI: Introduce CFI shims
Indirect calls through vtables (trait objects or drop_in_place) expect to have an alias set based on `dyn Trait` at the call-site. The actual implementations have aslias sets based on `MyImplType`. These shims create a separate `InstanceDef`, allowing a different type to be assigned. These function for both CFI and KCFI, as they have a single principal type.
1 parent 8aaa391 commit c9ff274

File tree

19 files changed

+193
-23
lines changed

19 files changed

+193
-23
lines changed

compiler/rustc_const_eval/src/interpret/terminator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
558558
| ty::InstanceDef::CloneShim(..)
559559
| ty::InstanceDef::FnPtrAddrShim(..)
560560
| ty::InstanceDef::ThreadLocalShim(..)
561+
| ty::InstanceDef::CfiShim { .. }
561562
| ty::InstanceDef::Item(_) => {
562563
// We need MIR for this fn
563564
let Some((body, instance)) = M::find_mir_or_eval_fn(

compiler/rustc_middle/src/mir/mono.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,8 @@ impl<'tcx> CodegenUnit<'tcx> {
406406
| InstanceDef::DropGlue(..)
407407
| InstanceDef::CloneShim(..)
408408
| InstanceDef::ThreadLocalShim(..)
409-
| InstanceDef::FnPtrAddrShim(..) => None,
409+
| InstanceDef::FnPtrAddrShim(..)
410+
| InstanceDef::CfiShim { .. } => None,
410411
}
411412
}
412413
MonoItem::Static(def_id) => def_id.as_local().map(Idx::index),

compiler/rustc_middle/src/mir/visit.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,21 @@ macro_rules! make_mir_visitor {
940940
// FIXME(eddyb) use a better `TyContext` here.
941941
self.visit_ty($(& $mutability *)? ty, TyContext::Location(location));
942942
}
943+
ty::InstanceDef::CfiShim { target_instance, invoke_ty } => {
944+
self.visit_ty($(& $mutability *)? invoke_ty, TyContext::Location(location));
945+
let $($mutability)? local_target_instance = {
946+
$(
947+
let $mutability _unused = ();
948+
*
949+
)?
950+
*target_instance
951+
};
952+
self.visit_instance_def($(& $mutability)? local_target_instance);
953+
$(
954+
*target_instance = self.tcx().arena.alloc(local_target_instance);
955+
let $mutability _unused = ();
956+
)?
957+
}
943958
}
944959
}
945960

compiler/rustc_middle/src/ty/codec.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ impl_arena_copy_decoder! {<'tcx>
536536
rustc_span::def_id::LocalDefId,
537537
(rustc_middle::middle::exported_symbols::ExportedSymbol<'tcx>, rustc_middle::middle::exported_symbols::SymbolExportInfo),
538538
ty::DeducedParamAttrs,
539+
ty::InstanceDef<'tcx>,
539540
}
540541

541542
#[macro_export]

compiler/rustc_middle/src/ty/instance.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
22
use crate::ty::print::{FmtPrinter, Printer};
33
use crate::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
4-
use crate::ty::{EarlyBinder, GenericArgs, GenericArgsRef, TypeVisitableExt};
4+
use crate::ty::{EarlyBinder, GenericArgs, GenericArgsRef, Lift, TypeVisitableExt};
55
use rustc_errors::ErrorGuaranteed;
66
use rustc_hir as hir;
77
use rustc_hir::def::Namespace;
@@ -135,6 +135,14 @@ pub enum InstanceDef<'tcx> {
135135
///
136136
/// The `DefId` is for `FnPtr::addr`, the `Ty` is the type `T`.
137137
FnPtrAddrShim(DefId, Ty<'tcx>),
138+
139+
/// Typecast shim which replaces the `Self` type with the provided type.
140+
/// This is used in vtable calls, where the type of `Self` is abstract as of the time of
141+
/// the call.
142+
///
143+
/// `target_instance` will be an instantiable `InstanceDef`, either an `Item` for which
144+
/// we have MIR available or a generatable shim.
145+
CfiShim { target_instance: &'tcx InstanceDef<'tcx>, invoke_ty: Ty<'tcx> },
138146
}
139147

140148
impl<'tcx> Instance<'tcx> {
@@ -198,6 +206,7 @@ impl<'tcx> InstanceDef<'tcx> {
198206
| InstanceDef::DropGlue(def_id, _)
199207
| InstanceDef::CloneShim(def_id, _)
200208
| InstanceDef::FnPtrAddrShim(def_id, _) => def_id,
209+
InstanceDef::CfiShim { target_instance, .. } => target_instance.def_id(),
201210
}
202211
}
203212

@@ -209,6 +218,7 @@ impl<'tcx> InstanceDef<'tcx> {
209218
Some(def_id)
210219
}
211220
InstanceDef::VTableShim(..)
221+
| InstanceDef::CfiShim { .. }
212222
| InstanceDef::ReifyShim(..)
213223
| InstanceDef::FnPtrShim(..)
214224
| InstanceDef::Virtual(..)
@@ -319,6 +329,17 @@ impl<'tcx> InstanceDef<'tcx> {
319329
| InstanceDef::ReifyShim(..)
320330
| InstanceDef::Virtual(..)
321331
| InstanceDef::VTableShim(..) => true,
332+
InstanceDef::CfiShim { target_instance, .. } => {
333+
target_instance.has_polymorphic_mir_body()
334+
}
335+
}
336+
}
337+
338+
pub fn is_vtable_shim(&self) -> bool {
339+
match self {
340+
InstanceDef::VTableShim(..) => true,
341+
InstanceDef::CfiShim { target_instance, .. } => target_instance.is_vtable_shim(),
342+
_ => false,
322343
}
323344
}
324345
}
@@ -339,6 +360,10 @@ fn fmt_instance_def(f: &mut fmt::Formatter<'_>, instance_def: &InstanceDef<'_>)
339360
InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"),
340361
InstanceDef::CloneShim(_, ty) => write!(f, " - shim({ty})"),
341362
InstanceDef::FnPtrAddrShim(_, ty) => write!(f, " - shim({ty})"),
363+
InstanceDef::CfiShim { invoke_ty, target_instance } => {
364+
fmt_instance_def(f, target_instance)?;
365+
write!(f, " - cfi-shim({invoke_ty})")
366+
}
342367
}
343368
}
344369

@@ -579,6 +604,34 @@ impl<'tcx> Instance<'tcx> {
579604
Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args)
580605
}
581606

607+
pub fn cfi_shim(
608+
mut self,
609+
tcx: TyCtxt<'tcx>,
610+
invoke_trait: Option<ty::PolyTraitRef<'tcx>>,
611+
) -> ty::Instance<'tcx> {
612+
if tcx.sess.cfi_shims() {
613+
let invoke_ty = if let Some(poly_trait_ref) = invoke_trait {
614+
tcx.trait_object_ty(poly_trait_ref)
615+
} else {
616+
Ty::new_dynamic(tcx, ty::List::empty(), tcx.lifetimes.re_erased, ty::Dyn)
617+
};
618+
// If we're an Item and the `def_id` is not local, we may not have MIR available.
619+
// If it's a closure, we can't ReifyShim it, just use it directly.
620+
if let InstanceDef::Item(def_id) = self.def
621+
&& !def_id.is_local()
622+
&& !tcx.is_closure_like(def_id)
623+
{
624+
self.def = InstanceDef::ReifyShim(def_id);
625+
}
626+
627+
self.def = InstanceDef::CfiShim {
628+
target_instance: (&self.def).lift_to_tcx(tcx).expect("Could not lift for shimming"),
629+
invoke_ty,
630+
};
631+
}
632+
self
633+
}
634+
582635
#[instrument(level = "debug", skip(tcx), ret)]
583636
pub fn fn_once_adapter_instance(
584637
tcx: TyCtxt<'tcx>,

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,6 +1730,7 @@ impl<'tcx> TyCtxt<'tcx> {
17301730
| ty::InstanceDef::CloneShim(..)
17311731
| ty::InstanceDef::ThreadLocalShim(..)
17321732
| ty::InstanceDef::FnPtrAddrShim(..) => self.mir_shims(instance),
1733+
ty::InstanceDef::CfiShim { target_instance, .. } => self.instance_mir(*target_instance),
17331734
}
17341735
}
17351736

compiler/rustc_middle/src/ty/structural_impls.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,14 @@ impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
479479
}
480480
}
481481

482+
impl<'a, 'b, 'tcx> Lift<'tcx> for &'b ty::InstanceDef<'a> {
483+
type Lifted = &'tcx ty::InstanceDef<'tcx>;
484+
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
485+
let lifted: ty::InstanceDef<'tcx> = (*self).lift_to_tcx(tcx)?;
486+
Some(tcx.arena.alloc(lifted))
487+
}
488+
}
489+
482490
///////////////////////////////////////////////////////////////////////////
483491
// Traversal implementations.
484492

@@ -488,6 +496,22 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::AdtDef<'tcx> {
488496
}
489497
}
490498

499+
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for &ty::InstanceDef<'tcx> {
500+
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
501+
(*self).visit_with(visitor)
502+
}
503+
}
504+
505+
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::InstanceDef<'tcx> {
506+
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
507+
self,
508+
folder: &mut F,
509+
) -> Result<Self, F::Error> {
510+
let folded: ty::InstanceDef<'tcx> = (*self).try_fold_with(folder)?;
511+
Ok(folder.interner().arena.alloc(folded))
512+
}
513+
}
514+
491515
impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> TypeFoldable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
492516
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
493517
self,

compiler/rustc_mir_transform/src/inline.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,8 @@ impl<'tcx> Inliner<'tcx> {
331331
| InstanceDef::DropGlue(..)
332332
| InstanceDef::CloneShim(..)
333333
| InstanceDef::ThreadLocalShim(..)
334-
| InstanceDef::FnPtrAddrShim(..) => return Ok(()),
334+
| InstanceDef::FnPtrAddrShim(..)
335+
| InstanceDef::CfiShim { .. } => return Ok(()),
335336
}
336337

337338
if self.tcx.is_constructor(callee_def_id) {

compiler/rustc_mir_transform/src/inline/cycle.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
9090
| InstanceDef::ConstructCoroutineInClosureShim { .. }
9191
| InstanceDef::CoroutineKindShim { .. }
9292
| InstanceDef::ThreadLocalShim { .. }
93-
| InstanceDef::CloneShim(..) => {}
93+
| InstanceDef::CloneShim(..)
94+
| InstanceDef::CfiShim { .. } => {}
9495

9596
// This shim does not call any other functions, thus there can be no recursion.
9697
InstanceDef::FnPtrAddrShim(..) => continue,

compiler/rustc_mir_transform/src/shim.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
3131

3232
let mut result = match instance {
3333
ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
34+
ty::InstanceDef::CfiShim { .. } => bug!("cfi shim {instance:?} passed to make_shim"),
3435
ty::InstanceDef::VTableShim(def_id) => {
3536
let adjustment = Adjustment::Deref { source: DerefSource::MutPtr };
3637
build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id))

0 commit comments

Comments
 (0)