Hi jordan_rose, zaks.anna, krememek,

Regions passed to pthread* functions are invalidated because the call is 
evaluated conservatively. This leads to false positives (tests included). This 
patch replaces PostStmt<CallExpr> with evalCall for such functions.

http://reviews.llvm.org/D5247

Files:
  lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
  test/Analysis/pthreadlock.c
Index: lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -49,7 +49,8 @@
   }
 };
 
-class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
+class PthreadLockChecker : public Checker< eval::Call,
+                                           check::PostStmt<CallExpr> > {
   mutable std::unique_ptr<BugType> BT_doublelock;
   mutable std::unique_ptr<BugType> BT_doubleunlock;
   mutable std::unique_ptr<BugType> BT_destroylock;
@@ -62,7 +63,8 @@
   };
 public:
   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
-    
+  bool evalCall(const CallExpr *CE, CheckerContext &C) const;
+
   void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock,
                    bool isTryLock, enum LockingSemantics semantics) const;
     
@@ -78,44 +80,64 @@
 
 REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState)
 
-void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
-                                       CheckerContext &C) const {
+bool PthreadLockChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
   ProgramStateRef state = C.getState();
   const LocationContext *LCtx = C.getLocationContext();
   StringRef FName = C.getCalleeName(CE);
   if (FName.empty())
-    return;
+    return false;
 
   if (CE->getNumArgs() != 1 && CE->getNumArgs() != 2)
-    return;
+    return false;
 
   if (FName == "pthread_mutex_lock" ||
       FName == "pthread_rwlock_rdlock" ||
-      FName == "pthread_rwlock_wrlock")
+      FName == "pthread_rwlock_wrlock") {
     AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
                 false, PthreadSemantics);
-  else if (FName == "lck_mtx_lock" ||
+    return true;
+  } else if (FName == "lck_mtx_lock" ||
            FName == "lck_rw_lock_exclusive" ||
-           FName == "lck_rw_lock_shared") 
+           FName == "lck_rw_lock_shared") {
     AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
                 false, XNUSemantics);
-  else if (FName == "pthread_mutex_trylock" ||
+    return true;
+  } else if (FName == "pthread_mutex_trylock" ||
            FName == "pthread_rwlock_tryrdlock" ||
-           FName == "pthread_rwlock_trywrlock")
+           FName == "pthread_rwlock_trywrlock") {
     AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
                 true, PthreadSemantics);
-  else if (FName == "lck_mtx_try_lock" ||
+    return true;
+  } else if (FName == "lck_mtx_try_lock" ||
            FName == "lck_rw_try_lock_exclusive" ||
-           FName == "lck_rw_try_lock_shared")
+           FName == "lck_rw_try_lock_shared") {
     AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
                 true, XNUSemantics);
-  else if (FName == "pthread_mutex_unlock" ||
+    return true;
+  } else if (FName == "pthread_mutex_unlock" ||
            FName == "pthread_rwlock_unlock" ||
            FName == "lck_mtx_unlock" ||
-           FName == "lck_rw_done")
+           FName == "lck_rw_done") {
     ReleaseLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
-  else if (FName == "pthread_mutex_destroy" ||
-           FName == "lck_mtx_destroy")
+    return true;
+  }
+  return false;
+}
+
+
+void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
+                                       CheckerContext &C) const {
+  ProgramStateRef state = C.getState();
+  const LocationContext *LCtx = C.getLocationContext();
+  StringRef FName = C.getCalleeName(CE);
+  if (FName.empty())
+    return;
+
+  if (CE->getNumArgs() != 1 && CE->getNumArgs() != 2)
+    return;
+
+  if (FName == "pthread_mutex_destroy" ||
+      FName == "lck_mtx_destroy")
     DestroyLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
   else if (FName == "pthread_mutex_init")
     InitLock(C, CE, state->getSVal(CE->getArg(0), LCtx));
@@ -130,12 +152,11 @@
     return;
   
   ProgramStateRef state = C.getState();
-  
-  SVal X = state->getSVal(CE, C.getLocationContext());
-  if (X.isUnknownOrUndef())
-    return;
-  
-  DefinedSVal retVal = X.castAs<DefinedSVal>();
+  const LocationContext *LCtx = C.getLocationContext();
+  DefinedSVal retVal = C.getSValBuilder() .conjureSymbolVal(nullptr, CE, LCtx,
+                                                            C.blockCount())
+      .castAs<DefinedSVal>();
+  state = state->BindExpr(CE, LCtx, retVal);
 
   if (const LockState *LState = state->get<LockMap>(lockR)) {
     if (LState->isLocked()) {
@@ -246,6 +267,11 @@
   }
 
   state = state->set<LockMap>(lockR, LockState::getUnlocked());
+  const LocationContext *LCtx = C.getLocationContext();
+  DefinedSVal retVal = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
+                                                           C.blockCount())
+      .castAs<DefinedSVal>();
+  state = state->BindExpr(CE, LCtx, retVal);
   C.addTransition(state);
 }
 
Index: test/Analysis/pthreadlock.c
===================================================================
--- test/Analysis/pthreadlock.c
+++ test/Analysis/pthreadlock.c
@@ -30,6 +30,8 @@
 lck_mtx_t lck1, lck2;
 lck_grp_t grp1;
 
+pthread_mutex_t *pmtx;
+
 #define NULL 0
 
 void
@@ -184,6 +186,21 @@
 }
 
 void
+ok21(void) {
+	pthread_mutex_lock(pmtx);	// no-warning
+	pthread_mutex_unlock(pmtx);	// no-warning
+}
+
+void
+ok22(void) {
+	pthread_mutex_lock(pmtx);	// no-warning
+	pthread_mutex_unlock(pmtx);	// no-warning
+	pthread_mutex_lock(pmtx);	// no-warning
+	pthread_mutex_unlock(pmtx);	// no-warning
+}
+
+
+void
 bad1(void)
 {
 	pthread_mutex_lock(&mtx1);	// no-warning
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to