1
+ use std:: cell:: RefCell ;
1
2
use std:: iter;
2
3
use std:: ops:: ControlFlow ;
3
4
@@ -483,17 +484,53 @@ impl VisitorState {
483
484
struct ImproperCTypesVisitor < ' a , ' tcx > {
484
485
cx : & ' a LateContext < ' tcx > ,
485
486
/// To prevent problems with recursive types,
486
- /// add a types-in-check cache.
487
- cache : FxHashSet < Ty < ' tcx > > ,
487
+ /// add a types-in-check cache and a depth counter.
488
+ recursion_limiter : RefCell < ( FxHashSet < Ty < ' tcx > > , usize ) > ,
489
+
488
490
/// The original type being checked, before we recursed
489
491
/// to any other types it contains.
490
492
base_ty : Ty < ' tcx > ,
491
493
base_fn_mode : CItemKind ,
492
494
}
493
495
496
+ /// Structure similar to a mutex guard, allocated for each type in-check
497
+ /// to let the ImproperCTypesVisitor know the current depth of the checking process.
498
+ struct ImproperCTypesVisitorDepthGuard < ' a , ' tcx , ' v > ( & ' v ImproperCTypesVisitor < ' a , ' tcx > ) ;
499
+
500
+ impl < ' a , ' tcx , ' v > Drop for ImproperCTypesVisitorDepthGuard < ' a , ' tcx , ' v > {
501
+ fn drop ( & mut self ) {
502
+ let mut limiter_guard = self . 0 . recursion_limiter . borrow_mut ( ) ;
503
+ let ( _, ref mut depth) = * limiter_guard;
504
+ * depth -= 1 ;
505
+ }
506
+ }
507
+
494
508
impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
495
509
fn new ( cx : & ' a LateContext < ' tcx > , base_ty : Ty < ' tcx > , base_fn_mode : CItemKind ) -> Self {
496
- Self { cx, base_ty, base_fn_mode, cache : FxHashSet :: default ( ) }
510
+ Self {
511
+ cx,
512
+ base_ty,
513
+ base_fn_mode,
514
+ recursion_limiter : RefCell :: new ( ( FxHashSet :: default ( ) , 0 ) ) ,
515
+ }
516
+ }
517
+
518
+ /// Protect against infinite recursion, for example
519
+ /// `struct S(*mut S);`, or issue #130310.
520
+ fn can_enter_type < ' v > (
521
+ & ' v self ,
522
+ ty : Ty < ' tcx > ,
523
+ ) -> Result < ImproperCTypesVisitorDepthGuard < ' a , ' tcx , ' v > , FfiResult < ' tcx > > {
524
+ // panic unlikely: this non-recursive function is the only place that
525
+ // borrows the refcell, outside of ImproperCTypesVisitorDepthGuard::drop()
526
+ let mut limiter_guard = self . recursion_limiter . borrow_mut ( ) ;
527
+ let ( ref mut cache, ref mut depth) = * limiter_guard;
528
+ if ( !cache. insert ( ty) ) || * depth >= 1024 {
529
+ Err ( FfiResult :: FfiSafe )
530
+ } else {
531
+ * depth += 1 ;
532
+ Ok ( ImproperCTypesVisitorDepthGuard ( self ) )
533
+ }
497
534
}
498
535
499
536
/// Checks if a simple numeric (int, float) type has an actual portable definition
@@ -516,7 +553,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
516
553
517
554
/// Checks if the given indirection (box,ref,pointer) is "ffi-safe".
518
555
fn visit_indirection (
519
- & mut self ,
556
+ & self ,
520
557
state : VisitorState ,
521
558
ty : Ty < ' tcx > ,
522
559
inner_ty : Ty < ' tcx > ,
@@ -564,7 +601,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
564
601
565
602
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
566
603
fn visit_variant_fields (
567
- & mut self ,
604
+ & self ,
568
605
state : VisitorState ,
569
606
ty : Ty < ' tcx > ,
570
607
def : AdtDef < ' tcx > ,
@@ -609,7 +646,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
609
646
}
610
647
611
648
fn visit_struct_or_union (
612
- & mut self ,
649
+ & self ,
613
650
state : VisitorState ,
614
651
ty : Ty < ' tcx > ,
615
652
def : AdtDef < ' tcx > ,
@@ -666,7 +703,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
666
703
}
667
704
668
705
fn visit_enum (
669
- & mut self ,
706
+ & self ,
670
707
state : VisitorState ,
671
708
ty : Ty < ' tcx > ,
672
709
def : AdtDef < ' tcx > ,
@@ -718,23 +755,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
718
755
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
719
756
/// representation which can be exported to C code).
720
757
fn visit_type (
721
- & mut self ,
758
+ & self ,
722
759
state : VisitorState ,
723
760
outer_ty : Option < Ty < ' tcx > > ,
724
761
ty : Ty < ' tcx > ,
725
762
) -> FfiResult < ' tcx > {
726
763
use FfiResult :: * ;
727
764
765
+ let _depth_guard = match self . can_enter_type ( ty) {
766
+ Ok ( guard) => guard,
767
+ Err ( ffi_res) => return ffi_res,
768
+ } ;
728
769
let tcx = self . cx . tcx ;
729
770
730
- // Protect against infinite recursion, for example
731
- // `struct S(*mut S);`.
732
- // FIXME: A recursion limit is necessary as well, for irregular
733
- // recursive types.
734
- if !self . cache . insert ( ty) {
735
- return FfiSafe ;
736
- }
737
-
738
771
match * ty. kind ( ) {
739
772
ty:: Adt ( def, args) => {
740
773
if let Some ( inner_ty) = ty. boxed_ty ( ) {
@@ -910,7 +943,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
910
943
}
911
944
}
912
945
913
- fn visit_for_opaque_ty ( & mut self , ty : Ty < ' tcx > ) -> PartialFfiResult < ' tcx > {
946
+ fn visit_for_opaque_ty ( & self , ty : Ty < ' tcx > ) -> PartialFfiResult < ' tcx > {
914
947
struct ProhibitOpaqueTypes ;
915
948
impl < ' tcx > ty:: TypeVisitor < TyCtxt < ' tcx > > for ProhibitOpaqueTypes {
916
949
type Result = ControlFlow < Ty < ' tcx > > ;
@@ -933,7 +966,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
933
966
. map ( |ty| FfiResult :: new_with_reason ( ty, fluent:: lint_improper_ctypes_opaque, None ) )
934
967
}
935
968
936
- fn check_type ( & mut self , state : VisitorState , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
969
+ fn check_type ( & self , state : VisitorState , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
937
970
let ty = self . cx . tcx . try_normalize_erasing_regions ( self . cx . typing_env ( ) , ty) . unwrap_or ( ty) ;
938
971
match self . visit_for_opaque_ty ( ty) {
939
972
None => { }
@@ -1065,7 +1098,7 @@ impl<'tcx> ImproperCTypesLint {
1065
1098
1066
1099
let all_types = iter:: zip ( visitor. tys . drain ( ..) , visitor. spans . drain ( ..) ) ;
1067
1100
for ( fn_ptr_ty, span) in all_types {
1068
- let mut visitor = ImproperCTypesVisitor :: new ( cx, fn_ptr_ty, fn_mode) ;
1101
+ let visitor = ImproperCTypesVisitor :: new ( cx, fn_ptr_ty, fn_mode) ;
1069
1102
// FIXME(ctypes): make a check_for_fnptr
1070
1103
let ffi_res = visitor. check_type ( state, fn_ptr_ty) ;
1071
1104
@@ -1113,9 +1146,9 @@ impl<'tcx> ImproperCTypesLint {
1113
1146
ImproperCTypesVisitor :: check_struct_for_power_alignment ( cx, item, adt_def) ;
1114
1147
}
1115
1148
1116
- fn check_foreign_static ( & mut self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
1149
+ fn check_foreign_static ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
1117
1150
let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
1118
- let mut visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: Declaration ) ;
1151
+ let visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: Declaration ) ;
1119
1152
let ffi_res = visitor. check_type ( VisitorState :: STATIC_TY , ty) ;
1120
1153
self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Declaration ) ;
1121
1154
}
@@ -1133,14 +1166,14 @@ impl<'tcx> ImproperCTypesLint {
1133
1166
1134
1167
for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1135
1168
let state = VisitorState :: argument_from_fnmode ( fn_mode) ;
1136
- let mut visitor = ImproperCTypesVisitor :: new ( cx, * input_ty, fn_mode) ;
1169
+ let visitor = ImproperCTypesVisitor :: new ( cx, * input_ty, fn_mode) ;
1137
1170
let ffi_res = visitor. check_type ( state, * input_ty) ;
1138
1171
self . process_ffi_result ( cx, input_hir. span , ffi_res, fn_mode) ;
1139
1172
}
1140
1173
1141
1174
if let hir:: FnRetTy :: Return ( ret_hir) = decl. output {
1142
1175
let state = VisitorState :: return_from_fnmode ( fn_mode) ;
1143
- let mut visitor = ImproperCTypesVisitor :: new ( cx, sig. output ( ) , fn_mode) ;
1176
+ let visitor = ImproperCTypesVisitor :: new ( cx, sig. output ( ) , fn_mode) ;
1144
1177
let ffi_res = visitor. check_type ( state, sig. output ( ) ) ;
1145
1178
self . process_ffi_result ( cx, ret_hir. span , ffi_res, fn_mode) ;
1146
1179
}
0 commit comments