[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