From 110eaaceddcec790f7e6a5e3bf1261c9aa1e73ab Mon Sep 17 00:00:00 2001
From: dim <dim@FreeBSD.org>
Date: Mon, 2 May 2011 19:39:53 +0000
Subject: Vendor import of clang trunk r130700:
 http://llvm.org/svn/llvm-project/cfe/trunk@130700

---
 lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 187 +++++++++++++-------------
 1 file changed, 97 insertions(+), 90 deletions(-)

(limited to 'lib/StaticAnalyzer/Checkers/MallocChecker.cpp')

diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 794740a..9100215 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -12,9 +12,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "ExperimentalChecks.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -62,55 +64,52 @@ public:
 
 class RegionState {};
 
-class MallocChecker : public CheckerVisitor<MallocChecker> {
-  BuiltinBug *BT_DoubleFree;
-  BuiltinBug *BT_Leak;
-  BuiltinBug *BT_UseFree;
-  BuiltinBug *BT_UseRelinquished;
-  BuiltinBug *BT_BadFree;
-  IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc;
+class MallocChecker : public Checker<eval::Call, check::DeadSymbols, check::EndPath, check::PreStmt<ReturnStmt>, check::Location,
+                               check::Bind, eval::Assume> {
+  mutable llvm::OwningPtr<BuiltinBug> BT_DoubleFree;
+  mutable llvm::OwningPtr<BuiltinBug> BT_Leak;
+  mutable llvm::OwningPtr<BuiltinBug> BT_UseFree;
+  mutable llvm::OwningPtr<BuiltinBug> BT_UseRelinquished;
+  mutable llvm::OwningPtr<BuiltinBug> BT_BadFree;
+  mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc;
 
 public:
-  MallocChecker() 
-    : BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0), BT_UseRelinquished(0),
-      BT_BadFree(0),
-      II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {}
-  static void *getTag();
-  bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
-  void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper);
-  void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExprEngine &Eng);
-  void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
-  const GRState *evalAssume(const GRState *state, SVal Cond, bool Assumption,
-                            bool *respondsToCallback);
-  void visitLocation(CheckerContext &C, const Stmt *S, SVal l, bool isLoad);
-  virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
-                            SVal location, SVal val);
+  MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {}
+
+  bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+  void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+  void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
+  const GRState *evalAssume(const GRState *state, SVal Cond,
+                            bool Assumption) const;
+  void checkLocation(SVal l, bool isLoad, CheckerContext &C) const;
+  void checkBind(SVal location, SVal val, CheckerContext &C) const;
 
 private:
-  void MallocMem(CheckerContext &C, const CallExpr *CE);
-  void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
-                            const OwnershipAttr* Att);
-  const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
-                              const Expr *SizeEx, SVal Init,
-                              const GRState *state) {
+  static void MallocMem(CheckerContext &C, const CallExpr *CE);
+  static void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
+                                   const OwnershipAttr* Att);
+  static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+                                     const Expr *SizeEx, SVal Init,
+                                     const GRState *state) {
     return MallocMemAux(C, CE, state->getSVal(SizeEx), Init, state);
   }
-  const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
-                              SVal SizeEx, SVal Init,
-                              const GRState *state);
+  static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+                                     SVal SizeEx, SVal Init,
+                                     const GRState *state);
 
-  void FreeMem(CheckerContext &C, const CallExpr *CE);
+  void FreeMem(CheckerContext &C, const CallExpr *CE) const;
   void FreeMemAttr(CheckerContext &C, const CallExpr *CE,
-                   const OwnershipAttr* Att);
+                   const OwnershipAttr* Att) const;
   const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
-                            const GRState *state, unsigned Num, bool Hold);
+                           const GRState *state, unsigned Num, bool Hold) const;
 
-  void ReallocMem(CheckerContext &C, const CallExpr *CE);
-  void CallocMem(CheckerContext &C, const CallExpr *CE);
+  void ReallocMem(CheckerContext &C, const CallExpr *CE) const;
+  static void CallocMem(CheckerContext &C, const CallExpr *CE);
   
-  bool SummarizeValue(llvm::raw_ostream& os, SVal V);
-  bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR);
-  void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range);
+  static bool SummarizeValue(llvm::raw_ostream& os, SVal V);
+  static bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR);
+  void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const;
 };
 } // end anonymous namespace
 
@@ -121,21 +120,12 @@ namespace ento {
   template <>
   struct GRStateTrait<RegionState> 
     : public GRStatePartialTrait<RegionStateTy> {
-    static void *GDMIndex() { return MallocChecker::getTag(); }
+    static void *GDMIndex() { static int x; return &x; }
   };
 }
 }
 
-void ento::RegisterMallocChecker(ExprEngine &Eng) {
-  Eng.registerCheck(new MallocChecker());
-}
-
-void *MallocChecker::getTag() {
-  static int x;
-  return &x;
-}
-
-bool MallocChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
   const GRState *state = C.getState();
   const Expr *Callee = CE->getCallee();
   SVal L = state->getSVal(Callee);
@@ -256,7 +246,7 @@ const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
   return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE));
 }
 
-void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
+void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) const {
   const GRState *state = FreeMemAux(C, CE, C.getState(), 0, false);
 
   if (state)
@@ -264,7 +254,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
 }
 
 void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE,
-                                const OwnershipAttr* Att) {
+                                const OwnershipAttr* Att) const {
   if (Att->getModule() != "malloc")
     return;
 
@@ -279,7 +269,7 @@ void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE,
 
 const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
                                          const GRState *state, unsigned Num,
-                                         bool Hold) {
+                                         bool Hold) const {
   const Expr *ArgExpr = CE->getArg(Num);
   SVal ArgVal = state->getSVal(ArgExpr);
 
@@ -357,9 +347,9 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
   if (RS->isReleased()) {
     if (ExplodedNode *N = C.generateSink()) {
       if (!BT_DoubleFree)
-        BT_DoubleFree
-          = new BuiltinBug("Double free",
-                         "Try to free a memory block that has been released");
+        BT_DoubleFree.reset(
+          new BuiltinBug("Double free",
+                         "Try to free a memory block that has been released"));
       // FIXME: should find where it's freed last time.
       BugReport *R = new BugReport(*BT_DoubleFree, 
                                    BT_DoubleFree->getDescription(), N);
@@ -463,10 +453,10 @@ bool MallocChecker::SummarizeRegion(llvm::raw_ostream& os,
 }
 
 void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
-                                  SourceRange range) {
+                                  SourceRange range) const {
   if (ExplodedNode *N = C.generateSink()) {
     if (!BT_BadFree)
-      BT_BadFree = new BuiltinBug("Bad free");
+      BT_BadFree.reset(new BuiltinBug("Bad free"));
     
     llvm::SmallString<100> buf;
     llvm::raw_svector_ostream os(buf);
@@ -500,7 +490,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
   }
 }
 
-void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
+void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const {
   const GRState *state = C.getState();
   const Expr *arg0Expr = CE->getArg(0);
   DefinedOrUnknownSVal arg0Val 
@@ -511,8 +501,24 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
   DefinedOrUnknownSVal PtrEQ =
     svalBuilder.evalEQ(state, arg0Val, svalBuilder.makeNull());
 
-  // If the ptr is NULL, the call is equivalent to malloc(size).
-  if (const GRState *stateEqual = state->assume(PtrEQ, true)) {
+  // Get the size argument. If there is no size arg then give up.
+  const Expr *Arg1 = CE->getArg(1);
+  if (!Arg1)
+    return;
+
+  // Get the value of the size argument.
+  DefinedOrUnknownSVal Arg1Val = 
+    cast<DefinedOrUnknownSVal>(state->getSVal(Arg1));
+
+  // Compare the size argument to 0.
+  DefinedOrUnknownSVal SizeZero =
+    svalBuilder.evalEQ(state, Arg1Val,
+                       svalBuilder.makeIntValWithPtrWidth(0, false));
+
+  // If the ptr is NULL and the size is not 0, the call is equivalent to 
+  // malloc(size).
+  const GRState *stateEqual = state->assume(PtrEQ, true);
+  if (stateEqual && state->assume(SizeZero, false)) {
     // Hack: set the NULL symbolic region to released to suppress false warning.
     // In the future we should add more states for allocated regions, e.g., 
     // CheckedNull, CheckedNonNull.
@@ -527,17 +533,17 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
   }
 
   if (const GRState *stateNotEqual = state->assume(PtrEQ, false)) {
-    const Expr *Arg1 = CE->getArg(1);
-    DefinedOrUnknownSVal Arg1Val = 
-      cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1));
-    DefinedOrUnknownSVal SizeZero =
-      svalBuilder.evalEQ(stateNotEqual, Arg1Val,
-                         svalBuilder.makeIntValWithPtrWidth(0, false));
-
+    // If the size is 0, free the memory.
     if (const GRState *stateSizeZero = stateNotEqual->assume(SizeZero, true))
-      if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero, 0, false))
-        C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
+      if (const GRState *stateFree = 
+          FreeMemAux(C, CE, stateSizeZero, 0, false)) {
+
+        // Add the state transition to set input pointer argument to be free.
+        C.addTransition(stateFree);
 
+        // Bind the return value to UndefinedVal because it is now free.
+        C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
+      }
     if (const GRState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false))
       if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero,
                                                 0, false)) {
@@ -562,7 +568,8 @@ void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) {
   C.addTransition(MallocMemAux(C, CE, TotalSize, zeroVal, state));
 }
 
-void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper)
+void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+                                     CheckerContext &C) const
 {
   if (!SymReaper.hasDeadSymbols())
     return;
@@ -576,8 +583,8 @@ void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper)
       if (I->second.isAllocated()) {
         if (ExplodedNode *N = C.generateNode()) {
           if (!BT_Leak)
-            BT_Leak = new BuiltinBug("Memory leak",
-                     "Allocated memory never released. Potential memory leak.");
+            BT_Leak.reset(new BuiltinBug("Memory leak",
+                    "Allocated memory never released. Potential memory leak."));
           // FIXME: where it is allocated.
           BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
           C.EmitReport(R);
@@ -591,8 +598,8 @@ void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper)
   C.generateNode(state->set<RegionState>(RS));
 }
 
-void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
-                                ExprEngine &Eng) {
+void MallocChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
+                                 ExprEngine &Eng) const {
   const GRState *state = B.getState();
   RegionStateTy M = state->get<RegionState>();
 
@@ -602,8 +609,8 @@ void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
       ExplodedNode *N = B.generateNode(state);
       if (N) {
         if (!BT_Leak)
-          BT_Leak = new BuiltinBug("Memory leak",
-                     "Allocated memory never released. Potential memory leak.");
+          BT_Leak.reset(new BuiltinBug("Memory leak",
+                    "Allocated memory never released. Potential memory leak."));
         BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
         Eng.getBugReporter().EmitReport(R);
       }
@@ -611,7 +618,7 @@ void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
   }
 }
 
-void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
+void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
   const Expr *retExpr = S->getRetValue();
   if (!retExpr)
     return;
@@ -634,14 +641,14 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
 }
 
 const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond, 
-                                         bool Assumption,
-                                         bool * /* respondsToCallback */) {
+                                         bool Assumption) const {
   // If a symblic region is assumed to NULL, set its state to AllocateFailed.
   // FIXME: should also check symbols assumed to non-null.
 
   RegionStateTy RS = state->get<RegionState>();
 
   for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
+    // If the symbol is assumed to NULL, this will return an APSInt*.
     if (state->getSymVal(I.getKey()))
       state = state->set<RegionState>(I.getKey(),RefState::getAllocateFailed());
   }
@@ -650,16 +657,15 @@ const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond,
 }
 
 // Check if the location is a freed symbolic region.
-void MallocChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
-                                  bool isLoad) {
+void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const {
   SymbolRef Sym = l.getLocSymbolInBase();
   if (Sym) {
     const RefState *RS = C.getState()->get<RegionState>(Sym);
     if (RS && RS->isReleased()) {
       if (ExplodedNode *N = C.generateNode()) {
         if (!BT_UseFree)
-          BT_UseFree = new BuiltinBug("Use dynamically allocated memory after"
-                                      " it is freed.");
+          BT_UseFree.reset(new BuiltinBug("Use dynamically allocated memory "
+                                          "after it is freed."));
 
         BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(),
                                      N);
@@ -669,10 +675,7 @@ void MallocChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
   }
 }
 
-void MallocChecker::PreVisitBind(CheckerContext &C,
-                                 const Stmt *StoreE,
-                                 SVal location,
-                                 SVal val) {
+void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const {
   // The PreVisitBind implements the same algorithm as already used by the 
   // Objective C ownership checker: if the pointer escaped from this scope by 
   // assignment, let it go.  However, assigning to fields of a stack-storage 
@@ -721,7 +724,7 @@ void MallocChecker::PreVisitBind(CheckerContext &C,
           // We no longer own this pointer.
           notNullState =
             notNullState->set<RegionState>(Sym,
-                                           RefState::getRelinquished(StoreE));
+                                        RefState::getRelinquished(C.getStmt()));
         }
         while (false);
       }
@@ -729,3 +732,7 @@ void MallocChecker::PreVisitBind(CheckerContext &C,
     }
   }
 }
+
+void ento::registerMallocChecker(CheckerManager &mgr) {
+  mgr.registerChecker<MallocChecker>();
+}
-- 
cgit v1.1