[cfe-commits] r159387 - in /cfe/trunk: lib/Analysis/ThreadSafety.cpp test/SemaCXX/warn-thread-safety-analysis.cpp

DeLesley Hutchins delesley at google.com
Thu Jun 28 15:42:48 PDT 2012


Author: delesley
Date: Thu Jun 28 17:42:48 2012
New Revision: 159387

URL: http://llvm.org/viewvc/llvm-project?rev=159387&view=rev
Log:
Thread safety analysis:  support release() function on scoped
lockable objects.

Modified:
    cfe/trunk/lib/Analysis/ThreadSafety.cpp
    cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp

Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=159387&r1=159386&r2=159387&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Thu Jun 28 17:42:48 2012
@@ -349,14 +349,18 @@
   ///
   /// FIXME: add support for re-entrant locking and lock up/downgrading
   LockKind LKind;
-  MutexID UnderlyingMutex;  // for ScopedLockable objects
+  bool     Managed;            // for ScopedLockable objects
+  MutexID  UnderlyingMutex;    // for ScopedLockable objects
 
-  LockData(SourceLocation AcquireLoc, LockKind LKind)
-    : AcquireLoc(AcquireLoc), LKind(LKind), UnderlyingMutex(Decl::EmptyShell())
+  LockData(SourceLocation AcquireLoc, LockKind LKind, bool M = false)
+    : AcquireLoc(AcquireLoc), LKind(LKind), Managed(M),
+      UnderlyingMutex(Decl::EmptyShell())
   {}
 
   LockData(SourceLocation AcquireLoc, LockKind LKind, const MutexID &Mu)
-    : AcquireLoc(AcquireLoc), LKind(LKind), UnderlyingMutex(Mu) {}
+    : AcquireLoc(AcquireLoc), LKind(LKind), Managed(false),
+      UnderlyingMutex(Mu)
+  {}
 
   bool operator==(const LockData &other) const {
     return AcquireLoc == other.AcquireLoc && LKind == other.LKind;
@@ -924,7 +928,8 @@
   Lockset addLock(const Lockset &LSet, Expr *MutexExp, const NamedDecl *D,
                   const LockData &LDat);
   Lockset removeLock(const Lockset &LSet, const MutexID &Mutex,
-                     SourceLocation UnlockLoc);
+                     SourceLocation UnlockLoc,
+                     bool Warn=true, bool FullyRemove=false);
 
   template <class AttrType>
   Lockset addLocksToSet(const Lockset &LSet, LockKind LK, AttrType *Attr,
@@ -986,21 +991,31 @@
 /// \param UnlockLoc The source location of the unlock (only used in error msg)
 Lockset ThreadSafetyAnalyzer::removeLock(const Lockset &LSet,
                                          const MutexID &Mutex,
-                                         SourceLocation UnlockLoc) {
+                                         SourceLocation UnlockLoc,
+                                         bool Warn, bool FullyRemove) {
   const LockData *LDat = LSet.lookup(Mutex);
   if (!LDat) {
-    Handler.handleUnmatchedUnlock(Mutex.getName(), UnlockLoc);
+    if (Warn)
+      Handler.handleUnmatchedUnlock(Mutex.getName(), UnlockLoc);
     return LSet;
   }
   else {
     Lockset Result = LSet;
-    // For scoped-lockable vars, remove the mutex associated with this var.
-    if (LDat->UnderlyingMutex.isValid())
-      Result = removeLock(Result, LDat->UnderlyingMutex, UnlockLoc);
+    if (LDat->UnderlyingMutex.isValid()) {
+      // For scoped-lockable vars, remove the mutex associated with this var.
+      Result = removeLock(Result, LDat->UnderlyingMutex, UnlockLoc,
+                          false, true);
+      // Fully remove the object only when the destructor is called
+      if (FullyRemove)
+        return LocksetFactory.remove(Result, Mutex);
+      else
+        return Result;
+    }
     return LocksetFactory.remove(Result, Mutex);
   }
 }
 
+
 /// \brief This function, parameterized by an attribute type, is used to add a
 /// set of locks specified as attribute arguments to the lockset.
 template <typename AttrType>
@@ -1040,14 +1055,18 @@
     if (!Mutex.isValid())
       MutexID::warnInvalidLock(Handler, *I, Exp, FunDecl);
     else {
-      Result = addLock(Result, Mutex, LockData(ExpLocation, LK));
       if (isScopedVar) {
+        // Mutex is managed by scoped var -- suppress certain warnings.
+        Result = addLock(Result, Mutex, LockData(ExpLocation, LK, true));
         // For scoped lockable vars, map this var to its underlying mutex.
         DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue, VD->getLocation());
         MutexID SMutex(&DRE, 0, 0);
         Result = addLock(Result, SMutex,
                          LockData(VD->getLocation(), LK, Mutex));
       }
+      else {
+        Result = addLock(Result, Mutex, LockData(ExpLocation, LK));
+      }
     }
   }
   return Result;
@@ -1057,9 +1076,11 @@
 /// arguments from the lockset.
 Lockset ThreadSafetyAnalyzer::removeLocksFromSet(const Lockset &LSet,
                                                  UnlockFunctionAttr *Attr,
-                                                 Expr *Exp, NamedDecl* FunDecl) {
+                                                 Expr *Exp,
+                                                 NamedDecl* FunDecl) {
   SourceLocation ExpLocation;
   if (Exp) ExpLocation = Exp->getExprLoc();
+  bool Dtor = isa<CXXDestructorDecl>(FunDecl);
 
   if (Attr->args_size() == 0) {
     // The mutex held is the "this" object.
@@ -1068,7 +1089,7 @@
       MutexID::warnInvalidLock(Handler, 0, Exp, FunDecl);
       return LSet;
     } else {
-      return removeLock(LSet, Mu, ExpLocation);
+      return removeLock(LSet, Mu, ExpLocation, true, Dtor);
     }
   }
 
@@ -1079,7 +1100,7 @@
     if (!Mutex.isValid())
       MutexID::warnInvalidLock(Handler, *I, Exp, FunDecl);
     else
-      Result = removeLock(Result, Mutex, ExpLocation);
+      Result = removeLock(Result, Mutex, ExpLocation, true, Dtor);
   }
   return Result;
 }
@@ -1537,9 +1558,10 @@
                                             LSet2LockData);
       }
     } else {
-      Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(),
-                                        LSet2LockData.AcquireLoc,
-                                        JoinLoc, LEK);
+      if (!LSet2LockData.Managed)
+        Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(),
+                                          LSet2LockData.AcquireLoc,
+                                          JoinLoc, LEK);
     }
   }
 
@@ -1547,9 +1569,11 @@
     if (!LSet2.contains(I.getKey())) {
       const MutexID &Mutex = I.getKey();
       const LockData &MissingLock = I.getData();
-      Handler.handleMutexHeldEndOfScope(Mutex.getName(),
-                                        MissingLock.AcquireLoc,
-                                        JoinLoc, LEK);
+
+      if (!MissingLock.Managed)
+        Handler.handleMutexHeldEndOfScope(Mutex.getName(),
+                                          MissingLock.AcquireLoc,
+                                          JoinLoc, LEK);
       Intersection = LocksetFactory.remove(Intersection, Mutex);
     }
   }

Modified: cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp?rev=159387&r1=159386&r2=159387&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp Thu Jun 28 17:42:48 2012
@@ -49,6 +49,13 @@
   ~ReaderMutexLock() __attribute__((unlock_function));
 };
 
+class SCOPED_LOCKABLE ReleasableMutexLock {
+ public:
+  ReleasableMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu);
+  ~ReleasableMutexLock() UNLOCK_FUNCTION();
+
+  void Release() UNLOCK_FUNCTION();
+};
 
 Mutex sls_mu;
 
@@ -1578,7 +1585,7 @@
     MutexLock mulock_a(&mu1);
     MutexLock mulock_b(&mu1); // \
       // expected-warning {{locking 'mu1' that is already locked}}
-  }   // expected-warning {{unlocking 'mu1' that was not locked}}
+  }
 
   void foo4() {
     MutexLock mulock1(&mu1), mulock2(&mu2);
@@ -2361,3 +2368,42 @@
 } // end namespace LockReturned
 
 
+namespace ReleasableScopedLock {
+
+class Foo {
+  Mutex mu_;
+  bool c;
+  int a GUARDED_BY(mu_);
+
+  void test1();
+  void test2();
+  void test3();
+};
+
+
+void Foo::test1() {
+  ReleasableMutexLock rlock(&mu_);
+  rlock.Release();
+}
+
+void Foo::test2() {
+  ReleasableMutexLock rlock(&mu_);
+  if (c) {            // test join point -- held/not held during release
+    rlock.Release();
+  }
+}
+
+void Foo::test3() {
+  ReleasableMutexLock rlock(&mu_);
+  a = 0;
+  rlock.Release();
+  a = 1;  // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
+}
+
+} // end namespace ReleasableScopedLock
+
+
+
+
+
+





More information about the cfe-commits mailing list