]> granicus.if.org Git - clang/commitdiff
[analyzer] Invalidate the region passed to pthread_setspecific() call.
authorAnna Zaks <ganna@apple.com>
Thu, 23 Feb 2012 01:05:27 +0000 (01:05 +0000)
committerAnna Zaks <ganna@apple.com>
Thu, 23 Feb 2012 01:05:27 +0000 (01:05 +0000)
Make this call an exception in ExprEngine::invalidateArguments:
'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.

(Here we just blacklist the call in the ExprEngine's default
logic. Another option would be to add a checker which evaluates
the call and triggers the call to invalidate regions.)

Teach the Malloc Checker, which treats all system calls as safe about
the API.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151220 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/MallocChecker.cpp
lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
test/Analysis/malloc.c
test/Analysis/system-header-simulator.h

index d9ec668b4188f42eb28b17dea5f754aa4d630fb4..4ae1dd81efa0a515b8f3681f8158b051cd038efa 100644 (file)
@@ -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;
 
index 03db6270aaace551198776a0a42be875c8d035f0..c53b7b1c0acb748e5981b1c921c74b6927a60094 100644 (file)
@@ -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)))
index 1923305fe202df357a663c4446160c18784fff58..4e42657c197b974a05f761bf3fed160b958ba113 100644 (file)
@@ -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.
index 1dd9c5b60746e10988d94eae275222102b1760b1..472cb5a616001d6e18480cb45211982e1dd1cc06 100644 (file)
@@ -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 *);