@@ -31,6 +31,13 @@ pub struct Instance<'tcx> {
31
31
pub args : GenericArgsRef < ' tcx > ,
32
32
}
33
33
34
+ #[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
35
+ #[ derive( TyEncodable , TyDecodable , HashStable ) ]
36
+ pub enum ReifyReason {
37
+ FnPtr ,
38
+ Vtable ,
39
+ }
40
+
34
41
#[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
35
42
#[ derive( TyEncodable , TyDecodable , HashStable , TypeFoldable , TypeVisitable , Lift ) ]
36
43
pub enum InstanceDef < ' tcx > {
@@ -67,7 +74,13 @@ pub enum InstanceDef<'tcx> {
67
74
/// Because this is a required part of the function's ABI but can't be tracked
68
75
/// as a property of the function pointer, we use a single "caller location"
69
76
/// (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 > ) ,
71
84
72
85
/// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers).
73
86
///
@@ -194,7 +207,7 @@ impl<'tcx> InstanceDef<'tcx> {
194
207
match self {
195
208
InstanceDef :: Item ( def_id)
196
209
| InstanceDef :: VTableShim ( def_id)
197
- | InstanceDef :: ReifyShim ( def_id)
210
+ | InstanceDef :: ReifyShim ( def_id, _ )
198
211
| InstanceDef :: FnPtrShim ( def_id, _)
199
212
| InstanceDef :: Virtual ( def_id, _)
200
213
| InstanceDef :: Intrinsic ( def_id)
@@ -354,7 +367,9 @@ fn fmt_instance(
354
367
match instance. def {
355
368
InstanceDef :: Item ( _) => Ok ( ( ) ) ,
356
369
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)" ) ,
358
373
InstanceDef :: ThreadLocalShim ( _) => write ! ( f, " - shim(tls)" ) ,
359
374
InstanceDef :: Intrinsic ( _) => write ! ( f, " - intrinsic" ) ,
360
375
InstanceDef :: Virtual ( _, num) => write ! ( f, " - virtual#{num}" ) ,
@@ -476,15 +491,24 @@ impl<'tcx> Instance<'tcx> {
476
491
debug ! ( "resolve(def_id={:?}, args={:?})" , def_id, args) ;
477
492
// Use either `resolve_closure` or `resolve_for_vtable`
478
493
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 ) ;
479
495
Instance :: resolve ( tcx, param_env, def_id, args) . ok ( ) . flatten ( ) . map ( |mut resolved| {
480
496
match resolved. def {
481
497
InstanceDef :: Item ( def) if resolved. def . requires_caller_location ( tcx) => {
482
498
debug ! ( " => fn pointer created for function with #[track_caller]" ) ;
483
- resolved. def = InstanceDef :: ReifyShim ( def) ;
499
+ resolved. def = InstanceDef :: ReifyShim ( def, reason ) ;
484
500
}
485
501
InstanceDef :: Virtual ( def_id, _) => {
486
502
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)
488
512
}
489
513
_ => { }
490
514
}
@@ -508,6 +532,7 @@ impl<'tcx> Instance<'tcx> {
508
532
debug ! ( " => associated item with unsizeable self: Self" ) ;
509
533
Some ( Instance { def : InstanceDef :: VTableShim ( def_id) , args } )
510
534
} else {
535
+ let reason = tcx. sess . is_sanitizer_kcfi_enabled ( ) . then_some ( ReifyReason :: Vtable ) ;
511
536
Instance :: resolve ( tcx, param_env, def_id, args) . ok ( ) . flatten ( ) . map ( |mut resolved| {
512
537
match resolved. def {
513
538
InstanceDef :: Item ( def) => {
@@ -544,18 +569,18 @@ impl<'tcx> Instance<'tcx> {
544
569
// Create a shim for the `FnOnce/FnMut/Fn` method we are calling
545
570
// - unlike functions, invoking a closure always goes through a
546
571
// trait.
547
- resolved = Instance { def : InstanceDef :: ReifyShim ( def_id) , args } ;
572
+ resolved = Instance { def : InstanceDef :: ReifyShim ( def_id, reason ) , args } ;
548
573
} else {
549
574
debug ! (
550
575
" => vtable fn pointer created for function with #[track_caller]: {:?}" , def
551
576
) ;
552
- resolved. def = InstanceDef :: ReifyShim ( def) ;
577
+ resolved. def = InstanceDef :: ReifyShim ( def, reason ) ;
553
578
}
554
579
}
555
580
}
556
581
InstanceDef :: Virtual ( def_id, _) => {
557
582
debug ! ( " => vtable fn pointer created for virtual call" ) ;
558
- resolved. def = InstanceDef :: ReifyShim ( def_id) ;
583
+ resolved. def = InstanceDef :: ReifyShim ( def_id, reason )
559
584
}
560
585
_ => { }
561
586
}
0 commit comments