From: Jordan Rose Date: Fri, 22 Jun 2012 17:15:58 +0000 (+0000) Subject: [analyzer] Check for +raise:format: on subclasses of NSException as well. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6c234b1fd1da64a14a77433cb805cb1aa798512a;p=clang [analyzer] Check for +raise:format: on subclasses of NSException as well. We don't handle exceptions yet, so we treat them as sinks. ExprEngine hardcodes messages that are known to raise Objective-C exceptions like -raise, but it was only checking for +raise:format: and +raise:format:arguments: on NSException itself, not subclasses. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159010 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index 45ba0449f4..be9a26b1f5 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -132,6 +132,14 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); } +static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) { + if (!Class) + return false; + if (Class->getIdentifier() == II) + return true; + return isSubclass(Class->getSuperClass(), II); +} + void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, ExplodedNode *Pred, ExplodedNodeSet &Dst) { @@ -177,47 +185,50 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, // Dispatch to plug-in transfer function. evalObjCMessage(Bldr, msg, Pred, notNilState, RaisesException); } - } - else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) { - IdentifierInfo* ClsName = Iface->getIdentifier(); - Selector S = msg.getSelector(); - - // Check for special instance methods. - if (!NSExceptionII) { - ASTContext &Ctx = getContext(); - NSExceptionII = &Ctx.Idents.get("NSException"); - } - - if (ClsName == NSExceptionII) { - enum { NUM_RAISE_SELECTORS = 2 }; - - // Lazily create a cache of the selectors. - if (!NSExceptionInstanceRaiseSelectors) { + } else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) { + // Note that this branch also handles messages to super, not just + // class methods! + + // Check for special class methods. + if (!msg.isInstanceMessage()) { + if (!NSExceptionII) { ASTContext &Ctx = getContext(); - NSExceptionInstanceRaiseSelectors = - new Selector[NUM_RAISE_SELECTORS]; - SmallVector II; - unsigned idx = 0; - - // raise:format: - II.push_back(&Ctx.Idents.get("raise")); - II.push_back(&Ctx.Idents.get("format")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); - - // raise:format::arguments: - II.push_back(&Ctx.Idents.get("arguments")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); + NSExceptionII = &Ctx.Idents.get("NSException"); } - for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) - if (S == NSExceptionInstanceRaiseSelectors[i]) { - RaisesException = true; - break; + if (isSubclass(Iface, NSExceptionII)) { + enum { NUM_RAISE_SELECTORS = 2 }; + + // Lazily create a cache of the selectors. + if (!NSExceptionInstanceRaiseSelectors) { + ASTContext &Ctx = getContext(); + NSExceptionInstanceRaiseSelectors = + new Selector[NUM_RAISE_SELECTORS]; + SmallVector II; + unsigned idx = 0; + + // raise:format: + II.push_back(&Ctx.Idents.get("raise")); + II.push_back(&Ctx.Idents.get("format")); + NSExceptionInstanceRaiseSelectors[idx++] = + Ctx.Selectors.getSelector(II.size(), &II[0]); + + // raise:format:arguments: + II.push_back(&Ctx.Idents.get("arguments")); + NSExceptionInstanceRaiseSelectors[idx++] = + Ctx.Selectors.getSelector(II.size(), &II[0]); + } + + Selector S = msg.getSelector(); + for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) { + if (S == NSExceptionInstanceRaiseSelectors[i]) { + RaisesException = true; + break; + } } + } } - + // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. // Dispatch to plug-in transfer function. diff --git a/test/Analysis/NoReturn.m b/test/Analysis/NoReturn.m index ea2efd0617..1d948fa66f 100644 --- a/test/Analysis/NoReturn.m +++ b/test/Analysis/NoReturn.m @@ -76,3 +76,15 @@ int f3(int* x) { return *x; // no-warning } + +@interface CustomException : NSException +@end + +int testCustomException(int *x) { + if (x != 0) return 0; + + [CustomException raise:@"Blah" format:@"abc"]; + + return *x; // no-warning +} +