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