@@ -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,30 @@ 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)
512
+ }
513
+ _ if tcx. sess . is_sanitizer_kcfi_enabled ( )
514
+ && tcx. is_closure_like ( resolved. def_id ( ) ) =>
515
+ {
516
+ // Reroute through a reify via the *original*
517
+ resolved = Instance { def : InstanceDef :: ReifyShim ( def_id, reason) , args }
488
518
}
489
519
_ => { }
490
520
}
@@ -508,6 +538,7 @@ impl<'tcx> Instance<'tcx> {
508
538
debug ! ( " => associated item with unsizeable self: Self" ) ;
509
539
Some ( Instance { def : InstanceDef :: VTableShim ( def_id) , args } )
510
540
} else {
541
+ let reason = tcx. sess . is_sanitizer_kcfi_enabled ( ) . then_some ( ReifyReason :: Vtable ) ;
511
542
Instance :: resolve ( tcx, param_env, def_id, args) . ok ( ) . flatten ( ) . map ( |mut resolved| {
512
543
match resolved. def {
513
544
InstanceDef :: Item ( def) => {
@@ -544,18 +575,18 @@ impl<'tcx> Instance<'tcx> {
544
575
// Create a shim for the `FnOnce/FnMut/Fn` method we are calling
545
576
// - unlike functions, invoking a closure always goes through a
546
577
// trait.
547
- resolved = Instance { def : InstanceDef :: ReifyShim ( def_id) , args } ;
578
+ resolved = Instance { def : InstanceDef :: ReifyShim ( def_id, reason ) , args } ;
548
579
} else {
549
580
debug ! (
550
581
" => vtable fn pointer created for function with #[track_caller]: {:?}" , def
551
582
) ;
552
- resolved. def = InstanceDef :: ReifyShim ( def) ;
583
+ resolved. def = InstanceDef :: ReifyShim ( def, reason ) ;
553
584
}
554
585
}
555
586
}
556
587
InstanceDef :: Virtual ( def_id, _) => {
557
588
debug ! ( " => vtable fn pointer created for virtual call" ) ;
558
- resolved. def = InstanceDef :: ReifyShim ( def_id) ;
589
+ resolved. def = InstanceDef :: ReifyShim ( def_id, reason )
559
590
}
560
591
_ => { }
561
592
}
0 commit comments