]> granicus.if.org Git - clang/commitdiff
[analyzer] Lock checker: Allow pthread_mutex_init to reinitialize a destroyed lock.
authorJordan Rose <jordan_rose@apple.com>
Tue, 1 Apr 2014 03:40:53 +0000 (03:40 +0000)
committerJordan Rose <jordan_rose@apple.com>
Tue, 1 Apr 2014 03:40:53 +0000 (03:40 +0000)
Patch by Daniel Fahlgren!

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

lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
test/Analysis/pthreadlock.c

index 76ae02731a3d3c6dbbf8fd10f5fe9f46120b96da..1ede3a2a512637c2052f364b35db797fd512cfa4 100644 (file)
@@ -53,6 +53,7 @@ class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
   mutable std::unique_ptr<BugType> BT_doublelock;
   mutable std::unique_ptr<BugType> BT_doubleunlock;
   mutable std::unique_ptr<BugType> BT_destroylock;
+  mutable std::unique_ptr<BugType> BT_initlock;
   mutable std::unique_ptr<BugType> BT_lor;
   enum LockingSemantics {
     NotApplicable = 0,
@@ -67,6 +68,7 @@ public:
     
   void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const;
   void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
+  void InitLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
   void reportUseDestroyedBug(CheckerContext &C, const CallExpr *CE) const;
 };
 } // end anonymous namespace
@@ -115,6 +117,8 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
   else 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));
 }
 
 void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
@@ -280,6 +284,41 @@ void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE,
   C.emitReport(Report);
 }
 
+void PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE,
+                                  SVal Lock) const {
+
+  const MemRegion *LockR = Lock.getAsRegion();
+  if (!LockR)
+    return;
+
+  ProgramStateRef State = C.getState();
+
+  const struct LockState *LState = State->get<LockMap>(LockR);
+  if (!LState || LState->isDestroyed()) {
+    State = State->set<LockMap>(LockR, LockState::getUnlocked());
+    C.addTransition(State);
+    return;
+  }
+
+  StringRef Message;
+
+  if (LState->isLocked()) {
+    Message = "This lock is still being held";
+  } else {
+    Message = "This lock has already been initialized";
+  }
+
+  if (!BT_initlock)
+    BT_initlock.reset(new BugType(this, "Init invalid lock",
+                                  "Lock checker"));
+  ExplodedNode *N = C.generateSink();
+  if (!N)
+    return;
+  BugReport *Report = new BugReport(*BT_initlock, Message, N);
+  Report->addRange(CE->getArg(0)->getSourceRange());
+  C.emitReport(Report);
+}
+
 void PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C,
                                                const CallExpr *CE) const {
   if (!BT_destroylock)
index 6a75a6e480e491dacffababfffa83fc732993aa1..2a59e0ffe98acd3d3d09da248b2dc9dff1ca5539 100644 (file)
@@ -6,6 +6,10 @@ typedef struct {
        void    *foo;
 } pthread_mutex_t;
 
+typedef struct {
+       void    *foo;
+} pthread_mutexattr_t;
+
 typedef struct {
        void    *foo;
 } lck_grp_t;
@@ -16,6 +20,7 @@ extern int pthread_mutex_lock(pthread_mutex_t *);
 extern int pthread_mutex_unlock(pthread_mutex_t *);
 extern int pthread_mutex_trylock(pthread_mutex_t *);
 extern int pthread_mutex_destroy(pthread_mutex_t *);
+extern int pthread_mutex_init(pthread_mutex_t  *mutex, const pthread_mutexattr_t *mutexattr);
 extern int lck_mtx_lock(lck_mtx_t *);
 extern int lck_mtx_unlock(lck_mtx_t *);
 extern int lck_mtx_try_lock(lck_mtx_t *);
@@ -25,6 +30,8 @@ pthread_mutex_t mtx1, mtx2;
 lck_mtx_t lck1, lck2;
 lck_grp_t grp1;
 
+#define NULL 0
+
 void
 ok1(void)
 {
@@ -137,6 +144,45 @@ ok15(void)
        pthread_mutex_destroy(&mtx1);   // no-warning
 }
 
+void
+ok16(void)
+{
+       pthread_mutex_init(&mtx1, NULL);        // no-warning
+}
+
+void
+ok17(void)
+{
+       pthread_mutex_init(&mtx1, NULL);        // no-warning
+       pthread_mutex_init(&mtx2, NULL);        // no-warning
+}
+
+void
+ok18(void)
+{
+       pthread_mutex_destroy(&mtx1);           // no-warning
+       pthread_mutex_init(&mtx1, NULL);        // no-warning
+}
+
+void
+ok19(void)
+{
+       pthread_mutex_destroy(&mtx1);           // no-warning
+       pthread_mutex_init(&mtx1, NULL);        // no-warning
+       pthread_mutex_destroy(&mtx2);           // no-warning
+       pthread_mutex_init(&mtx2, NULL);        // no-warning
+}
+
+void
+ok20(void)
+{
+       pthread_mutex_unlock(&mtx1);            // no-warning
+       pthread_mutex_destroy(&mtx1);           // no-warning
+       pthread_mutex_init(&mtx1, NULL);        // no-warning
+       pthread_mutex_destroy(&mtx1);           // no-warning
+       pthread_mutex_init(&mtx1, NULL);        // no-warning
+}
+
 void
 bad1(void)
 {
@@ -331,3 +377,24 @@ bad23(void)
        lck_mtx_lock(&mtx1);            // no-warning
        lck_mtx_destroy(&mtx1, &grp1);  // expected-warning{{This lock is still locked}}
 }
+
+void
+bad24(void)
+{
+       pthread_mutex_init(&mtx1, NULL);        // no-warning
+       pthread_mutex_init(&mtx1, NULL);        // expected-warning{{This lock has already been initialized}}
+}
+
+void
+bad25(void)
+{
+       pthread_mutex_lock(&mtx1);              // no-warning
+       pthread_mutex_init(&mtx1, NULL);        // expected-warning{{This lock is still being held}}
+}
+
+void
+bad26(void)
+{
+       pthread_mutex_unlock(&mtx1);            // no-warning
+       pthread_mutex_init(&mtx1, NULL);        // expected-warning{{This lock has already been initialized}}
+}