summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp14
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp14
-rw-r--r--clang/test/Analysis/malloc.c10
-rw-r--r--clang/test/Analysis/system-header-simulator.h4
4 files changed, 40 insertions, 2 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index d9ec668b418..4ae1dd81efa 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1033,9 +1033,19 @@ bool MallocChecker::hasUnknownBehavior(const FunctionDecl *FD,
return false;
}
- // If it's a system call, we know it does not free the memory.
+ // Most system calls, do not free the memory.
SourceManager &SM = ASTC.getSourceManager();
if (SM.isInSystemHeader(FD->getLocation())) {
+ const IdentifierInfo *II = FD->getIdentifier();
+
+ // White list the system functions whose arguments escape.
+ if (II) {
+ StringRef FName = II->getName();
+ if (FName.equals("pthread_setspecific"))
+ return true;
+ }
+
+ // Otherwise, assume that the function does not free memory.
return false;
}
@@ -1052,7 +1062,7 @@ MallocChecker::checkRegionChanges(ProgramStateRef State,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallOrObjCMessage *Call) const {
- if (!invalidated)
+ if (!invalidated || invalidated->empty())
return State;
llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 03db6270aaa..c53b7b1c0ac 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -187,6 +187,20 @@ static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
return;
if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) {
+ const IdentifierInfo *II = FDecl->getIdentifier();
+
+ // List the cases, where the region should be invalidated even if the
+ // 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
+ // 'void *ptheread_getspecific(pthread_key)'. So even thought the
+ // parameter is 'const void *', the region escapes through the call.
+ if (FName.equals("pthread_setspecific"))
+ return;
+ }
+
for (unsigned Idx = 0, E = Call.getNumArgs(); Idx != E; ++Idx) {
if (FDecl && Idx < FDecl->getNumParams()) {
if (isPointerToConst(FDecl->getParamDecl(Idx)))
diff --git a/clang/test/Analysis/malloc.c b/clang/test/Analysis/malloc.c
index 1923305fe20..4e42657c197 100644
--- a/clang/test/Analysis/malloc.c
+++ b/clang/test/Analysis/malloc.c
@@ -677,6 +677,16 @@ void testStrdupContentIsDefined(const char *s, unsigned validIndex) {
free(s2);
}
+// Test the system library functions to which the pointer can escape.
+
+// For now, we assume memory passed to pthread_specific escapes.
+// TODO: We could check that if a new pthread binding is set, the existing
+// binding must be freed; otherwise, a memory leak can occur.
+void testPthereadSpecificEscape(pthread_key_t key) {
+ void *buf = malloc(12);
+ pthread_setspecific(key, buf); // no warning
+}
+
// Below are the known false positives.
// TODO: There should be no warning here. This one might be difficult to get rid of.
diff --git a/clang/test/Analysis/system-header-simulator.h b/clang/test/Analysis/system-header-simulator.h
index 1dd9c5b6074..472cb5a6160 100644
--- a/clang/test/Analysis/system-header-simulator.h
+++ b/clang/test/Analysis/system-header-simulator.h
@@ -11,3 +11,7 @@ unsigned long strlen(const char *);
char *strcpy(char *restrict s1, const char *restrict s2);
+typedef unsigned long __darwin_pthread_key_t;
+typedef __darwin_pthread_key_t pthread_key_t;
+int pthread_setspecific(pthread_key_t ,
+ const void *);
OpenPOWER on IntegriCloud