From 3004a759bcdf7b0a2a3a4220ed216d20defbd081 Mon Sep 17 00:00:00 2001 From: Michael Buch Date: Wed, 14 Sep 2022 22:36:07 -0400 Subject: [PATCH] [lldb][tests][gmodules] Test for expression evaluator crash for types referencing the same template The problem here is that the ASTImporter adds the template class member FieldDecl to the DeclContext twice. This happens because we don't construct a `LookupPtr` for decls that originate from modules and thus the ASTImporter never realizes that the FieldDecl has already been imported. These duplicate decls then break the assumption of the LayoutBuilder which expects only a single member decl to exist. The test will be fixed by a follow-up revision and is thus skipped for now. Differential Revision: https://reviews.llvm.org/D133944 --- .../gmodules/template-with-same-arg/Makefile | 3 + .../TestTemplateWithSameArg.py | 72 +++++++++++++++++++ .../template-with-same-arg/base_module.cpp | 3 + .../template-with-same-arg/base_module.h | 6 ++ .../gmodules/template-with-same-arg/main.cpp | 15 ++++ .../template-with-same-arg/module.modulemap | 14 ++++ .../template-with-same-arg/module1.cpp | 3 + .../gmodules/template-with-same-arg/module1.h | 10 +++ .../template-with-same-arg/module2.cpp | 3 + .../gmodules/template-with-same-arg/module2.h | 10 +++ 10 files changed, 139 insertions(+) create mode 100644 lldb/test/API/lang/cpp/gmodules/template-with-same-arg/Makefile create mode 100644 lldb/test/API/lang/cpp/gmodules/template-with-same-arg/TestTemplateWithSameArg.py create mode 100644 lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.cpp create mode 100644 lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.h create mode 100644 lldb/test/API/lang/cpp/gmodules/template-with-same-arg/main.cpp create mode 100644 lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module.modulemap create mode 100644 lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.cpp create mode 100644 lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.h create mode 100644 lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.cpp create mode 100644 lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.h diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/Makefile b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/Makefile new file mode 100644 index 000000000000..2d13591d6ccd --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp module1.cpp module2.cpp base_module.cpp + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/TestTemplateWithSameArg.py b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/TestTemplateWithSameArg.py new file mode 100644 index 000000000000..0ad4603651a1 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/TestTemplateWithSameArg.py @@ -0,0 +1,72 @@ +""" +Tests the scenario where we evaluate expressions +of two types in different modules that reference +a class template instantiated with the same +template argument. + +Note that, +1. Since the decls originate from modules, LLDB + marks them as such and Clang doesn't create + a LookupPtr map on the corresponding DeclContext. + This prevents regular DeclContext::lookup from + succeeding. +2. Because we reference the same class template + from two different modules we get a redeclaration + chain for the class's ClassTemplateSpecializationDecl. + The importer will import all FieldDecls into the + same DeclContext on the redeclaration chain. If + we don't do the bookkeeping correctly we end up + with duplicate decls on the same DeclContext leading + to crashes down the line. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestTemplateWithSameArg(TestBase): + + def setUp(self): + TestBase.setUp(self) + self.build() + self.main_source_file = lldb.SBFileSpec("main.cpp") + + @add_test_categories(["gmodules"]) + @skipIf(bugnumber='rdar://96581048') + def test_same_template_arg(self): + lldbutil.run_to_source_breakpoint(self, "Break here", self.main_source_file) + + self.expect_expr("FromMod1", result_type="ClassInMod1", result_children=[ + ValueCheck(name="VecInMod1", children=[ + ValueCheck(name="Member", value="137") + ]) + ]) + + self.expect_expr("FromMod2", result_type="ClassInMod2", result_children=[ + ValueCheck(name="VecInMod2", children=[ + ValueCheck(name="Member", value="42") + ]) + ]) + + @add_test_categories(["gmodules"]) + @skipIf(bugnumber='rdar://96581048') + def test_duplicate_decls(self): + lldbutil.run_to_source_breakpoint(self, "Break here", self.main_source_file) + + self.expect_expr("(intptr_t)&FromMod1 + (intptr_t)&FromMod2") + + # Make sure we only have a single 'Member' decl on the AST + self.filecheck("target module dump ast", __file__) +# CHECK: ClassTemplateSpecializationDecl {{.*}} imported in Module2 struct ClassInMod3 definition +# CHECK-NEXT: |-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable pod trivial +# CHECK-NEXT: | |-DefaultConstructor exists trivial needs_implicit +# CHECK-NEXT: | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param +# CHECK-NEXT: | |-MoveConstructor exists simple trivial needs_implicit +# CHECK-NEXT: | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param +# CHECK-NEXT: | |-MoveAssignment exists simple trivial needs_implicit +# CHECK-NEXT: | `-Destructor simple irrelevant trivial needs_implicit +# CHECK-NEXT: |-TemplateArgument type 'int' +# CHECK-NEXT: | `-BuiltinType {{.*}} 'int' +# CHECK-NEXT: `-FieldDecl {{.*}} imported in Module2 Member 'int' diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.cpp b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.cpp new file mode 100644 index 000000000000..d706a518be08 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.cpp @@ -0,0 +1,3 @@ +#include "base_module.h" + +namespace crash {} // namespace crash diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.h b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.h new file mode 100644 index 000000000000..bb0bfe7fdab4 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.h @@ -0,0 +1,6 @@ +#ifndef MOD3_H_IN +#define MOD3_H_IN + +template struct ClassInMod3 { int Member = 0; }; + +#endif // _H_IN diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/main.cpp b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/main.cpp new file mode 100644 index 000000000000..845e6b2c5343 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/main.cpp @@ -0,0 +1,15 @@ +#include "module1.h" +#include "module2.h" + +#include + +int main() { + ClassInMod1 FromMod1; + ClassInMod2 FromMod2; + + FromMod1.VecInMod1.Member = 137; + FromMod2.VecInMod2.Member = 42; + + std::puts("Break here"); + return 0; +} diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module.modulemap b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module.modulemap new file mode 100644 index 000000000000..ec0d7c561450 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module.modulemap @@ -0,0 +1,14 @@ +module Module1 { + header "module1.h" + export * +} + +module Module2 { + header "module2.h" + export * +} + +module BaseModule { + header "base_module.h" + export * +} diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.cpp b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.cpp new file mode 100644 index 000000000000..aa951f8f0d34 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.cpp @@ -0,0 +1,3 @@ +#include "module1.h" + +namespace crash {} // namespace crash diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.h b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.h new file mode 100644 index 000000000000..8a911ed766de --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.h @@ -0,0 +1,10 @@ +#ifndef MOD1_H_IN +#define MOD1_H_IN + +#include "base_module.h" + +struct ClassInMod1 { + ClassInMod3 VecInMod1; +}; + +#endif // _H_IN diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.cpp b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.cpp new file mode 100644 index 000000000000..fd94461cc4c9 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.cpp @@ -0,0 +1,3 @@ +#include "module2.h" + +namespace crash {} // namespace crash diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.h b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.h new file mode 100644 index 000000000000..130088162985 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.h @@ -0,0 +1,10 @@ +#ifndef MOD2_H_IN +#define MOD2_H_IN + +#include "base_module.h" + +struct ClassInMod2 { + ClassInMod3 VecInMod2; +}; + +#endif