[PATCH] PR23175 (fix) - Infinite loop iterating Objective-C method declarations in categories when the AST was deserialized from an .ast file

Tom Honermann thonermann at coverity.com
Mon Apr 20 14:02:38 PDT 2015


Hi klimek,

This patch corrects several errors that result in incorrect Objective-C method declaration enumeration that occurs when an AST is deserialized from an .ast file.

There were two issues:

1) In lib/AST/DeclObjC.cpp, in ObjCImplDecl::setClassInterface(), the base class version (ObjCImplDecl) of (non-virtual) getIdentifier() was being called, but the derived class version (ObjCCategoryImplDecl) is what is required.  See this comment in include/clang/AST/DeclObjC.h:
     class ObjCCategoryImplDecl : public ObjCImplDecl {
     ...
     /// getIdentifier - Get the identifier that names the category
     /// interface associated with this implementation.
     /// FIXME: This is a bad API, we are hiding NamedDecl::getIdentifier()
     /// with a different meaning. For example:
     /// ((NamedDecl *)SomeCategoryImplDecl)->getIdentifier()
     /// returns the class interface name, whereas
     /// ((ObjCCategoryImplDecl *)SomeCategoryImplDecl)->getIdentifier()
     /// returns the category name.
     IdentifierInfo *getIdentifier() const {
       return Id;
     }
   I did not change the interface, but clearly, it would be a good idea to do so.  The patch uses the existing downcasted pointer to call the correct version.

2) With the above change, when deserializing a ObjCCategoryImplDecl instance, ObjCImplDecl::setClassInterface() was being called by ASTDeclReader::VisitObjCImplDecl() before the category name was deserialized in ASTDeclReader::VisitObjCCategoryImplDecl().  The patch delays the call to ObjCImplDecl::setClassInterface() until after the category name is deserialized and set.

REPOSITORY
  rL LLVM

http://reviews.llvm.org/D9127

Files:
  lib/AST/DeclObjC.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriterDecl.cpp

Index: lib/AST/DeclObjC.cpp
===================================================================
--- lib/AST/DeclObjC.cpp
+++ lib/AST/DeclObjC.cpp
@@ -1741,8 +1741,10 @@
 
   } else if (ObjCCategoryImplDecl *ImplD =
              dyn_cast_or_null<ObjCCategoryImplDecl>(this)) {
-    if (ObjCCategoryDecl *CD = IFace->FindCategoryDeclaration(getIdentifier()))
+    if (ObjCCategoryDecl *CD =
+        IFace->FindCategoryDeclaration(ImplD->getIdentifier())) {
       Ctx.setObjCImplementation(CD, ImplD);
+    }
   }
 
   ClassInterface = IFace;
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -981,17 +981,20 @@
 
 void ASTDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) {
   VisitObjCContainerDecl(D);
-  D->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
+  // For ObjCCategoryImplDecl, setClassInterface must not be called until the
+  // category identifier has been deserialized and set.  See PR23175.
 }
 
 void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
   VisitObjCImplDecl(D);
   D->setIdentifier(Reader.GetIdentifierInfo(F, Record, Idx));
   D->CategoryNameLoc = ReadSourceLocation(Record, Idx);
+  D->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
 }
 
 void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
   VisitObjCImplDecl(D);
+  D->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
   D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
   D->SuperLoc = ReadSourceLocation(Record, Idx);
   D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx));
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -695,19 +695,20 @@
 
 void ASTDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) {
   VisitObjCContainerDecl(D);
-  Writer.AddDeclRef(D->getClassInterface(), Record);
   // Abstract class (no need to define a stable serialization::DECL code).
 }
 
 void ASTDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
   VisitObjCImplDecl(D);
   Writer.AddIdentifierRef(D->getIdentifier(), Record);
   Writer.AddSourceLocation(D->getCategoryNameLoc(), Record);
+  Writer.AddDeclRef(D->getClassInterface(), Record);
   Code = serialization::DECL_OBJC_CATEGORY_IMPL;
 }
 
 void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
   VisitObjCImplDecl(D);
+  Writer.AddDeclRef(D->getClassInterface(), Record);
   Writer.AddDeclRef(D->getSuperClass(), Record);
   Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
   Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D9127.24061.patch
Type: text/x-patch
Size: 2798 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150420/2cdbef7e/attachment.bin>


More information about the cfe-commits mailing list