]> granicus.if.org Git - clang/commitdiff
Added path diagnostics for reference counts.
authorTed Kremenek <kremenek@apple.com>
Fri, 18 Apr 2008 04:55:01 +0000 (04:55 +0000)
committerTed Kremenek <kremenek@apple.com>
Fri, 18 Apr 2008 04:55:01 +0000 (04:55 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49892 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/CFRefCount.cpp

index 0c5860ecda95d78b4597b67f70bfdb2d19e6c05c..41754c95e75fdb59ebe78f4cddc02c21fd6356ef 100644 (file)
@@ -23,6 +23,7 @@
 #include "llvm/ADT/ImmutableMap.h"
 #include "llvm/Support/Compiler.h"
 #include <ostream>
+#include <sstream>
 
 using namespace clang;
 
@@ -1235,11 +1236,11 @@ namespace {
     UseAfterRelease(CFRefCount& tf) : CFRefBug(tf) {}
     
     virtual const char* getName() const {
-      return "(CoreFoundation) use-after-release";
+      return "Core Foundation: Use-After-Release";
     }
     virtual const char* getDescription() const {
-      return "(CoreFoundation) Reference-counted object is used"
-      " after it is released.";
+      return "Reference-counted object is used"
+             " after it is released.";
     }
     
     virtual void EmitWarnings(BugReporter& BR);
@@ -1251,11 +1252,11 @@ namespace {
     BadRelease(CFRefCount& tf) : CFRefBug(tf) {}
     
     virtual const char* getName() const {
-      return "(CoreFoundation) release of non-owned object";
+      return "Core Foundation: Release of non-owned object";
     }
     virtual const char* getDescription() const {
       return "Incorrect decrement of the reference count of a "
-      "CoreFoundation object:\n"
+      "CoreFoundation object: "
       "The object is not owned at this point by the caller.";
     }
     
@@ -1267,12 +1268,11 @@ namespace {
     Leak(CFRefCount& tf) : CFRefBug(tf) {}
     
     virtual const char* getName() const {
-      return "(CoreFoundation) Memory Leak";
+      return "Core Foundation: Memory Leak";
     }
     
     virtual const char* getDescription() const {
-      return "The CoreFoundation object has an excessive reference count and"
-      "\nis leaked after this statement.";
+      return "Object leaked.";
     }
     
     virtual void EmitWarnings(BugReporter& BR);
@@ -1320,10 +1320,102 @@ PathDiagnosticPiece* CFRefReport::VisitNode(ExplodedNode<ValueState>* N,
   CFRefCount::RefBindings PrevB = CFRefCount::GetRefBindings(*PrevSt);
   CFRefCount::RefBindings CurrB = CFRefCount::GetRefBindings(*CurrSt);
   
+  CFRefCount::RefBindings::TreeTy* PrevT = PrevB.SlimFind(Sym);
+  CFRefCount::RefBindings::TreeTy* CurrT = CurrB.SlimFind(Sym);
   
+  if (!CurrT)
+    return NULL;  
   
+  const char* Msg = NULL;  
+  RefVal CurrV = CurrB.SlimFind(Sym)->getValue().second;
   
-  return NULL;
+  if (!PrevT) {
+    
+    // Check for the point where we start tracking the value.
+    
+    if (CurrV.isOwned())
+      Msg = "Function call returns 'Owned' Core Foundation object.";
+    else {
+      assert (CurrV.isNotOwned());
+      Msg = "Function call returns 'Non-Owned' Core Foundation object.";
+    }
+
+    Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();    
+    FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager());
+    PathDiagnosticPiece* P = new PathDiagnosticPiece(Pos, Msg);
+    
+    if (Expr* Exp = dyn_cast<Expr>(S))
+      P->addRange(Exp->getSourceRange());
+    
+    return P;    
+  }
+  
+  // Determine if the typestate has changed.
+  
+  RefVal PrevV = PrevB.SlimFind(Sym)->getValue().second;
+  
+  if (PrevV == CurrV)
+    return NULL;
+  
+  // The typestate has changed.
+  
+  std::ostringstream os;
+  
+  switch (CurrV.getKind()) {
+    case RefVal::Owned:
+    case RefVal::NotOwned:
+      assert (PrevV.getKind() == CurrV.getKind());
+      
+      if (PrevV.getCount() > CurrV.getCount())
+        os << "Reference count decremented.";
+      else
+        os << "Reference count incremented.";
+      
+      if (CurrV.getCount())
+        os << " Object has +" << CurrV.getCount() << " reference counts.";
+      
+      Msg = os.str().c_str();
+      
+      break;
+      
+    case RefVal::Released:
+      Msg = "Object released.";
+      break;
+      
+    case RefVal::ReturnedOwned:
+      Msg = "Object returned to caller.  "
+            "Caller gets ownership of object.";
+      break;
+      
+    case RefVal::ReturnedNotOwned:
+      Msg = "Object returned to caller.  "
+            "Caller does not get ownership of object.";
+      break;
+
+    default:
+      return NULL;
+  }
+  
+  Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();    
+  FullSourceLoc Pos(S->getLocStart(), BR.getContext().getSourceManager());
+  PathDiagnosticPiece* P = new PathDiagnosticPiece(Pos, Msg);
+  
+  // Add the range by scanning the children of the statement for any bindings
+  // to Sym.
+  
+  ValueStateManager& VSM = BR.getEngine().getStateManager();
+  
+  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
+    if (Expr* Exp = dyn_cast_or_null<Expr>(*I)) {
+      RVal X = VSM.GetRVal(CurrSt, Exp);
+      
+      if (lval::SymbolVal* SV = dyn_cast<lval::SymbolVal>(&X))
+        if (SV->getSymbol() == Sym) {
+          P->addRange(Exp->getSourceRange()); break;
+        }
+    }
+  
+  return P;
 }
 
 void UseAfterRelease::EmitWarnings(BugReporter& BR) {