[cfe-commits] r49509 - in /cfe/trunk: lib/Analysis/CFRefCount.cpp lib/Analysis/GRExprEngine.cpp test/Analysis-Apple/CFDate.c

Ted Kremenek kremenek at apple.com
Thu Apr 10 16:44:06 PDT 2008


Author: kremenek
Date: Thu Apr 10 18:44:06 2008
New Revision: 49509

URL: http://llvm.org/viewvc/llvm-project?rev=49509&view=rev
Log:
Fixed some logic errors in the CF ref count checker; we now can detect simple
use-after-release errors.  Added test case.

Added:
    cfe/trunk/test/Analysis-Apple/CFDate.c
Modified:
    cfe/trunk/lib/Analysis/CFRefCount.cpp
    cfe/trunk/lib/Analysis/GRExprEngine.cpp

Modified: cfe/trunk/lib/Analysis/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFRefCount.cpp?rev=49509&r1=49508&r2=49509&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Thu Apr 10 18:44:06 2008
@@ -48,7 +48,8 @@
   
 class RetEffect {
 public:
-  enum Kind { Alias = 0x0, OwnedSymbol = 0x1, NotOwnedSymbol = 0x2 };
+  enum Kind { NoRet = 0x0, Alias = 0x1, OwnedSymbol = 0x2,
+              NotOwnedSymbol = 0x3 };
 
 private:
   unsigned Data;
@@ -69,6 +70,8 @@
   
   static RetEffect MakeNotOwned() { return RetEffect(NotOwnedSymbol, 0); }
   
+  static RetEffect MakeNoRet() { return RetEffect(NoRet, 0); }
+  
   operator Kind() const { return getKind(); }
   
   void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger(Data); }
@@ -133,6 +136,10 @@
   
   CFRefSummary* getPersistentSummary(ArgEffects* AE, RetEffect RE);
   
+  CFRefSummary* getDoNothingSummary(unsigned Args);
+  void FillDoNothing(unsigned Args);
+
+  
 public:
   CFRefSummaryManager(ASTContext& ctx) : Ctx(ctx) {}
   ~CFRefSummaryManager();
@@ -158,8 +165,6 @@
 
 ArgEffects* CFRefSummaryManager::getArgEffects() {
 
-  assert (!ScratchArgs.empty());
-  
   llvm::FoldingSetNodeID profile;
   profile.Add(ScratchArgs);
   void* InsertPos;
@@ -314,20 +319,22 @@
     // CFRetain: the return type should also be "CFTypeRef".
     if (RetTy.getTypePtr() != ArgT)
       return NULL;
+    
+    // The function's interface checks out.  Generate a canned summary.    
+    assert (ScratchArgs.empty());
+    ScratchArgs.push_back(IncRef);
+    return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
   }
   else {
     // CFRelease: the return type should be void.
     
     if (RetTy != Ctx.VoidTy)
       return NULL;
-  }
     
-  // The function's interface checks out.  Generate a canned summary.
-  
-  assert (ScratchArgs.empty());
-  ScratchArgs.push_back(isRetain ? IncRef : DecRef);
-  
-  return getPersistentSummary(getArgEffects(), RetEffect::MakeAlias(0));
+    assert (ScratchArgs.empty());
+    ScratchArgs.push_back(DecRef);
+    return getPersistentSummary(getArgEffects(), RetEffect::MakeNoRet());
+  }
 }
 
 static bool isCFRefType(QualType T) {
@@ -354,21 +361,28 @@
   return true;
 }
   
+void CFRefSummaryManager::FillDoNothing(unsigned Args) {
+  for (unsigned i = 0; i != Args; ++i)
+    ScratchArgs.push_back(DoNothing);
+}
+
+CFRefSummary* CFRefSummaryManager::getDoNothingSummary(unsigned Args) {
+  FillDoNothing(Args);
+  return getPersistentSummary(getArgEffects(), RetEffect::MakeNoRet());  
+}
 
 CFRefSummary*
 CFRefSummaryManager::getCFSummaryCreateRule(FunctionTypeProto* FT) {
  
   if (!isCFRefType(FT->getResultType()))
-    return NULL;
+    return getDoNothingSummary(FT->getNumArgs());
 
   assert (ScratchArgs.empty());
   
   // FIXME: Add special-cases for functions that retain/release.  For now
   //  just handle the default case.
   
-  for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
-    ScratchArgs.push_back(DoNothing);
-  
+  FillDoNothing(FT->getNumArgs());  
   return getPersistentSummary(getArgEffects(), RetEffect::MakeOwned());
 }
 
@@ -376,16 +390,14 @@
 CFRefSummaryManager::getCFSummaryGetRule(FunctionTypeProto* FT) {
   
   if (!isCFRefType(FT->getResultType()))
-    return NULL;
+    return getDoNothingSummary(FT->getNumArgs());
   
   assert (ScratchArgs.empty());
   
   // FIXME: Add special-cases for functions that retain/release.  For now
   //  just handle the default case.
   
-  for (unsigned i = 0, n = FT->getNumArgs(); i != n; ++i)
-    ScratchArgs.push_back(DoNothing);
-  
+  FillDoNothing(FT->getNumArgs());  
   return getPersistentSummary(getArgEffects(), RetEffect::MakeNotOwned());
 }
 
@@ -711,11 +723,11 @@
     
   if (hasError) {
     St = StateMgr.getPersistentState(StVals);
-    GRExprEngine::NodeTy* N = Builder.generateNode(CE, St, Pred);
+    
+    Builder.BuildSinks = true;
+    GRExprEngine::NodeTy* N  = Builder.MakeNode(Dst, CE, Pred, St);
 
     if (N) {
-      N->markAsSink();
-      
       switch (hasError) {
         default: assert(false);
         case RefVal::ErrorUseAfterRelease:
@@ -741,6 +753,9 @@
     default:
       assert (false && "Unhandled RetEffect."); break;
     
+    case RetEffect::NoRet:
+      break;
+      
     case RetEffect::Alias: {
       unsigned idx = RE.getValue();
       assert (idx < CE->getNumArgs());
@@ -810,7 +825,8 @@
           assert(false);
 
         case RefVal::Owned:
-          V = RefVal::makeOwned(V.getCount()+1); break;
+          V = RefVal::makeOwned(V.getCount()+1);
+          break;
                     
         case RefVal::NotOwned:
           V = RefVal::makeNotOwned(V.getCount()+1);
@@ -822,6 +838,8 @@
           break;
       }
       
+      break;
+      
     case DecRef:
       switch (V.getKind()) {
         default:
@@ -851,6 +869,8 @@
           hasError = V.getKind();
           break;          
       }
+      
+      break;
   }
 
   return RefBFactory.Add(B, sym, V);

Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=49509&r1=49508&r2=49509&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Thu Apr 10 18:44:06 2008
@@ -678,6 +678,8 @@
       
       unsigned size = Dst.size();
       
+      SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+      
       EvalCall(Dst, CE, cast<LVal>(L), *DI);
       
       if (!Builder->BuildSinks && Dst.size() == size)

Added: cfe/trunk/test/Analysis-Apple/CFDate.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis-Apple/CFDate.c?rev=49509&view=auto

==============================================================================
--- cfe/trunk/test/Analysis-Apple/CFDate.c (added)
+++ cfe/trunk/test/Analysis-Apple/CFDate.c Thu Apr 10 18:44:06 2008
@@ -0,0 +1,15 @@
+// RUN: clang -checker-cfref -verify %s
+
+#include <CoreFoundation/CFDate.h>
+
+CFAbsoluteTime f1() {
+  CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
+  CFDateRef date = CFDateCreate(NULL, t);
+  CFRetain(date);
+  CFRelease(date);
+  t = CFDateGetAbsoluteTime(date);
+  CFRelease(date);
+  t = CFDateGetAbsoluteTime(date);   // expected-warning{{Reference-counted object is used after it is released.}}
+  return t;
+}
+





More information about the cfe-commits mailing list