Skip to content

Commit 68b439c

Browse files
authored
Rollup merge of #138599 - adwinwhite:recursive-overflow, r=wesleywiser
avoid overflow when generating debuginfo for expanding recursive types Fixes #135093 Fixes #121538 Fixes #107362 Fixes #100618 Fixes #115994 The overflow happens because expanding recursive types keep creating new nested types when recurring into sub fields. I fixed that by returning an empty stub node when expanding recursion is detected.
2 parents 484abe9 + d5c4ed0 commit 68b439c

File tree

7 files changed

+66
-61
lines changed

7 files changed

+66
-61
lines changed

compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs

+48
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,16 @@ pub(super) fn stub<'ll, 'tcx>(
247247
StubInfo { metadata, unique_type_id }
248248
}
249249

250+
struct AdtStackPopGuard<'ll, 'tcx, 'a> {
251+
cx: &'a CodegenCx<'ll, 'tcx>,
252+
}
253+
254+
impl<'ll, 'tcx, 'a> Drop for AdtStackPopGuard<'ll, 'tcx, 'a> {
255+
fn drop(&mut self) {
256+
debug_context(self.cx).adt_stack.borrow_mut().pop();
257+
}
258+
}
259+
250260
/// This function enables creating debuginfo nodes that can recursively refer to themselves.
251261
/// It will first insert the given stub into the type map and only then execute the `members`
252262
/// and `generics` closures passed in. These closures have access to the stub so they can
@@ -261,6 +271,44 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
261271
) -> DINodeCreationResult<'ll> {
262272
assert_eq!(debug_context(cx).type_map.di_node_for_unique_id(stub_info.unique_type_id), None);
263273

274+
let mut _adt_stack_pop_guard = None;
275+
if let UniqueTypeId::Ty(ty, ..) = stub_info.unique_type_id
276+
&& let ty::Adt(adt_def, args) = ty.kind()
277+
{
278+
let def_id = adt_def.did();
279+
// If any sub type reference the original type definition and the sub type has a type
280+
// parameter that strictly contains the original parameter, the original type is a recursive
281+
// type that can expanding indefinitely. Example,
282+
// ```
283+
// enum Recursive<T> {
284+
// Recurse(*const Recursive<Wrap<T>>),
285+
// Item(T),
286+
// }
287+
// ```
288+
let is_expanding_recursive =
289+
debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| {
290+
if def_id == *parent_def_id {
291+
args.iter().zip(parent_args.iter()).any(|(arg, parent_arg)| {
292+
if let (Some(arg), Some(parent_arg)) = (arg.as_type(), parent_arg.as_type())
293+
{
294+
arg != parent_arg && arg.contains(parent_arg)
295+
} else {
296+
false
297+
}
298+
})
299+
} else {
300+
false
301+
}
302+
});
303+
if is_expanding_recursive {
304+
// FIXME: indicate that this is an expanding recursive type in stub metadata?
305+
return DINodeCreationResult::new(stub_info.metadata, false);
306+
} else {
307+
debug_context(cx).adt_stack.borrow_mut().push((def_id, args));
308+
_adt_stack_pop_guard = Some(AdtStackPopGuard { cx });
309+
}
310+
}
311+
264312
debug_context(cx).type_map.insert(stub_info.unique_type_id, stub_info.metadata);
265313

266314
let members: SmallVec<_> =

compiler/rustc_codegen_llvm/src/debuginfo/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
6666
created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>,
6767

6868
type_map: metadata::TypeMap<'ll, 'tcx>,
69+
adt_stack: RefCell<Vec<(DefId, GenericArgsRef<'tcx>)>>,
6970
namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
7071
recursion_marker_type: OnceCell<&'ll DIType>,
7172
}
@@ -80,6 +81,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
8081
builder,
8182
created_files: Default::default(),
8283
type_map: Default::default(),
84+
adt_stack: Default::default(),
8385
namespace_map: RefCell::new(Default::default()),
8486
recursion_marker_type: OnceCell::new(),
8587
}

tests/crashes/100618.rs

-12
This file was deleted.

tests/crashes/115994.rs

-17
This file was deleted.

tests/crashes/121538.rs

-30
This file was deleted.

tests/debuginfo/recursive-enum.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// gdb-command:run
55

66
// Test whether compiling a recursive enum definition crashes debug info generation. The test case
7-
// is taken from issue #11083.
7+
// is taken from issue #11083 and #135093.
88

99
#![allow(unused_variables)]
1010
#![feature(omit_gdb_pretty_printer_section)]
@@ -18,6 +18,21 @@ struct WindowCallbacks<'a> {
1818
pos_callback: Option<Box<FnMut(&Window, i32, i32) + 'a>>,
1919
}
2020

21+
enum ExpandingRecursive<T> {
22+
Recurse(Indirect<T>),
23+
Item(T),
24+
}
25+
26+
struct Indirect<U> {
27+
rec: *const ExpandingRecursive<Option<U>>,
28+
}
29+
30+
2131
fn main() {
2232
let x = WindowCallbacks { pos_callback: None };
33+
34+
// EXPANDING RECURSIVE
35+
let expanding_recursive: ExpandingRecursive<u64> = ExpandingRecursive::Recurse(Indirect {
36+
rec: &ExpandingRecursive::Item(Option::Some(42)),
37+
});
2338
}

tests/crashes/107362.rs renamed to tests/debuginfo/recursive-type-with-gat.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
//@ known-bug: #107362
21
//@ compile-flags: -Cdebuginfo=2
32

43
pub trait Functor

0 commit comments

Comments
 (0)