Skip to content

Commit 2ec7eab

Browse files
committed
ImproperCTypes: add recursion limit
Simple change to stop irregular recursive types from causing infinitely-deep recursion in type checking.
1 parent eec85cd commit 2ec7eab

File tree

3 files changed

+46
-23
lines changed

3 files changed

+46
-23
lines changed

compiler/rustc_lint/src/types/improper_ctypes.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,8 @@ struct VisitorState {
347347
/// Flags describing both the immediate context in which the current mir::Ty is,
348348
/// linked to how it relates to its parent mir::Ty (or lack thereof).
349349
outer_ty_kind: OuterTyKind,
350+
/// Type recursion depth, to prevent infinite recursion
351+
depth: usize,
350352
}
351353

352354
impl RootUseFlags {
@@ -374,6 +376,7 @@ impl VisitorState {
374376
Self {
375377
root_use_flags: self.root_use_flags,
376378
outer_ty_kind: OuterTyKind::from_outer_ty(current_ty),
379+
depth: self.depth + 1,
377380
}
378381
}
379382
/// From an existing state, compute the state of any subtype of the current type.
@@ -387,12 +390,13 @@ impl VisitorState {
387390
FnPos::Arg => RootUseFlags::ARGUMENT_TY_IN_FNPTR,
388391
},
389392
outer_ty_kind: OuterTyKind::from_outer_ty(current_ty),
393+
depth: self.depth + 1,
390394
}
391395
}
392396

393397
/// Generate the state for an "outermost" type that needs to be checked
394398
fn entry_point(root_use_flags: RootUseFlags) -> Self {
395-
Self { root_use_flags, outer_ty_kind: OuterTyKind::None }
399+
Self { root_use_flags, outer_ty_kind: OuterTyKind::None, depth: 0 }
396400
}
397401

398402
/// Get the proper visitor state for a given function's arguments or return type.
@@ -718,9 +722,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
718722

719723
// Protect against infinite recursion, for example
720724
// `struct S(*mut S);`.
721-
// FIXME: A recursion limit is necessary as well, for irregular
722-
// recursive types.
723-
if !self.cache.insert(ty) {
725+
if !(self.cache.insert(ty) && self.cx.tcx.recursion_limit().value_within_limit(state.depth))
726+
{
724727
return FfiSafe;
725728
}
726729

@@ -935,20 +938,25 @@ impl<'tcx> ImproperCTypesLint {
935938
fn_mode: CItemKind,
936939
) {
937940
struct FnPtrFinder<'tcx> {
941+
current_depth: usize,
942+
depths: Vec<usize>,
938943
spans: Vec<Span>,
939944
tys: Vec<Ty<'tcx>>,
940945
}
941946

942947
impl<'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'tcx> {
943948
fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
944949
debug!(?ty);
950+
self.current_depth += 1;
945951
if let hir::TyKind::FnPtr(hir::FnPtrTy { abi, .. }) = ty.kind
946952
&& !abi.is_rustic_abi()
947953
{
954+
self.depths.push(self.current_depth);
948955
self.spans.push(ty.span);
949956
}
950957

951958
hir::intravisit::walk_ty(self, ty);
959+
self.current_depth -= 1;
952960
}
953961
}
954962

@@ -966,15 +974,24 @@ impl<'tcx> ImproperCTypesLint {
966974
}
967975
}
968976

969-
let mut visitor = FnPtrFinder { spans: Vec::new(), tys: Vec::new() };
977+
let mut visitor = FnPtrFinder {
978+
spans: Vec::new(),
979+
tys: Vec::new(),
980+
depths: Vec::new(),
981+
current_depth: 0,
982+
};
970983
ty.visit_with(&mut visitor);
971984
visitor.visit_ty_unambig(hir_ty);
972985

973-
let all_types = iter::zip(visitor.tys.drain(..), visitor.spans.drain(..));
974-
for (fn_ptr_ty, span) in all_types {
986+
let all_types = iter::zip(
987+
visitor.depths.drain(..),
988+
iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)),
989+
);
990+
for (depth, (fn_ptr_ty, span)) in all_types {
975991
let mut visitor = ImproperCTypesVisitor::new(cx, fn_ptr_ty, fn_mode);
992+
let bridge_state = VisitorState { depth, ..state };
976993
// FIXME(ctypes): make a check_for_fnptr
977-
let ffi_res = visitor.check_type(state, fn_ptr_ty);
994+
let ffi_res = visitor.check_type(bridge_state, fn_ptr_ty);
978995

979996
self.process_ffi_result(cx, span, ffi_res, fn_mode);
980997
}

tests/crashes/130310.rs

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ check-pass
2+
3+
//! this test checks that irregular recursive types do not cause stack overflow in ImproperCTypes
4+
//! Issue: https://github.com/rust-lang/rust/issues/94223
5+
6+
#![deny(improper_ctypes, improper_ctypes_definitions)]
7+
8+
use std::marker::PhantomData;
9+
10+
#[repr(C)]
11+
struct A<T> {
12+
a: *const A<A<T>>, // without a recursion limit, checking this ends up creating checks for
13+
// infinitely deep types the likes of `A<A<A<A<A<A<...>>>>>>`
14+
p: PhantomData<T>,
15+
}
16+
17+
extern "C" {
18+
fn f(a: *const A<()>);
19+
}
20+
21+
fn main() {}

0 commit comments

Comments
 (0)