@@ -18,6 +18,7 @@ use rustc_target::spec::abi::Abi as SpecAbi;
18
18
use tracing:: debug;
19
19
use { rustc_ast as ast, rustc_attr as attr, rustc_hir as hir} ;
20
20
21
+ use crate :: errors:: RecursionLimitReached ;
21
22
use crate :: lints:: {
22
23
AmbiguousWidePointerComparisons , AmbiguousWidePointerComparisonsAddrMetadataSuggestion ,
23
24
AmbiguousWidePointerComparisonsAddrSuggestion , AtomicOrderingFence , AtomicOrderingLoad ,
@@ -991,12 +992,15 @@ struct CTypesVisitorState<'tcx> {
991
992
/// The original type being checked, before we recursed
992
993
/// to any other types it contains.
993
994
base_ty : Ty < ' tcx > ,
995
+ /// Number of times we recursed while checking the type
996
+ recursion_depth : usize ,
994
997
}
995
998
996
999
enum FfiResult < ' tcx > {
997
1000
FfiSafe ,
998
1001
FfiPhantom ( Ty < ' tcx > ) ,
999
1002
FfiUnsafe { ty : Ty < ' tcx > , reason : DiagMessage , help : Option < DiagMessage > } ,
1003
+ RecursionLimitReached ,
1000
1004
}
1001
1005
1002
1006
pub ( crate ) fn nonnull_optimization_guaranteed < ' tcx > (
@@ -1270,7 +1274,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1270
1274
// `()` fields are FFI-safe!
1271
1275
FfiUnsafe { ty, .. } if ty. is_unit ( ) => false ,
1272
1276
FfiPhantom ( ..) => true ,
1273
- r @ FfiUnsafe { .. } => return r,
1277
+ r => return r,
1274
1278
}
1275
1279
}
1276
1280
@@ -1296,12 +1300,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1296
1300
1297
1301
// Protect against infinite recursion, for example
1298
1302
// `struct S(*mut S);`.
1299
- // FIXME: A recursion limit is necessary as well, for irregular
1300
- // recursive types.
1301
1303
if !acc. cache . insert ( ty) {
1302
1304
return FfiSafe ;
1303
1305
}
1304
1306
1307
+ // Additional recursion check for more complex types like
1308
+ // `struct A<T> { v: *const A<A<T>>, ... }` for which the
1309
+ // cache check above won't be enough (fixes #130310)
1310
+ if !tcx. recursion_limit ( ) . value_within_limit ( acc. recursion_depth ) {
1311
+ return RecursionLimitReached ;
1312
+ }
1313
+
1314
+ acc. recursion_depth += 1 ;
1315
+
1305
1316
match * ty. kind ( ) {
1306
1317
ty:: Adt ( def, args) => {
1307
1318
if let Some ( boxed) = ty. boxed_ty ( )
@@ -1644,7 +1655,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1644
1655
return ;
1645
1656
}
1646
1657
1647
- let mut acc = CTypesVisitorState { cache : FxHashSet :: default ( ) , base_ty : ty } ;
1658
+ let mut acc =
1659
+ CTypesVisitorState { cache : FxHashSet :: default ( ) , base_ty : ty, recursion_depth : 0 } ;
1648
1660
match self . check_type_for_ffi ( & mut acc, ty) {
1649
1661
FfiResult :: FfiSafe => { }
1650
1662
FfiResult :: FfiPhantom ( ty) => {
@@ -1658,6 +1670,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1658
1670
FfiResult :: FfiUnsafe { ty, reason, help } => {
1659
1671
self . emit_ffi_unsafe_type_lint ( ty, sp, reason, help) ;
1660
1672
}
1673
+ FfiResult :: RecursionLimitReached => {
1674
+ self . cx . tcx . dcx ( ) . emit_err ( RecursionLimitReached {
1675
+ ty,
1676
+ span : sp,
1677
+ action : format ! ( "checking type `{ty}` for FFI safety" ) ,
1678
+ } ) ;
1679
+ }
1661
1680
}
1662
1681
}
1663
1682
0 commit comments