From: Anna Zaks Date: Thu, 23 Feb 2012 01:05:27 +0000 (+0000) Subject: [analyzer] Invalidate the region passed to pthread_setspecific() call. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0d389b819c33bdf0375694a8f141c8f02e002b18;p=clang [analyzer] Invalidate the region passed to pthread_setspecific() call. 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 --- diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index d9ec668b41..4ae1dd81ef 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/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 ExplicitRegions, ArrayRef Regions, const CallOrObjCMessage *Call) const { - if (!invalidated) + if (!invalidated || invalidated->empty()) return State; llvm::SmallPtrSet WhitelistedSymbols; diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 03db6270aa..c53b7b1c0a 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -187,6 +187,20 @@ static void findPtrToConstParams(llvm::SmallSet &PreserveArgs, return; if (const FunctionDecl *FDecl = dyn_cast(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/test/Analysis/malloc.c b/test/Analysis/malloc.c index 1923305fe2..4e42657c19 100644 --- a/test/Analysis/malloc.c +++ b/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/test/Analysis/system-header-simulator.h b/test/Analysis/system-header-simulator.h index 1dd9c5b607..472cb5a616 100644 --- a/test/Analysis/system-header-simulator.h +++ b/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 *);