Skip to content

fix(debuginfo): handle false positives in overflow check #145297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 38 additions & 16 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
&& let ty::Adt(adt_def, args) = ty.kind()
{
let def_id = adt_def.did();
// If any sub type reference the original type definition and the sub type has a type
// If any child type references the original type definition and the child type has a type
// parameter that strictly contains the original parameter, the original type is a recursive
// type that can expanding indefinitely. Example,
// ```
Expand All @@ -285,21 +285,43 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
// Item(T),
// }
// ```
let is_expanding_recursive = adt_def.is_enum()
&& debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| {
if def_id == *parent_def_id {
args.iter().zip(parent_args.iter()).any(|(arg, parent_arg)| {
if let (Some(arg), Some(parent_arg)) = (arg.as_type(), parent_arg.as_type())
{
arg != parent_arg && arg.contains(parent_arg)
} else {
false
}
})
} else {
false
}
});
let is_expanding_recursive = {
let stack = debug_context(cx).adt_stack.borrow();
stack
.iter()
.enumerate()
.rev()
.skip(1)
.filter(|(_, (ancestor_def_id, _))| def_id == *ancestor_def_id)
.any(|(ancestor_index, (_, ancestor_args))| {
args.iter()
.zip(ancestor_args.iter())
.filter_map(|(arg, ancestor_arg)| arg.as_type().zip(ancestor_arg.as_type()))
.any(|(arg, ancestor_arg)|
// Strictly contains.
(arg != ancestor_arg && arg.contains(ancestor_arg))
// Check all types between current and ancestor use the
// ancestor_arg.
// Otherwise, duplicate wrappers in normal recursive type may be
// regarded as expanding.
// ```
// struct Recursive {
// a: Box<Box<Recursive>>,
// }
// ```
// It can produce an ADT stack like this,
// - Box<Recursive>
// - Recursive
// - Box<Box<Recursive>>
&& stack[ancestor_index + 1..stack.len()].iter().all(
|(_, intermediate_args)|
intermediate_args
.iter()
.filter_map(|arg| arg.as_type())
.any(|mid_arg| mid_arg.contains(ancestor_arg))
))
})
};
if is_expanding_recursive {
// FIXME: indicate that this is an expanding recursive type in stub metadata?
return DINodeCreationResult::new(stub_info.metadata, false);
Expand Down
9 changes: 9 additions & 0 deletions tests/debuginfo/recursive-struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@

use self::Opt::{Empty, Val};
use std::boxed::Box as B;
use std::marker::PhantomData;

enum Opt<T> {
Empty,
Expand Down Expand Up @@ -98,6 +99,11 @@ struct LongCycleWithAnonymousTypes {
value: usize,
}

struct Expanding<T> {
a: PhantomData<T>,
b: *const Expanding<(T, T)>,
}

// This test case makes sure that recursive structs are properly described. The Node structs are
// generic so that we can have a new type (that newly needs to be described) for the different
// cases. The potential problem with recursive types is that the DI generation algorithm gets
Expand Down Expand Up @@ -205,6 +211,9 @@ fn main() {
value: 30
})))));

// This type can generate new instances infinitely if not handled properly.
std::hint::black_box(Expanding::<()> { a: PhantomData, b: std::ptr::null() });

zzz(); // #break
}

Expand Down
Loading