1
+ use std:: cell:: RefCell ;
1
2
use std:: iter;
2
3
use std:: ops:: ControlFlow ;
3
4
@@ -86,11 +87,6 @@ enum CItemKind {
86
87
Definition ,
87
88
}
88
89
89
- struct ImproperCTypesVisitor < ' a , ' tcx > {
90
- cx : & ' a LateContext < ' tcx > ,
91
- cache : FxHashSet < Ty < ' tcx > > ,
92
- }
93
-
94
90
#[ derive( Clone , Debug ) ]
95
91
struct FfiUnsafeReason < ' tcx > {
96
92
ty : Ty < ' tcx > ,
@@ -386,9 +382,52 @@ impl CTypesVisitorState {
386
382
}
387
383
}
388
384
385
+ /// visitor structure responsible for checking the actual FFI-safety
386
+ /// of a given type
387
+ struct ImproperCTypesVisitor < ' a , ' tcx > {
388
+ cx : & ' a LateContext < ' tcx > ,
389
+ /// to prevent problems with recursive types, add a types-in-check cache
390
+ /// and a depth counter
391
+ recursion_limiter : RefCell < ( FxHashSet < Ty < ' tcx > > , usize ) > ,
392
+ }
393
+
394
+ /// structure similar to a mutex guard, allocated for each type in-check
395
+ /// to let the ImproperCTypesVisitor know the current depth of the checking process
396
+ struct ImproperCTypesVisitorDepthGuard < ' a , ' tcx , ' v > ( & ' v ImproperCTypesVisitor < ' a , ' tcx > ) ;
397
+
398
+ impl < ' a , ' tcx , ' v > Drop for ImproperCTypesVisitorDepthGuard < ' a , ' tcx , ' v > {
399
+ fn drop ( & mut self ) {
400
+ let mut limiter_guard = self . 0 . recursion_limiter . borrow_mut ( ) ;
401
+ let ( _, ref mut depth) = * limiter_guard;
402
+ * depth -= 1 ;
403
+ }
404
+ }
405
+
389
406
impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
407
+ fn new ( cx : & ' a LateContext < ' tcx > ) -> Self {
408
+ Self { cx, recursion_limiter : RefCell :: new ( ( FxHashSet :: default ( ) , 0 ) ) }
409
+ }
410
+
411
+ /// Protect against infinite recursion, for example
412
+ /// `struct S(*mut S);`, or issue #130310.
413
+ fn can_enter_type < ' v > (
414
+ & ' v self ,
415
+ ty : Ty < ' tcx > ,
416
+ ) -> Result < ImproperCTypesVisitorDepthGuard < ' a , ' tcx , ' v > , FfiResult < ' tcx > > {
417
+ // panic unlikely: this non-recursive function is the only place that
418
+ // borrows the refcell, outside of ImproperCTypesVisitorDepthGuard::drop()
419
+ let mut limiter_guard = self . recursion_limiter . borrow_mut ( ) ;
420
+ let ( ref mut cache, ref mut depth) = * limiter_guard;
421
+ if ( !cache. insert ( ty) ) || * depth >= 1024 {
422
+ Err ( FfiResult :: FfiSafe )
423
+ } else {
424
+ * depth += 1 ;
425
+ Ok ( ImproperCTypesVisitorDepthGuard ( self ) )
426
+ }
427
+ }
428
+
390
429
/// Checks whether an `extern "ABI" fn` function pointer is indeed FFI-safe to call
391
- fn visit_fnptr ( & mut self , mode : CItemKind , ty : Ty < ' tcx > , sig : Sig < ' tcx > ) -> FfiResult < ' tcx > {
430
+ fn visit_fnptr ( & self , mode : CItemKind , ty : Ty < ' tcx > , sig : Sig < ' tcx > ) -> FfiResult < ' tcx > {
392
431
use FfiResult :: * ;
393
432
debug_assert ! ( !sig. abi( ) . is_rustic_abi( ) ) ;
394
433
let sig = self . cx . tcx . instantiate_bound_regions_with_erased ( sig) ;
@@ -426,7 +465,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
426
465
427
466
/// Checks if a simple numeric (int, float) type has an actual portable definition
428
467
/// for the compile target
429
- fn visit_numeric ( & mut self , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
468
+ fn visit_numeric ( & self , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
430
469
// FIXME: for now, this is very incomplete, and seems to assume a x86_64 target
431
470
match ty. kind ( ) {
432
471
ty:: Int ( ty:: IntTy :: I128 ) | ty:: Uint ( ty:: UintTy :: U128 ) => {
@@ -438,7 +477,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
438
477
}
439
478
440
479
/// Return the right help for Cstring and Cstr-linked unsafety
441
- fn visit_cstr ( & mut self , outer_ty : Option < Ty < ' tcx > > , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
480
+ fn visit_cstr ( & self , outer_ty : Option < Ty < ' tcx > > , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
442
481
debug_assert ! ( matches!( ty. kind( ) , ty:: Adt ( def, _)
443
482
if matches!(
444
483
self . cx. tcx. get_diagnostic_name( def. did( ) ) ,
@@ -469,7 +508,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
469
508
470
509
/// Checks if the given indirection (box,ref,pointer) is "ffi-safe"
471
510
fn visit_indirection (
472
- & mut self ,
511
+ & self ,
473
512
state : CTypesVisitorState ,
474
513
outer_ty : Option < Ty < ' tcx > > ,
475
514
ty : Ty < ' tcx > ,
@@ -609,7 +648,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
609
648
610
649
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
611
650
fn visit_variant_fields (
612
- & mut self ,
651
+ & self ,
613
652
state : CTypesVisitorState ,
614
653
ty : Ty < ' tcx > ,
615
654
def : ty:: AdtDef < ' tcx > ,
@@ -668,7 +707,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
668
707
}
669
708
670
709
fn visit_struct_union (
671
- & mut self ,
710
+ & self ,
672
711
state : CTypesVisitorState ,
673
712
ty : Ty < ' tcx > ,
674
713
def : ty:: AdtDef < ' tcx > ,
@@ -724,7 +763,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
724
763
}
725
764
726
765
fn visit_enum (
727
- & mut self ,
766
+ & self ,
728
767
state : CTypesVisitorState ,
729
768
ty : Ty < ' tcx > ,
730
769
def : ty:: AdtDef < ' tcx > ,
@@ -792,23 +831,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
792
831
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
793
832
/// representation which can be exported to C code).
794
833
fn visit_type (
795
- & mut self ,
834
+ & self ,
796
835
state : CTypesVisitorState ,
797
836
outer_ty : Option < Ty < ' tcx > > ,
798
837
ty : Ty < ' tcx > ,
799
838
) -> FfiResult < ' tcx > {
800
839
use FfiResult :: * ;
801
840
841
+ let _depth_guard = match self . can_enter_type ( ty) {
842
+ Ok ( guard) => guard,
843
+ Err ( ffi_res) => return ffi_res,
844
+ } ;
802
845
let tcx = self . cx . tcx ;
803
846
804
- // Protect against infinite recursion, for example
805
- // `struct S(*mut S);`.
806
- // FIXME: A recursion limit is necessary as well, for irregular
807
- // recursive types.
808
- if !self . cache . insert ( ty) {
809
- return FfiSafe ;
810
- }
811
-
812
847
match * ty. kind ( ) {
813
848
ty:: Adt ( def, args) => {
814
849
if let Some ( inner_ty) = ty. boxed_ty ( ) {
@@ -1007,7 +1042,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1007
1042
}
1008
1043
}
1009
1044
1010
- fn check_for_opaque_ty ( & mut self , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1045
+ fn check_for_opaque_ty ( & self , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1011
1046
struct ProhibitOpaqueTypes ;
1012
1047
impl < ' tcx > ty:: TypeVisitor < TyCtxt < ' tcx > > for ProhibitOpaqueTypes {
1013
1048
type Result = ControlFlow < Ty < ' tcx > > ;
@@ -1032,7 +1067,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1032
1067
}
1033
1068
}
1034
1069
1035
- fn check_for_type ( & mut self , state : CTypesVisitorState , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1070
+ fn check_for_type ( & self , state : CTypesVisitorState , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1036
1071
let ty = normalize_if_possible ( self . cx , ty) ;
1037
1072
1038
1073
match self . check_for_opaque_ty ( ty) {
@@ -1042,7 +1077,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1042
1077
self . visit_type ( state, None , ty)
1043
1078
}
1044
1079
1045
- fn check_for_fnptr ( & mut self , mode : CItemKind , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1080
+ fn check_for_fnptr ( & self , mode : CItemKind , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1046
1081
let ty = normalize_if_possible ( self . cx , ty) ;
1047
1082
1048
1083
match self . check_for_opaque_ty ( ty) {
@@ -1184,8 +1219,7 @@ impl<'c, 'tcx> ImproperCTypesLint<'c, 'tcx> {
1184
1219
all_types
1185
1220
. map ( |( fn_ptr_ty, span) | {
1186
1221
// FIXME this will probably lead to error deduplication: fix this
1187
- let mut visitor =
1188
- ImproperCTypesVisitor { cx : self . cx , cache : FxHashSet :: default ( ) } ;
1222
+ let visitor = ImproperCTypesVisitor :: new ( self . cx ) ;
1189
1223
let ffi_res = visitor. check_for_fnptr ( fn_mode, fn_ptr_ty) ;
1190
1224
( span, ffi_res)
1191
1225
} )
@@ -1218,7 +1252,7 @@ impl<'c, 'tcx> ImproperCTypesLint<'c, 'tcx> {
1218
1252
/// Check that an extern "ABI" static variable is of a ffi-safe type
1219
1253
fn check_foreign_static ( & self , id : hir:: OwnerId , span : Span ) {
1220
1254
let ty = self . cx . tcx . type_of ( id) . instantiate_identity ( ) ;
1221
- let mut visitor = ImproperCTypesVisitor { cx : self . cx , cache : FxHashSet :: default ( ) } ;
1255
+ let visitor = ImproperCTypesVisitor :: new ( self . cx ) ;
1222
1256
let ffi_res = visitor. check_for_type ( CTypesVisitorState :: StaticTy , ty) ;
1223
1257
self . process_ffi_result ( span, ffi_res, CItemKind :: Declaration ) ;
1224
1258
}
@@ -1234,7 +1268,7 @@ impl<'c, 'tcx> ImproperCTypesLint<'c, 'tcx> {
1234
1268
let sig = self . cx . tcx . instantiate_bound_regions_with_erased ( sig) ;
1235
1269
1236
1270
for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1237
- let mut visitor = ImproperCTypesVisitor { cx : self . cx , cache : FxHashSet :: default ( ) } ;
1271
+ let visitor = ImproperCTypesVisitor :: new ( self . cx ) ;
1238
1272
let visit_state = match fn_mode {
1239
1273
CItemKind :: Definition => CTypesVisitorState :: ArgumentTyInDefinition ,
1240
1274
CItemKind :: Declaration => CTypesVisitorState :: ArgumentTyInDeclaration ,
@@ -1244,7 +1278,7 @@ impl<'c, 'tcx> ImproperCTypesLint<'c, 'tcx> {
1244
1278
}
1245
1279
1246
1280
if let hir:: FnRetTy :: Return ( ret_hir) = decl. output {
1247
- let mut visitor = ImproperCTypesVisitor { cx : self . cx , cache : FxHashSet :: default ( ) } ;
1281
+ let visitor = ImproperCTypesVisitor :: new ( self . cx ) ;
1248
1282
let visit_state = match fn_mode {
1249
1283
CItemKind :: Definition => CTypesVisitorState :: ReturnTyInDefinition ,
1250
1284
CItemKind :: Declaration => CTypesVisitorState :: ReturnTyInDeclaration ,
0 commit comments