Skip to content

Commit 6aa89f6

Browse files
committed
Track reason for creating a ReifyShim
KCFI needs to be able to tell which kind of `ReifyShim` it is examining in order to decide whether to use a concrete type (`FnPtr` case) or an abstract case (`Vtable` case). You can *almost* tell this from context, but there is one case where you can't - if a trait has a method which is *not* `#[track_caller]`, with an impl that *is* `#[track_caller]`, both the vtable and a function pointer created from that method will be `ReifyShim(def_id)`. Currently, the reason is optional to ensure no additional unique `ReifyShim`s are added without KCFI on. However, the case in which an extra `ReifyShim` is created is sufficiently rare that this may be worth revisiting to reduce complexity.
1 parent 93c2bac commit 6aa89f6

File tree

9 files changed

+60
-19
lines changed

9 files changed

+60
-19
lines changed

compiler/rustc_middle/src/mir/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ macro_rules! make_mir_visitor {
341341

342342
ty::InstanceDef::Intrinsic(_def_id) |
343343
ty::InstanceDef::VTableShim(_def_id) |
344-
ty::InstanceDef::ReifyShim(_def_id) |
344+
ty::InstanceDef::ReifyShim(_def_id, _) |
345345
ty::InstanceDef::Virtual(_def_id, _) |
346346
ty::InstanceDef::ThreadLocalShim(_def_id) |
347347
ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |

compiler/rustc_middle/src/ty/instance.rs

+40-8
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,28 @@ pub struct Instance<'tcx> {
3131
pub args: GenericArgsRef<'tcx>,
3232
}
3333

34+
/// Describes why a `ReifyShim` was created. This is needed to distingish a ReifyShim created to
35+
/// adjust for things like `#[track_caller]` in a vtable from a `ReifyShim` created to produce a
36+
/// function pointer from a vtable entry.
37+
/// Currently, this is only used when KCFI is enabled, as only KCFI needs to treat those two
38+
/// `ReifyShim`s differently.
39+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
40+
#[derive(TyEncodable, TyDecodable, HashStable)]
41+
pub enum ReifyReason {
42+
/// The `ReifyShim` was created to produce a function pointer. This happens when:
43+
/// * A vtable entry is directly converted to a function call (e.g. creating a fn ptr from a
44+
/// method on a `dyn` object).
45+
/// * A function with `#[track_caller]` is converted to a function pointer
46+
/// * If KCFI is enabled, creating a function pointer from a method on an object-safe trait.
47+
/// This includes the case of converting `::call`-like methods on closure-likes to function
48+
/// pointers.
49+
FnPtr,
50+
/// This `ReifyShim` was created to populate a vtable. Currently, this happens when a
51+
/// `#[track_caller]` mismatch occurs between the implementation of a method and the method.
52+
/// This includes the case of `::call`-like methods in closure-likes' vtables.
53+
Vtable,
54+
}
55+
3456
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
3557
#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
3658
pub enum InstanceDef<'tcx> {
@@ -67,7 +89,13 @@ pub enum InstanceDef<'tcx> {
6789
/// Because this is a required part of the function's ABI but can't be tracked
6890
/// as a property of the function pointer, we use a single "caller location"
6991
/// (the definition of the function itself).
70-
ReifyShim(DefId),
92+
///
93+
/// The second field encodes *why* this shim was created. This allows distinguishing between
94+
/// a `ReifyShim` that appears in a vtable vs one that appears as a function pointer.
95+
///
96+
/// This field will only be populated if we are compiling in a mode that needs these shims
97+
/// to be separable, currently only when KCFI is enabled.
98+
ReifyShim(DefId, Option<ReifyReason>),
7199

72100
/// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers).
73101
///
@@ -194,7 +222,7 @@ impl<'tcx> InstanceDef<'tcx> {
194222
match self {
195223
InstanceDef::Item(def_id)
196224
| InstanceDef::VTableShim(def_id)
197-
| InstanceDef::ReifyShim(def_id)
225+
| InstanceDef::ReifyShim(def_id, _)
198226
| InstanceDef::FnPtrShim(def_id, _)
199227
| InstanceDef::Virtual(def_id, _)
200228
| InstanceDef::Intrinsic(def_id)
@@ -354,7 +382,9 @@ fn fmt_instance(
354382
match instance.def {
355383
InstanceDef::Item(_) => Ok(()),
356384
InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"),
357-
InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"),
385+
InstanceDef::ReifyShim(_, None) => write!(f, " - shim(reify)"),
386+
InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => write!(f, " - shim(reify-fnptr)"),
387+
InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => write!(f, " - shim(reify-vtable)"),
358388
InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"),
359389
InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"),
360390
InstanceDef::Virtual(_, num) => write!(f, " - virtual#{num}"),
@@ -476,15 +506,16 @@ impl<'tcx> Instance<'tcx> {
476506
debug!("resolve(def_id={:?}, args={:?})", def_id, args);
477507
// Use either `resolve_closure` or `resolve_for_vtable`
478508
assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}");
509+
let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr);
479510
Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
480511
match resolved.def {
481512
InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => {
482513
debug!(" => fn pointer created for function with #[track_caller]");
483-
resolved.def = InstanceDef::ReifyShim(def);
514+
resolved.def = InstanceDef::ReifyShim(def, reason);
484515
}
485516
InstanceDef::Virtual(def_id, _) => {
486517
debug!(" => fn pointer created for virtual call");
487-
resolved.def = InstanceDef::ReifyShim(def_id);
518+
resolved.def = InstanceDef::ReifyShim(def_id, reason);
488519
}
489520
_ => {}
490521
}
@@ -508,6 +539,7 @@ impl<'tcx> Instance<'tcx> {
508539
debug!(" => associated item with unsizeable self: Self");
509540
Some(Instance { def: InstanceDef::VTableShim(def_id), args })
510541
} else {
542+
let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable);
511543
Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| {
512544
match resolved.def {
513545
InstanceDef::Item(def) => {
@@ -544,18 +576,18 @@ impl<'tcx> Instance<'tcx> {
544576
// Create a shim for the `FnOnce/FnMut/Fn` method we are calling
545577
// - unlike functions, invoking a closure always goes through a
546578
// trait.
547-
resolved = Instance { def: InstanceDef::ReifyShim(def_id), args };
579+
resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args };
548580
} else {
549581
debug!(
550582
" => vtable fn pointer created for function with #[track_caller]: {:?}", def
551583
);
552-
resolved.def = InstanceDef::ReifyShim(def);
584+
resolved.def = InstanceDef::ReifyShim(def, reason);
553585
}
554586
}
555587
}
556588
InstanceDef::Virtual(def_id, _) => {
557589
debug!(" => vtable fn pointer created for virtual call");
558-
resolved.def = InstanceDef::ReifyShim(def_id);
590+
resolved.def = InstanceDef::ReifyShim(def_id, reason)
559591
}
560592
_ => {}
561593
}

compiler/rustc_middle/src/ty/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub use self::context::{
8888
tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift,
8989
TyCtxt, TyCtxtFeed,
9090
};
91-
pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams};
91+
pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams};
9292
pub use self::list::List;
9393
pub use self::parameterized::ParameterizedOverTcx;
9494
pub use self::predicate::{

compiler/rustc_middle/src/ty/structural_impls.rs

+1
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ TrivialTypeTraversalAndLiftImpls! {
449449
crate::ty::ClosureKind,
450450
crate::ty::ParamConst,
451451
crate::ty::ParamTy,
452+
crate::ty::instance::ReifyReason,
452453
interpret::AllocId,
453454
interpret::CtfeProvenance,
454455
interpret::Scalar,

compiler/rustc_mir_transform/src/inline.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ impl<'tcx> Inliner<'tcx> {
324324
// do not need to catch this here, we can wait until the inliner decides to continue
325325
// inlining a second time.
326326
InstanceDef::VTableShim(_)
327-
| InstanceDef::ReifyShim(_)
327+
| InstanceDef::ReifyShim(..)
328328
| InstanceDef::FnPtrShim(..)
329329
| InstanceDef::ClosureOnceShim { .. }
330330
| InstanceDef::ConstructCoroutineInClosureShim { .. }

compiler/rustc_mir_transform/src/inline/cycle.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
8484
// again, a function item can end up getting inlined. Thus we'll be able to cause
8585
// a cycle that way
8686
InstanceDef::VTableShim(_)
87-
| InstanceDef::ReifyShim(_)
87+
| InstanceDef::ReifyShim(..)
8888
| InstanceDef::FnPtrShim(..)
8989
| InstanceDef::ClosureOnceShim { .. }
9090
| InstanceDef::ConstructCoroutineInClosureShim { .. }

compiler/rustc_mir_transform/src/shim.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
5555
// a virtual call, or a direct call to a function for which
5656
// indirect calls must be codegen'd differently than direct ones
5757
// (such as `#[track_caller]`).
58-
ty::InstanceDef::ReifyShim(def_id) => {
58+
ty::InstanceDef::ReifyShim(def_id, _) => {
5959
build_call_shim(tcx, instance, None, CallKind::Direct(def_id))
6060
}
6161
ty::InstanceDef::ClosureOnceShim { call_once: _, track_caller: _ } => {

compiler/rustc_symbol_mangling/src/legacy.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
22
use rustc_hir::def_id::CrateNum;
33
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
44
use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
5-
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitableExt};
5+
use rustc_middle::ty::{self, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt};
66
use rustc_middle::ty::{GenericArg, GenericArgKind};
77

88
use std::fmt::{self, Write};
@@ -71,8 +71,14 @@ pub(super) fn mangle<'tcx>(
7171
ty::InstanceDef::VTableShim(..) => {
7272
printer.write_str("{{vtable-shim}}").unwrap();
7373
}
74-
ty::InstanceDef::ReifyShim(..) => {
75-
printer.write_str("{{reify-shim}}").unwrap();
74+
ty::InstanceDef::ReifyShim(_, reason) => {
75+
printer.write_str("{{reify-shim").unwrap();
76+
match reason {
77+
Some(ReifyReason::FnPtr) => printer.write_str("-fnptr").unwrap(),
78+
Some(ReifyReason::Vtable) => printer.write_str("-vtable").unwrap(),
79+
None => (),
80+
}
81+
printer.write_str("}}").unwrap();
7682
}
7783
// FIXME(async_closures): This shouldn't be needed when we fix
7884
// `Instance::ty`/`Instance::def_id`.

compiler/rustc_symbol_mangling/src/v0.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
88
use rustc_middle::ty::layout::IntegerExt;
99
use rustc_middle::ty::print::{Print, PrintError, Printer};
1010
use rustc_middle::ty::{
11-
self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, TypeVisitableExt,
12-
UintTy,
11+
self, EarlyBinder, FloatTy, Instance, IntTy, ReifyReason, Ty, TyCtxt, TypeVisitable,
12+
TypeVisitableExt, UintTy,
1313
};
1414
use rustc_middle::ty::{GenericArg, GenericArgKind};
1515
use rustc_span::symbol::kw;
@@ -44,7 +44,9 @@ pub(super) fn mangle<'tcx>(
4444
let shim_kind = match instance.def {
4545
ty::InstanceDef::ThreadLocalShim(_) => Some("tls"),
4646
ty::InstanceDef::VTableShim(_) => Some("vtable"),
47-
ty::InstanceDef::ReifyShim(_) => Some("reify"),
47+
ty::InstanceDef::ReifyShim(_, None) => Some("reify"),
48+
ty::InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify-fnptr"),
49+
ty::InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify-vtable"),
4850

4951
ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
5052
| ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"),

0 commit comments

Comments
 (0)