1
+ use std:: cell:: RefCell ;
1
2
use std:: iter;
2
3
use std:: ops:: ControlFlow ;
3
4
@@ -357,17 +358,53 @@ impl VisitorState {
357
358
struct ImproperCTypesVisitor < ' a , ' tcx > {
358
359
cx : & ' a LateContext < ' tcx > ,
359
360
/// To prevent problems with recursive types,
360
- /// add a types-in-check cache.
361
- cache : FxHashSet < Ty < ' tcx > > ,
361
+ /// add a types-in-check cache and a depth counter.
362
+ recursion_limiter : RefCell < ( FxHashSet < Ty < ' tcx > > , usize ) > ,
363
+
362
364
/// The original type being checked, before we recursed
363
365
/// to any other types it contains.
364
366
base_ty : Ty < ' tcx > ,
365
367
base_fn_mode : CItemKind ,
366
368
}
367
369
370
+ /// Structure similar to a mutex guard, allocated for each type in-check
371
+ /// to let the ImproperCTypesVisitor know the current depth of the checking process.
372
+ struct ImproperCTypesVisitorDepthGuard < ' a , ' tcx , ' v > ( & ' v ImproperCTypesVisitor < ' a , ' tcx > ) ;
373
+
374
+ impl < ' a , ' tcx , ' v > Drop for ImproperCTypesVisitorDepthGuard < ' a , ' tcx , ' v > {
375
+ fn drop ( & mut self ) {
376
+ let mut limiter_guard = self . 0 . recursion_limiter . borrow_mut ( ) ;
377
+ let ( _, ref mut depth) = * limiter_guard;
378
+ * depth -= 1 ;
379
+ }
380
+ }
381
+
368
382
impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
369
383
fn new ( cx : & ' a LateContext < ' tcx > , base_ty : Ty < ' tcx > , base_fn_mode : CItemKind ) -> Self {
370
- Self { cx, base_ty, base_fn_mode, cache : FxHashSet :: default ( ) }
384
+ Self {
385
+ cx,
386
+ base_ty,
387
+ base_fn_mode,
388
+ recursion_limiter : RefCell :: new ( ( FxHashSet :: default ( ) , 0 ) ) ,
389
+ }
390
+ }
391
+
392
+ /// Protect against infinite recursion, for example
393
+ /// `struct S(*mut S);`, or issue #130310.
394
+ fn can_enter_type < ' v > (
395
+ & ' v self ,
396
+ ty : Ty < ' tcx > ,
397
+ ) -> Result < ImproperCTypesVisitorDepthGuard < ' a , ' tcx , ' v > , FfiResult < ' tcx > > {
398
+ // panic unlikely: this non-recursive function is the only place that
399
+ // borrows the refcell, outside of ImproperCTypesVisitorDepthGuard::drop()
400
+ let mut limiter_guard = self . recursion_limiter . borrow_mut ( ) ;
401
+ let ( ref mut cache, ref mut depth) = * limiter_guard;
402
+ if ( !cache. insert ( ty) ) || * depth >= 1024 {
403
+ Err ( FfiResult :: FfiSafe )
404
+ } else {
405
+ * depth += 1 ;
406
+ Ok ( ImproperCTypesVisitorDepthGuard ( self ) )
407
+ }
371
408
}
372
409
373
410
/// Checks if a simple numeric (int, float) type has an actual portable definition
@@ -390,7 +427,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
390
427
391
428
/// Checks if the given indirection (box,ref,pointer) is "ffi-safe".
392
429
fn visit_indirection (
393
- & mut self ,
430
+ & self ,
394
431
state : VisitorState ,
395
432
ty : Ty < ' tcx > ,
396
433
inner_ty : Ty < ' tcx > ,
@@ -438,7 +475,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
438
475
439
476
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
440
477
fn visit_variant_fields (
441
- & mut self ,
478
+ & self ,
442
479
state : VisitorState ,
443
480
ty : Ty < ' tcx > ,
444
481
def : AdtDef < ' tcx > ,
@@ -490,7 +527,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
490
527
}
491
528
492
529
fn visit_struct_or_union (
493
- & mut self ,
530
+ & self ,
494
531
state : VisitorState ,
495
532
ty : Ty < ' tcx > ,
496
533
def : AdtDef < ' tcx > ,
@@ -547,7 +584,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
547
584
}
548
585
549
586
fn visit_enum (
550
- & mut self ,
587
+ & self ,
551
588
state : VisitorState ,
552
589
ty : Ty < ' tcx > ,
553
590
def : AdtDef < ' tcx > ,
@@ -599,23 +636,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
599
636
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
600
637
/// representation which can be exported to C code).
601
638
fn visit_type (
602
- & mut self ,
639
+ & self ,
603
640
state : VisitorState ,
604
641
outer_ty : Option < Ty < ' tcx > > ,
605
642
ty : Ty < ' tcx > ,
606
643
) -> FfiResult < ' tcx > {
607
644
use FfiResult :: * ;
608
645
646
+ let _depth_guard = match self . can_enter_type ( ty) {
647
+ Ok ( guard) => guard,
648
+ Err ( ffi_res) => return ffi_res,
649
+ } ;
609
650
let tcx = self . cx . tcx ;
610
651
611
- // Protect against infinite recursion, for example
612
- // `struct S(*mut S);`.
613
- // FIXME: A recursion limit is necessary as well, for irregular
614
- // recursive types.
615
- if !self . cache . insert ( ty) {
616
- return FfiSafe ;
617
- }
618
-
619
652
match * ty. kind ( ) {
620
653
ty:: Adt ( def, args) => {
621
654
if let Some ( inner_ty) = ty. boxed_ty ( ) {
@@ -796,7 +829,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
796
829
}
797
830
}
798
831
799
- fn visit_for_opaque_ty ( & mut self , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
832
+ fn visit_for_opaque_ty ( & self , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
800
833
struct ProhibitOpaqueTypes ;
801
834
impl < ' tcx > ty:: TypeVisitor < TyCtxt < ' tcx > > for ProhibitOpaqueTypes {
802
835
type Result = ControlFlow < Ty < ' tcx > > ;
@@ -821,7 +854,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
821
854
}
822
855
}
823
856
824
- fn check_for_type ( & mut self , state : VisitorState , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
857
+ fn check_for_type ( & self , state : VisitorState , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
825
858
let ty = self . cx . tcx . try_normalize_erasing_regions ( self . cx . typing_env ( ) , ty) . unwrap_or ( ty) ;
826
859
827
860
match self . visit_for_opaque_ty ( ty) {
@@ -944,7 +977,7 @@ impl<'tcx> ImproperCTypesLint {
944
977
945
978
let all_types = iter:: zip ( visitor. tys . drain ( ..) , visitor. spans . drain ( ..) ) ;
946
979
all_types. for_each ( |( fn_ptr_ty, span) | {
947
- let mut visitor = ImproperCTypesVisitor :: new ( cx, fn_ptr_ty, fn_mode) ;
980
+ let visitor = ImproperCTypesVisitor :: new ( cx, fn_ptr_ty, fn_mode) ;
948
981
// TODO: make a check_for_fnptr
949
982
let ffi_res = visitor. check_for_type ( state, fn_ptr_ty) ;
950
983
@@ -992,9 +1025,9 @@ impl<'tcx> ImproperCTypesLint {
992
1025
ImproperCTypesVisitor :: check_struct_for_power_alignment ( cx, item, adt_def) ;
993
1026
}
994
1027
995
- fn check_foreign_static ( & mut self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
1028
+ fn check_foreign_static ( & self , cx : & LateContext < ' tcx > , id : hir:: OwnerId , span : Span ) {
996
1029
let ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ;
997
- let mut visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: Declaration ) ;
1030
+ let visitor = ImproperCTypesVisitor :: new ( cx, ty, CItemKind :: Declaration ) ;
998
1031
let ffi_res = visitor. check_for_type ( VisitorState :: StaticTy , ty) ;
999
1032
self . process_ffi_result ( cx, span, ffi_res, CItemKind :: Declaration ) ;
1000
1033
}
@@ -1012,14 +1045,14 @@ impl<'tcx> ImproperCTypesLint {
1012
1045
1013
1046
for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1014
1047
let state = VisitorState :: argument_from_fnmode ( fn_mode) ;
1015
- let mut visitor = ImproperCTypesVisitor :: new ( cx, * input_ty, fn_mode) ;
1048
+ let visitor = ImproperCTypesVisitor :: new ( cx, * input_ty, fn_mode) ;
1016
1049
let ffi_res = visitor. check_for_type ( state, * input_ty) ;
1017
1050
self . process_ffi_result ( cx, input_hir. span , ffi_res, fn_mode) ;
1018
1051
}
1019
1052
1020
1053
if let hir:: FnRetTy :: Return ( ret_hir) = decl. output {
1021
1054
let state = VisitorState :: return_from_fnmode ( fn_mode) ;
1022
- let mut visitor = ImproperCTypesVisitor :: new ( cx, sig. output ( ) , fn_mode) ;
1055
+ let visitor = ImproperCTypesVisitor :: new ( cx, sig. output ( ) , fn_mode) ;
1023
1056
let ffi_res = visitor. check_for_type ( state, sig. output ( ) ) ;
1024
1057
self . process_ffi_result ( cx, ret_hir. span , ffi_res, fn_mode) ;
1025
1058
}
0 commit comments