summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBalazs Benics <balazs.benics@sigmatechnology.se>2021-05-18 09:43:20 +0200
committerBalazs Benics <balazs.benics@sigmatechnology.se>2021-05-18 09:43:20 +0200
commit88ee91cd87794813f4394f82d2c693c8d766e1d2 (patch)
treee2807c8727c2c2e1ec04ddbe3ef5f08c063955fe
parentbbea361039c11dc2e6e281c80fa8aa569f1c7c2d (diff)
[ASTimporter] Remove decl from lookup only if it has decl context
In the case of TypedefDecls we set the DeclContext after we imported it. It turns out, it could lead to null pointer dereferences during the cleanup part of a failed import. This patch demonstrates this issue and fixes it by checking if the DeclContext is available or not. Reviewed By: shafik Differential Revision: https://reviews.llvm.org/D102640
-rw-r--r--clang/lib/AST/ASTImporter.cpp6
-rw-r--r--clang/unittests/AST/ASTImporterTest.cpp34
2 files changed, 39 insertions, 1 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index dd11e3662148..9caa1178c0b7 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -8383,7 +8383,11 @@ Expected<Decl *> ASTImporter::Import(Decl *FromD) {
// traverse of the 'to' context).
auto PosF = ImportedFromDecls.find(ToD);
if (PosF != ImportedFromDecls.end()) {
- SharedState->removeDeclFromLookup(ToD);
+ // In the case of TypedefNameDecl we create the Decl first and only
+ // then we import and set its DeclContext. So, the DC might not be set
+ // when we reach here.
+ if (ToD->getDeclContext())
+ SharedState->removeDeclFromLookup(ToD);
ImportedFromDecls.erase(PosF);
}
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index e62203f28657..db87b2ab5e9c 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -5225,6 +5225,40 @@ TEST_P(ErrorHandlingTest, ErrorIsNotPropagatedFromMemberToNamespace) {
EXPECT_TRUE(ImportedOK);
}
+TEST_P(ErrorHandlingTest, ODRViolationWithinTypedefDecls) {
+ // Importing `z` should fail - instead of crashing - due to an ODR violation.
+ // The `bar::e` typedef sets it's DeclContext after the import is done.
+ // However, if the importation fails, it will be left as a nullptr.
+ // During the cleanup of the failed import, we should check whether the
+ // DeclContext is null or not - instead of dereferencing that unconditionally.
+ constexpr auto ToTUCode = R"(
+ namespace X {
+ struct bar {
+ int odr_violation;
+ };
+ })";
+ constexpr auto FromTUCode = R"(
+ namespace X {
+ enum b {};
+ struct bar {
+ typedef b e;
+ static e d;
+ };
+ }
+ int z = X::bar::d;
+ )";
+ Decl *ToTU = getToTuDecl(ToTUCode, Lang_CXX11);
+ static_cast<void>(ToTU);
+ Decl *FromTU = getTuDecl(FromTUCode, Lang_CXX11);
+ auto *FromZ =
+ FirstDeclMatcher<VarDecl>().match(FromTU, varDecl(hasName("z")));
+ ASSERT_TRUE(FromZ);
+ ASSERT_TRUE(FromZ->hasInit());
+
+ auto *ImportedZ = Import(FromZ, Lang_CXX11);
+ EXPECT_FALSE(ImportedZ);
+}
+
// An error should be set for a class if it had a previous import with an error
// from another TU.
TEST_P(ErrorHandlingTest,