diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 41 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 7 |
2 files changed, 44 insertions, 4 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 007eba19ab..ae81ad6eda 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -42,10 +42,8 @@ public: 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 @@ bool MallocChecker::doesNotFreeMemory(const CallOrObjCMessage *Call, 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 7b6e0d75d6..5e23d44bdc 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -197,10 +197,15 @@ static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, // 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; } |