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