aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-02-28 01:54:22 +0000
committerAnna Zaks <ganna@apple.com>2012-02-28 01:54:22 +0000
commit07d39a479cf8f20294407e749f9933da34ebecb7 (patch)
tree91d72e60df6fbcddae32c9da36ab0d1ec1395a1e /lib/StaticAnalyzer
parentcae40c4d448529fe65de3d87bdbe97d3b54b4d98 (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.cpp28
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp9
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;
}