@@ -31,6 +31,28 @@ pub struct Instance<'tcx> {
31
31
pub args : GenericArgsRef < ' tcx > ,
32
32
}
33
33
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
+
34
56
#[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
35
57
#[ derive( TyEncodable , TyDecodable , HashStable , TypeFoldable , TypeVisitable , Lift ) ]
36
58
pub enum InstanceDef < ' tcx > {
@@ -67,7 +89,13 @@ pub enum InstanceDef<'tcx> {
67
89
/// Because this is a required part of the function's ABI but can't be tracked
68
90
/// as a property of the function pointer, we use a single "caller location"
69
91
/// (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 > ) ,
71
99
72
100
/// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers).
73
101
///
@@ -194,7 +222,7 @@ impl<'tcx> InstanceDef<'tcx> {
194
222
match self {
195
223
InstanceDef :: Item ( def_id)
196
224
| InstanceDef :: VTableShim ( def_id)
197
- | InstanceDef :: ReifyShim ( def_id)
225
+ | InstanceDef :: ReifyShim ( def_id, _ )
198
226
| InstanceDef :: FnPtrShim ( def_id, _)
199
227
| InstanceDef :: Virtual ( def_id, _)
200
228
| InstanceDef :: Intrinsic ( def_id)
@@ -354,7 +382,9 @@ fn fmt_instance(
354
382
match instance. def {
355
383
InstanceDef :: Item ( _) => Ok ( ( ) ) ,
356
384
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)" ) ,
358
388
InstanceDef :: ThreadLocalShim ( _) => write ! ( f, " - shim(tls)" ) ,
359
389
InstanceDef :: Intrinsic ( _) => write ! ( f, " - intrinsic" ) ,
360
390
InstanceDef :: Virtual ( _, num) => write ! ( f, " - virtual#{num}" ) ,
@@ -476,15 +506,34 @@ impl<'tcx> Instance<'tcx> {
476
506
debug ! ( "resolve(def_id={:?}, args={:?})" , def_id, args) ;
477
507
// Use either `resolve_closure` or `resolve_for_vtable`
478
508
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 ) ;
479
510
Instance :: resolve ( tcx, param_env, def_id, args) . ok ( ) . flatten ( ) . map ( |mut resolved| {
480
511
match resolved. def {
481
512
InstanceDef :: Item ( def) if resolved. def . requires_caller_location ( tcx) => {
482
513
debug ! ( " => fn pointer created for function with #[track_caller]" ) ;
483
- resolved. def = InstanceDef :: ReifyShim ( def) ;
514
+ resolved. def = InstanceDef :: ReifyShim ( def, reason ) ;
484
515
}
485
516
InstanceDef :: Virtual ( def_id, _) => {
486
517
debug ! ( " => fn pointer created for virtual call" ) ;
487
- resolved. def = InstanceDef :: ReifyShim ( def_id) ;
518
+ resolved. def = InstanceDef :: ReifyShim ( def_id, reason) ;
519
+ }
520
+ // Reify `Trait::method` implementations if KCFI is enabled
521
+ // FIXME(maurer) only reify it if it is a vtable-safe function
522
+ _ if tcx. sess . is_sanitizer_kcfi_enabled ( )
523
+ && tcx. associated_item ( def_id) . trait_item_def_id . is_some ( ) =>
524
+ {
525
+ // If this function could also go in a vtable, we need to `ReifyShim` it with
526
+ // KCFI because it can only attach one type per function.
527
+ resolved. def = InstanceDef :: ReifyShim ( resolved. def_id ( ) , reason)
528
+ }
529
+ // Reify `::call`-like method implementations if KCFI is enabled
530
+ _ if tcx. sess . is_sanitizer_kcfi_enabled ( )
531
+ && tcx. is_closure_like ( resolved. def_id ( ) ) =>
532
+ {
533
+ // Reroute through a reify via the *unresolved* instance. The resolved one can't
534
+ // be directly reified because it's closure-like. The reify can handle the
535
+ // unresolved instance.
536
+ resolved = Instance { def : InstanceDef :: ReifyShim ( def_id, reason) , args }
488
537
}
489
538
_ => { }
490
539
}
@@ -508,6 +557,7 @@ impl<'tcx> Instance<'tcx> {
508
557
debug ! ( " => associated item with unsizeable self: Self" ) ;
509
558
Some ( Instance { def : InstanceDef :: VTableShim ( def_id) , args } )
510
559
} else {
560
+ let reason = tcx. sess . is_sanitizer_kcfi_enabled ( ) . then_some ( ReifyReason :: Vtable ) ;
511
561
Instance :: resolve ( tcx, param_env, def_id, args) . ok ( ) . flatten ( ) . map ( |mut resolved| {
512
562
match resolved. def {
513
563
InstanceDef :: Item ( def) => {
@@ -544,18 +594,18 @@ impl<'tcx> Instance<'tcx> {
544
594
// Create a shim for the `FnOnce/FnMut/Fn` method we are calling
545
595
// - unlike functions, invoking a closure always goes through a
546
596
// trait.
547
- resolved = Instance { def : InstanceDef :: ReifyShim ( def_id) , args } ;
597
+ resolved = Instance { def : InstanceDef :: ReifyShim ( def_id, reason ) , args } ;
548
598
} else {
549
599
debug ! (
550
600
" => vtable fn pointer created for function with #[track_caller]: {:?}" , def
551
601
) ;
552
- resolved. def = InstanceDef :: ReifyShim ( def) ;
602
+ resolved. def = InstanceDef :: ReifyShim ( def, reason ) ;
553
603
}
554
604
}
555
605
}
556
606
InstanceDef :: Virtual ( def_id, _) => {
557
607
debug ! ( " => vtable fn pointer created for virtual call" ) ;
558
- resolved. def = InstanceDef :: ReifyShim ( def_id) ;
608
+ resolved. def = InstanceDef :: ReifyShim ( def_id, reason )
559
609
}
560
610
_ => { }
561
611
}
0 commit comments