[analyzer] MallocChecker: implement pessimistic version of the checker,
which allows values to escape through unknown calls.

Assumes all calls but the malloc family are unknown.

Also, catch a use-after-free when a pointer is passed to a
function after a call to free (previously, you had to explicitly
dereference the pointer value).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150112 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index b14b400..c110e0f 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -131,6 +131,10 @@
   void ReallocMem(CheckerContext &C, const CallExpr *CE) const;
   static void CallocMem(CheckerContext &C, const CallExpr *CE);
   
+  bool checkEscape(SymbolRef Sym, const Stmt *S, CheckerContext &C) const;
+  bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
+                         const Stmt *S = 0) const;
+
   static bool SummarizeValue(raw_ostream &os, SVal V);
   static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
   void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const;
@@ -186,6 +190,7 @@
     return;
   }
 
+  if (Filter.CMallocOptimistic)
   // Check all the attributes, if there are any.
   // There can be multiple of these attributes.
   if (FD->hasAttrs()) {
@@ -206,6 +211,22 @@
       }
     }
   }
+
+  if (Filter.CMallocPessimistic) {
+    ProgramStateRef State = C.getState();
+    // The pointer might escape through a function call.
+    for (CallExpr::const_arg_iterator I = CE->arg_begin(),
+                                      E = CE->arg_end(); I != E; ++I) {
+      const Expr *A = *I;
+      if (A->getType().getTypePtr()->isAnyPointerType()) {
+        SymbolRef Sym = State->getSVal(A, C.getLocationContext()).getAsSymbol();
+        if (!Sym)
+          return;
+        checkEscape(Sym, A, C);
+        checkUseAfterFree(Sym, C, A);
+      }
+    }
+  }
 }
 
 void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
@@ -642,32 +663,36 @@
   }
 }
 
-void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
-  const Expr *retExpr = S->getRetValue();
-  if (!retExpr)
-    return;
-
+bool MallocChecker::checkEscape(SymbolRef Sym, const Stmt *S,
+                                CheckerContext &C) const {
   ProgramStateRef state = C.getState();
+  const RefState *RS = state->get<RegionState>(Sym);
+  if (!RS)
+    return false;
 
-  SymbolRef Sym = state->getSVal(retExpr, C.getLocationContext()).getAsSymbol();
+  if (RS->isAllocated()) {
+    state = state->set<RegionState>(Sym, RefState::getEscaped(S));
+    C.addTransition(state);
+    return true;
+  }
+  return false;
+}
+
+void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
+  const Expr *E = S->getRetValue();
+  if (!E)
+    return;
+  SymbolRef Sym = C.getState()->getSVal(E, C.getLocationContext()).getAsSymbol();
   if (!Sym)
     return;
 
-  const RefState *RS = state->get<RegionState>(Sym);
-  if (!RS)
-    return;
-
-  // FIXME: check other cases.
-  if (RS->isAllocated())
-    state = state->set<RegionState>(Sym, RefState::getEscaped(S));
-
-  C.addTransition(state);
+  checkEscape(Sym, S, C);
 }
 
 ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
                                               SVal Cond, 
                                               bool Assumption) const {
-  // If a symblic region is assumed to NULL, set its state to AllocateFailed.
+  // If a symbolic region is assumed to NULL, set its state to AllocateFailed.
   // FIXME: should also check symbols assumed to non-null.
 
   RegionStateTy RS = state->get<RegionState>();
@@ -681,24 +706,32 @@
   return state;
 }
 
+bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
+                                      const Stmt *S) const {
+  assert(Sym);
+  const RefState *RS = C.getState()->get<RegionState>(Sym);
+  if (RS && RS->isReleased()) {
+    if (ExplodedNode *N = C.addTransition()) {
+      if (!BT_UseFree)
+        BT_UseFree.reset(new BuiltinBug("Use dynamically allocated memory "
+            "after it is freed."));
+
+      BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(),N);
+      if (S)
+        R->addRange(S->getSourceRange());
+      C.EmitReport(R);
+      return true;
+    }
+  }
+  return false;
+}
+
 // Check if the location is a freed symbolic region.
 void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
                                   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.addTransition()) {
-        if (!BT_UseFree)
-          BT_UseFree.reset(new BuiltinBug("Use dynamically allocated memory "
-                                          "after it is freed."));
-
-        BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(),
-                                     N);
-        C.EmitReport(R);
-      }
-    }
-  }
+  if (Sym)
+    checkUseAfterFree(Sym, C);
 }
 
 void MallocChecker::checkBind(SVal location, SVal val,