@@ -31,6 +31,13 @@ pub struct Instance<'tcx> {
3131 pub args : GenericArgsRef < ' tcx > ,
3232}
3333
34+ #[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
35+ #[ derive( TyEncodable , TyDecodable , HashStable ) ]
36+ pub enum ReifyReason {
37+ FnPtr ,
38+ Vtable ,
39+ }
40+
3441#[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
3542#[ derive( TyEncodable , TyDecodable , HashStable , TypeFoldable , TypeVisitable , Lift ) ]
3643pub enum InstanceDef < ' tcx > {
@@ -67,7 +74,13 @@ pub enum InstanceDef<'tcx> {
6774 /// Because this is a required part of the function's ABI but can't be tracked
6875 /// as a property of the function pointer, we use a single "caller location"
6976 /// (the definition of the function itself).
70- ReifyShim ( DefId ) ,
77+ ///
78+ /// The second field encodes *why* this shim was created. This allows distinguishing between
79+ /// a `ReifyShim` that appears in a vtable vs one that appears as a function pointer.
80+ ///
81+ /// This field will only be populated if we are compiling in a mode that needs these shims
82+ /// to be separable, currently only when KCFI is enabled.
83+ ReifyShim ( DefId , Option < ReifyReason > ) ,
7184
7285 /// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers).
7386 ///
@@ -194,7 +207,7 @@ impl<'tcx> InstanceDef<'tcx> {
194207 match self {
195208 InstanceDef :: Item ( def_id)
196209 | InstanceDef :: VTableShim ( def_id)
197- | InstanceDef :: ReifyShim ( def_id)
210+ | InstanceDef :: ReifyShim ( def_id, _ )
198211 | InstanceDef :: FnPtrShim ( def_id, _)
199212 | InstanceDef :: Virtual ( def_id, _)
200213 | InstanceDef :: Intrinsic ( def_id)
@@ -354,7 +367,9 @@ fn fmt_instance(
354367 match instance. def {
355368 InstanceDef :: Item ( _) => Ok ( ( ) ) ,
356369 InstanceDef :: VTableShim ( _) => write ! ( f, " - shim(vtable)" ) ,
357- InstanceDef :: ReifyShim ( _) => write ! ( f, " - shim(reify)" ) ,
370+ InstanceDef :: ReifyShim ( _, None ) => write ! ( f, " - shim(reify)" ) ,
371+ InstanceDef :: ReifyShim ( _, Some ( ReifyReason :: FnPtr ) ) => write ! ( f, " - shim(reify-fnptr)" ) ,
372+ InstanceDef :: ReifyShim ( _, Some ( ReifyReason :: Vtable ) ) => write ! ( f, " - shim(reify-vtable)" ) ,
358373 InstanceDef :: ThreadLocalShim ( _) => write ! ( f, " - shim(tls)" ) ,
359374 InstanceDef :: Intrinsic ( _) => write ! ( f, " - intrinsic" ) ,
360375 InstanceDef :: Virtual ( _, num) => write ! ( f, " - virtual#{num}" ) ,
@@ -476,15 +491,24 @@ impl<'tcx> Instance<'tcx> {
476491 debug ! ( "resolve(def_id={:?}, args={:?})" , def_id, args) ;
477492 // Use either `resolve_closure` or `resolve_for_vtable`
478493 assert ! ( !tcx. is_closure_like( def_id) , "Called `resolve_for_fn_ptr` on closure: {def_id:?}" ) ;
494+ let reason = tcx. sess . is_sanitizer_kcfi_enabled ( ) . then_some ( ReifyReason :: FnPtr ) ;
479495 Instance :: resolve ( tcx, param_env, def_id, args) . ok ( ) . flatten ( ) . map ( |mut resolved| {
480496 match resolved. def {
481497 InstanceDef :: Item ( def) if resolved. def . requires_caller_location ( tcx) => {
482498 debug ! ( " => fn pointer created for function with #[track_caller]" ) ;
483- resolved. def = InstanceDef :: ReifyShim ( def) ;
499+ resolved. def = InstanceDef :: ReifyShim ( def, reason ) ;
484500 }
485501 InstanceDef :: Virtual ( def_id, _) => {
486502 debug ! ( " => fn pointer created for virtual call" ) ;
487- resolved. def = InstanceDef :: ReifyShim ( def_id) ;
503+ resolved. def = InstanceDef :: ReifyShim ( def_id, reason) ;
504+ }
505+ // FIXME(maurer) only shim it if it is a vtable-safe function
506+ _ if tcx. sess . is_sanitizer_kcfi_enabled ( )
507+ && tcx. associated_item ( def_id) . trait_item_def_id . is_some ( ) =>
508+ {
509+ // If this function could also go in a vtable, we need to `ReifyShim` it with
510+ // KCFI because it can only attach one type per function.
511+ resolved. def = InstanceDef :: ReifyShim ( resolved. def_id ( ) , reason)
488512 }
489513 _ => { }
490514 }
@@ -508,6 +532,7 @@ impl<'tcx> Instance<'tcx> {
508532 debug ! ( " => associated item with unsizeable self: Self" ) ;
509533 Some ( Instance { def : InstanceDef :: VTableShim ( def_id) , args } )
510534 } else {
535+ let reason = tcx. sess . is_sanitizer_kcfi_enabled ( ) . then_some ( ReifyReason :: Vtable ) ;
511536 Instance :: resolve ( tcx, param_env, def_id, args) . ok ( ) . flatten ( ) . map ( |mut resolved| {
512537 match resolved. def {
513538 InstanceDef :: Item ( def) => {
@@ -544,18 +569,18 @@ impl<'tcx> Instance<'tcx> {
544569 // Create a shim for the `FnOnce/FnMut/Fn` method we are calling
545570 // - unlike functions, invoking a closure always goes through a
546571 // trait.
547- resolved = Instance { def : InstanceDef :: ReifyShim ( def_id) , args } ;
572+ resolved = Instance { def : InstanceDef :: ReifyShim ( def_id, reason ) , args } ;
548573 } else {
549574 debug ! (
550575 " => vtable fn pointer created for function with #[track_caller]: {:?}" , def
551576 ) ;
552- resolved. def = InstanceDef :: ReifyShim ( def) ;
577+ resolved. def = InstanceDef :: ReifyShim ( def, reason ) ;
553578 }
554579 }
555580 }
556581 InstanceDef :: Virtual ( def_id, _) => {
557582 debug ! ( " => vtable fn pointer created for virtual call" ) ;
558- resolved. def = InstanceDef :: ReifyShim ( def_id) ;
583+ resolved. def = InstanceDef :: ReifyShim ( def_id, reason )
559584 }
560585 _ => { }
561586 }
0 commit comments