[cfe-commits] r156699 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp test/Analysis/retain-release-path-notes.m test/Analysis/retain-release.m
Jordy Rose
jediknil at belkadan.com
Fri May 11 22:10:43 PDT 2012
Author: jrose
Date: Sat May 12 00:10:43 2012
New Revision: 156699
URL: http://llvm.org/viewvc/llvm-project?rev=156699&view=rev
Log:
[analyzer] RetainCountChecker: track ObjC boxed expression objects.
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
cfe/trunk/test/Analysis/retain-release-path-notes.m
cfe/trunk/test/Analysis/retain-release.m
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=156699&r1=156698&r2=156699&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Sat May 12 00:10:43 2012
@@ -1867,6 +1867,15 @@
return false;
}
+static bool isNumericLiteralExpression(const Expr *E) {
+ // FIXME: This set of cases was copied from SemaExprObjC.
+ return isa<IntegerLiteral>(E) ||
+ isa<CharacterLiteral>(E) ||
+ isa<FloatingLiteral>(E) ||
+ isa<ObjCBoolLiteralExpr>(E) ||
+ isa<CXXBoolLiteralExpr>(E);
+}
+
static bool isPropertyAccess(const Stmt *S, ParentMap &PM) {
unsigned maxDepth = 4;
while (S && maxDepth) {
@@ -1916,6 +1925,24 @@
else if (isa<ObjCDictionaryLiteral>(S)) {
os << "NSDictionary literal is an object with a +0 retain count";
}
+ else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
+ if (isNumericLiteralExpression(BL->getSubExpr()))
+ os << "NSNumber literal is an object with a +0 retain count";
+ else {
+ const ObjCInterfaceDecl *BoxClass = 0;
+ if (const ObjCMethodDecl *Method = BL->getBoxingMethod())
+ BoxClass = Method->getClassInterface();
+
+ // We should always be able to find the boxing class interface,
+ // but consider this future-proofing.
+ if (BoxClass)
+ os << *BoxClass << " b";
+ else
+ os << "B";
+
+ os << "oxed expression produces an object with a +0 retain count";
+ }
+ }
else {
if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
// Get the name of the callee (if it is available).
@@ -2324,6 +2351,7 @@
check::PostStmt<CXXConstructExpr>,
check::PostStmt<ObjCArrayLiteral>,
check::PostStmt<ObjCDictionaryLiteral>,
+ check::PostStmt<ObjCBoxedExpr>,
check::PostObjCMessage,
check::PreStmt<ReturnStmt>,
check::RegionChanges,
@@ -2470,6 +2498,8 @@
void checkPostStmt(const CXXConstructExpr *CE, CheckerContext &C) const;
void checkPostStmt(const ObjCArrayLiteral *AL, CheckerContext &C) const;
void checkPostStmt(const ObjCDictionaryLiteral *DL, CheckerContext &C) const;
+ void checkPostStmt(const ObjCBoxedExpr *BE, CheckerContext &C) const;
+
void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const;
void checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &Call,
@@ -2721,6 +2751,21 @@
processObjCLiterals(C, DL);
}
+void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
+ CheckerContext &C) const {
+ const ExplodedNode *Pred = C.getPredecessor();
+ const LocationContext *LCtx = Pred->getLocationContext();
+ ProgramStateRef State = Pred->getState();
+
+ if (SymbolRef Sym = State->getSVal(Ex, LCtx).getAsSymbol()) {
+ QualType ResultTy = Ex->getType();
+ State = State->set<RefBindings>(Sym, RefVal::makeNotOwned(RetEffect::ObjC,
+ ResultTy));
+ }
+
+ C.addTransition(State);
+}
+
void RetainCountChecker::checkPostObjCMessage(const ObjCMessage &Msg,
CheckerContext &C) const {
ProgramStateRef state = C.getState();
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=156699&r1=156698&r2=156699&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Sat May 12 00:10:43 2012
@@ -588,7 +588,6 @@
case Stmt::ObjCIsaExprClass:
case Stmt::ObjCProtocolExprClass:
case Stmt::ObjCSelectorExprClass:
- case Expr::ObjCBoxedExprClass:
case Stmt::ParenListExprClass:
case Stmt::PredefinedExprClass:
case Stmt::ShuffleVectorExprClass:
@@ -628,22 +627,24 @@
}
case Expr::ObjCArrayLiteralClass:
- case Expr::ObjCDictionaryLiteralClass: {
+ case Expr::ObjCDictionaryLiteralClass:
+ // FIXME: explicitly model with a region and the actual contents
+ // of the container. For now, conjure a symbol.
+ case Expr::ObjCBoxedExprClass: {
Bldr.takeNodes(Pred);
ExplodedNodeSet preVisit;
getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
- // FIXME: explicitly model with a region and the actual contents
- // of the container. For now, conjure a symbol.
ExplodedNodeSet Tmp;
StmtNodeBuilder Bldr2(preVisit, Tmp, *currentBuilderContext);
+ const Expr *Ex = cast<Expr>(S);
+ QualType resultType = Ex->getType();
+
for (ExplodedNodeSet::iterator it = preVisit.begin(), et = preVisit.end();
it != et; ++it) {
ExplodedNode *N = *it;
- const Expr *Ex = cast<Expr>(S);
- QualType resultType = Ex->getType();
const LocationContext *LCtx = N->getLocationContext();
SVal result =
svalBuilder.getConjuredSymbolVal(0, Ex, LCtx, resultType,
Modified: cfe/trunk/test/Analysis/retain-release-path-notes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release-path-notes.m?rev=156699&r1=156698&r2=156699&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/retain-release-path-notes.m (original)
+++ cfe/trunk/test/Analysis/retain-release-path-notes.m Sat May 12 00:10:43 2012
@@ -130,3 +130,51 @@
return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}
@end
+
+
+typedef unsigned long NSUInteger;
+
+ at interface NSValue : NSObject
+ at end
+
+ at interface NSNumber : NSValue
++ (NSNumber *)numberWithInt:(int)i;
+ at end
+
+ at interface NSString : NSObject
++ (NSString *)stringWithUTF8String:(const char *)str;
+ at end
+
+ at interface NSArray : NSObject
++ (NSArray *)arrayWithObjects:(const id [])objects count:(NSUInteger)count;
+ at end
+
+ at interface NSDictionary : NSObject
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id /* <NSCopying> */ [])keys count:(NSUInteger)count;
+ at end
+
+
+void testNumericLiteral() {
+ id result = @1; // expected-note{{NSNumber literal is an object with a +0 retain count}}
+ [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+void testBoxedInt(int x) {
+ id result = @(x); // expected-note{{NSNumber boxed expression produces an object with a +0 retain count}}
+ [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+void testBoxedString(const char *str) {
+ id result = @(str); // expected-note{{NSString boxed expression produces an object with a +0 retain count}}
+ [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+void testArray(id obj) {
+ id result = @[obj]; // expected-note{{NSArray literal is an object with a +0 retain count}}
+ [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+void testDictionary(id key, id value) {
+ id result = @{key: value}; // expected-note{{NSDictionary literal is an object with a +0 retain count}}
+ [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
Modified: cfe/trunk/test/Analysis/retain-release.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=156699&r1=156698&r2=156699&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/retain-release.m (original)
+++ cfe/trunk/test/Analysis/retain-release.m Sat May 12 00:10:43 2012
@@ -142,9 +142,13 @@
@end
@class NSString, NSDictionary;
@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
- at end @interface NSNumber : NSValue - (char)charValue;
+ at end
+ at interface NSNumber : NSValue
+- (char)charValue;
- (id)initWithInt:(int)value;
- at end @class NSString;
++ (NSNumber *)numberWithInt:(int)value;
+ at end
+ at class NSString;
@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>
- (NSUInteger)count;
- (id)initWithObjects:(const id [])objects count:(NSUInteger)cnt;
@@ -1812,6 +1816,19 @@
}
}
+void test_objc_integer_literals() {
+ id value = [@1 retain]; // expected-warning {{leak}}
+ [value description];
+}
+
+void test_objc_boxed_expressions(int x, const char *y) {
+ id value = [@(x) retain]; // expected-warning {{leak}}
+ [value description];
+
+ value = [@(y) retain]; // expected-warning {{leak}}
+ [value description];
+}
+
// Test NSLog doesn't escape tracked objects.
void rdar11400885(int y)
{
More information about the cfe-commits
mailing list