arphaman created this revision.
arphaman added reviewers: manmanren, mehdi_amini.
arphaman added a subscriber: cfe-commits.
arphaman set the repository for this revision to rL LLVM.

This patch fixes an infinite loop that occurs when clang tries to iterate over 
redeclaration of a method that was declared in an invalid `@interface`. The 
existing validity checks don't catch this as that `@interface` is a duplicate 
of a previously declared valid `@interface` declaration, so we have to verify 
that the found redeclaration is in a valid declaration context.


Repository:
  rL LLVM

https://reviews.llvm.org/D26664

Files:
  lib/AST/DeclObjC.cpp
  test/SemaObjC/method-redecls-invalid-interface.m


Index: test/SemaObjC/method-redecls-invalid-interface.m
===================================================================
--- /dev/null
+++ test/SemaObjC/method-redecls-invalid-interface.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wdocumentation -Wno-objc-root-class 
%s
+// rdar://29220965
+
+@interface InvalidInterface { // expected-note {{previous definition is here}}
+  int *_property;
+}
+
+@end
+
+/*!
+ */
+
+@interface InvalidInterface // expected-error {{duplicate interface definition 
for class 'InvalidInterface'}}
+@property int *property;
+
+-(void) method;
+@end
+
+@implementation InvalidInterface
+-(void) method { }
+@end
Index: lib/AST/DeclObjC.cpp
===================================================================
--- lib/AST/DeclObjC.cpp
+++ lib/AST/DeclObjC.cpp
@@ -832,6 +832,18 @@
   setParamsAndSelLocs(C, Params, SelLocs);
 }
 
+/// Ensures that the discovered method redeclaration has a valid declaration
+/// context. Used by ObjCMethodDecl::getNextRedeclarationImpl to prevent
+/// infinite loops when iterating redeclarations in a partially invalid AST.
+static ObjCMethodDecl *ensureRedeclHasValidContext(ObjCMethodDecl *Redecl) {
+  if (!Redecl)
+    return nullptr;
+  if (const auto *Ctx = cast<Decl>(Redecl->getDeclContext()))
+    if (Ctx->isInvalidDecl())
+      return nullptr;
+  return Redecl;
+}
+
 /// \brief A definition will return its interface declaration.
 /// An interface declaration will return its definition.
 /// Otherwise it will return itself.
@@ -849,24 +861,28 @@
     if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
       if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD))
         if (!ImplD->isInvalidDecl())
-          Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+          Redecl = ensureRedeclHasValidContext(
+              ImplD->getMethod(getSelector(), isInstanceMethod()));
 
     } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) {
       if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD))
         if (!ImplD->isInvalidDecl())
-          Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+          Redecl = ensureRedeclHasValidContext(
+              ImplD->getMethod(getSelector(), isInstanceMethod()));
 
     } else if (ObjCImplementationDecl *ImplD =
                  dyn_cast<ObjCImplementationDecl>(CtxD)) {
       if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
         if (!IFD->isInvalidDecl())
-          Redecl = IFD->getMethod(getSelector(), isInstanceMethod());
+          Redecl = ensureRedeclHasValidContext(
+              IFD->getMethod(getSelector(), isInstanceMethod()));
 
     } else if (ObjCCategoryImplDecl *CImplD =
                  dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
       if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
         if (!CatD->isInvalidDecl())
-          Redecl = CatD->getMethod(getSelector(), isInstanceMethod());
+          Redecl = ensureRedeclHasValidContext(
+              CatD->getMethod(getSelector(), isInstanceMethod()));
     }
   }
 


Index: test/SemaObjC/method-redecls-invalid-interface.m
===================================================================
--- /dev/null
+++ test/SemaObjC/method-redecls-invalid-interface.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wdocumentation -Wno-objc-root-class %s
+// rdar://29220965
+
+@interface InvalidInterface { // expected-note {{previous definition is here}}
+  int *_property;
+}
+
+@end
+
+/*!
+ */
+
+@interface InvalidInterface // expected-error {{duplicate interface definition for class 'InvalidInterface'}}
+@property int *property;
+
+-(void) method;
+@end
+
+@implementation InvalidInterface
+-(void) method { }
+@end
Index: lib/AST/DeclObjC.cpp
===================================================================
--- lib/AST/DeclObjC.cpp
+++ lib/AST/DeclObjC.cpp
@@ -832,6 +832,18 @@
   setParamsAndSelLocs(C, Params, SelLocs);
 }
 
+/// Ensures that the discovered method redeclaration has a valid declaration
+/// context. Used by ObjCMethodDecl::getNextRedeclarationImpl to prevent
+/// infinite loops when iterating redeclarations in a partially invalid AST.
+static ObjCMethodDecl *ensureRedeclHasValidContext(ObjCMethodDecl *Redecl) {
+  if (!Redecl)
+    return nullptr;
+  if (const auto *Ctx = cast<Decl>(Redecl->getDeclContext()))
+    if (Ctx->isInvalidDecl())
+      return nullptr;
+  return Redecl;
+}
+
 /// \brief A definition will return its interface declaration.
 /// An interface declaration will return its definition.
 /// Otherwise it will return itself.
@@ -849,24 +861,28 @@
     if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
       if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD))
         if (!ImplD->isInvalidDecl())
-          Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+          Redecl = ensureRedeclHasValidContext(
+              ImplD->getMethod(getSelector(), isInstanceMethod()));
 
     } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) {
       if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD))
         if (!ImplD->isInvalidDecl())
-          Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+          Redecl = ensureRedeclHasValidContext(
+              ImplD->getMethod(getSelector(), isInstanceMethod()));
 
     } else if (ObjCImplementationDecl *ImplD =
                  dyn_cast<ObjCImplementationDecl>(CtxD)) {
       if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
         if (!IFD->isInvalidDecl())
-          Redecl = IFD->getMethod(getSelector(), isInstanceMethod());
+          Redecl = ensureRedeclHasValidContext(
+              IFD->getMethod(getSelector(), isInstanceMethod()));
 
     } else if (ObjCCategoryImplDecl *CImplD =
                  dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
       if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
         if (!CatD->isInvalidDecl())
-          Redecl = CatD->getMethod(getSelector(), isInstanceMethod());
+          Redecl = ensureRedeclHasValidContext(
+              CatD->getMethod(getSelector(), isInstanceMethod()));
     }
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to