diff options
author | Anna Zaks <ganna@apple.com> | 2012-02-28 01:54:22 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2012-02-28 01:54:22 +0000 |
commit | 07d39a479cf8f20294407e749f9933da34ebecb7 (patch) | |
tree | 91d72e60df6fbcddae32c9da36ab0d1ec1395a1e /lib/StaticAnalyzer | |
parent | cae40c4d448529fe65de3d87bdbe97d3b54b4d98 (diff) |
[analyzer] Fix Malloc False Positive (PR 12100)
When allocated buffer is passed to CF/NS..NoCopy functions, the
ownership is transfered unless the deallocator argument is set to
'kCFAllocatorNull'.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151608 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 28 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 9 |
2 files changed, 29 insertions, 8 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index f7f199e26c..007eba19ab 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1094,14 +1094,32 @@ bool MallocChecker::doesNotFreeMemory(const CallOrObjCMessage *Call, if (!SM.isInSystemHeader(D->getLocation())) return false; - // Process C functions. + // Process C/ObjC functions. if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) { // White list the system functions whose arguments escape. const IdentifierInfo *II = FD->getIdentifier(); - if (II) { - StringRef FName = II->getName(); - if (FName.equals("pthread_setspecific")) - return false; + if (!II) + return true; + StringRef FName = II->getName(); + + // White list thread local storage. + if (FName.equals("pthread_setspecific")) + return false; + + // White list the 'XXXNoCopy' ObjC Methods. + if (FName.endswith("NoCopy")) { + // Look for the deallocator argument. We know that the memory ownership + // is not transfered only if the deallocator argument is + // 'kCFAllocatorNull'. + for (unsigned i = 1; i < Call->getNumArgs(); ++i) { + const Expr *ArgE = Call->getArg(i)->IgnoreParenCasts(); + if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) { + StringRef DeallocatorName = DE->getFoundDecl()->getName(); + if (DeallocatorName == "kCFAllocatorNull") + return true; + } + } + return false; } // Otherwise, assume that the function does not free memory. diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index a98d3b8c59..7b6e0d75d6 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -193,11 +193,14 @@ static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, // argument is const. if (II) { StringRef FName = II->getName(); - // 'int pthread_setspecific(ptheread_key k, const void *)' stores a value - // into thread local storage. The value can later be retrieved with + // - 'int pthread_setspecific(ptheread_key k, const void *)' stores a + // 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. - if (FName.equals("pthread_setspecific")) + // - ObjC functions that end with "NoCopy" can free memory, of the passed + // in buffer. + if (FName == "pthread_setspecific" || + FName.endswith("NoCopy")) return; } |