[analyzer] Malloc: A pointer might escape through CFContainers APIs,
funopen, setvbuf.

Teach the checker and the engine about these APIs to resolve malloc
false positives. As I am adding more of these APIs, it is clear that all
this should be factored out into a separate callback (for example,
region escapes). Malloc, KeyChainAPI and RetainRelease checkers could
all use it.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151737 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 007eba1..ae81ad6 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -42,10 +42,8 @@
   RefState(Kind k, const Stmt *s) : K(k), S(s) {}
 
   bool isAllocated() const { return K == AllocateUnchecked; }
-  //bool isFailed() const { return K == AllocateFailed; }
   bool isReleased() const { return K == Released; }
-  //bool isEscaped() const { return K == Escaped; }
-  //bool isRelinquished() const { return K == Relinquished; }
+
   const Stmt *getStmt() const { return S; }
 
   bool operator==(const RefState &X) const {
@@ -1122,6 +1120,43 @@
       return false;
     }
 
+    // PR12101
+    // Many CoreFoundation and CoreGraphics might allow a tracked object 
+    // to escape.
+    if (Call->isCFCGAllowingEscape(FName))
+      return false;
+
+    // Associating streams with malloced buffers. The pointer can escape if
+    // 'closefn' is specified (and if that function does free memory).
+    // Currently, we do not inspect the 'closefn' function (PR12101).
+    if (FName == "funopen")
+      if (Call->getNumArgs() >= 4 && !Call->getArgSVal(4).isConstant(0))
+        return false;
+
+    // Do not warn on pointers passed to 'setbuf' when used with std streams,
+    // these leaks might be intentional when setting the buffer for stdio.
+    // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer
+    if (FName == "setbuf" || FName =="setbuffer" ||
+        FName == "setlinebuf" || FName == "setvbuf") {
+      if (Call->getNumArgs() >= 1)
+        if (const DeclRefExpr *Arg =
+              dyn_cast<DeclRefExpr>(Call->getArg(0)->IgnoreParenCasts()))
+          if (const VarDecl *D = dyn_cast<VarDecl>(Arg->getDecl()))
+              if (D->getCanonicalDecl()->getName().find("std")
+                                                   != StringRef::npos)
+                return false;
+    }
+
+    // A bunch of other functions, which take ownership of a pointer (See retain
+    // release checker). Not all the parameters here are invalidated, but the
+    // Malloc checker cannot differentiate between them. The right way of doing
+    // this would be to implement a pointer escapes callback.
+    if (FName == "CVPixelBufferCreateWithBytes" ||
+        FName == "CGBitmapContextCreateWithData" ||
+        FName == "CVPixelBufferCreateWithPlanarBytes") {
+      return false;
+    }
+
     // Otherwise, assume that the function does not free memory.
     // Most system calls, do not free the memory.
     return true;
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 7b6e0d7..5e23d44 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -197,10 +197,15 @@
       // value into thread local storage. The value can later be retrieved with
       // 'void *ptheread_getspecific(pthread_key)'. So even thought the
       // parameter is 'const void *', the region escapes through the call.
+      //  - funopen - sets a buffer for future IO calls.
       //  - ObjC functions that end with "NoCopy" can free memory, of the passed
       // in buffer.
+      // - Many CF containers allow objects to escape through custom
+      // allocators/deallocators upon container construction.
       if (FName == "pthread_setspecific" ||
-          FName.endswith("NoCopy"))
+          FName == "funopen" ||
+          FName.endswith("NoCopy") ||
+          Call.isCFCGAllowingEscape(FName))
         return;
     }