r228194 - Thread Safety Analysis: support adopting of locks, as implemented in

DeLesley Hutchins delesley at google.com
Wed Feb 4 13:16:17 PST 2015


Author: delesley
Date: Wed Feb  4 15:16:17 2015
New Revision: 228194

URL: http://llvm.org/viewvc/llvm-project?rev=228194&view=rev
Log:
Thread Safety Analysis: support adopting of locks, as implemented in
std::lock_guard.  If EXCLUSIVE_LOCKS_REQUIRED is placed on the constructor of
a SCOPED_LOCKABLE class, then that constructor is assumed to adopt the lock;
e.g. the lock must be held on construction, and will be released on destruction.

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=228194&r1=228193&r2=228194&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Wed Feb  4 15:16:17 2015
@@ -1690,8 +1690,19 @@ void BuildLockset::handleCall(Expr *Exp,
   SourceLocation Loc = Exp->getExprLoc();
   CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd;
   CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove;
+  CapExprSet ScopedExclusiveReqs, ScopedSharedReqs;
   StringRef CapDiagKind = "mutex";
 
+  // Figure out if we're calling the constructor of scoped lockable class
+  bool isScopedVar = false;
+  if (VD) {
+    if (const CXXConstructorDecl *CD = dyn_cast<const CXXConstructorDecl>(D)) {
+      const CXXRecordDecl* PD = CD->getParent();
+      if (PD && PD->hasAttr<ScopedLockableAttr>())
+        isScopedVar = true;
+    }
+  }
+
   for(Attr *Atconst : D->attrs()) {
     Attr* At = const_cast<Attr*>(Atconst);
     switch (At->getKind()) {
@@ -1751,10 +1762,17 @@ void BuildLockset::handleCall(Expr *Exp,
 
       case attr::RequiresCapability: {
         RequiresCapabilityAttr *A = cast<RequiresCapabilityAttr>(At);
-        for (auto *Arg : A->args())
+        for (auto *Arg : A->args()) {
           warnIfMutexNotHeld(D, Exp, A->isShared() ? AK_Read : AK_Written, Arg,
                              POK_FunctionCall, ClassifyDiagnostic(A),
                              Exp->getExprLoc());
+          // use for adopting a lock
+          if (isScopedVar) {
+            Analyzer->getMutexIDs(A->isShared() ? ScopedSharedReqs
+                                                : ScopedExclusiveReqs,
+                                  A, Exp, D, VD);
+          }
+        }
         break;
       }
 
@@ -1771,16 +1789,6 @@ void BuildLockset::handleCall(Expr *Exp,
     }
   }
 
-  // Figure out if we're calling the constructor of scoped lockable class
-  bool isScopedVar = false;
-  if (VD) {
-    if (const CXXConstructorDecl *CD = dyn_cast<const CXXConstructorDecl>(D)) {
-      const CXXRecordDecl* PD = CD->getParent();
-      if (PD && PD->hasAttr<ScopedLockableAttr>())
-        isScopedVar = true;
-    }
-  }
-
   // Add locks.
   for (const auto &M : ExclusiveLocksToAdd)
     Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
@@ -1797,6 +1805,11 @@ void BuildLockset::handleCall(Expr *Exp,
     DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue, VD->getLocation());
     // FIXME: does this store a pointer to DRE?
     CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE, nullptr);
+
+    std::copy(ScopedExclusiveReqs.begin(), ScopedExclusiveReqs.end(),
+              std::back_inserter(ExclusiveLocksToAdd));
+    std::copy(ScopedSharedReqs.begin(), ScopedSharedReqs.end(),
+              std::back_inserter(SharedLocksToAdd));
     Analyzer->addLock(FSet,
                       llvm::make_unique<ScopedLockableFactEntry>(
                           Scp, MLoc, ExclusiveLocksToAdd, SharedLocksToAdd),

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=228194&r1=228193&r2=228194&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp Wed Feb  4 15:16:17 2015
@@ -3,31 +3,31 @@
 // FIXME: should also run  %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 -Wc++98-compat %s
 // FIXME: should also run  %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
 
-#define LOCKABLE            __attribute__ ((lockable))
-#define SCOPED_LOCKABLE     __attribute__ ((scoped_lockable))
-#define GUARDED_BY(x)       __attribute__ ((guarded_by(x)))
-#define GUARDED_VAR         __attribute__ ((guarded_var))
-#define PT_GUARDED_BY(x)    __attribute__ ((pt_guarded_by(x)))
-#define PT_GUARDED_VAR      __attribute__ ((pt_guarded_var))
-#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
-#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))
-#define EXCLUSIVE_LOCK_FUNCTION(...)    __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
-#define SHARED_LOCK_FUNCTION(...)       __attribute__ ((shared_lock_function(__VA_ARGS__)))
-#define ASSERT_EXCLUSIVE_LOCK(...)      __attribute__ ((assert_exclusive_lock(__VA_ARGS__)))
-#define ASSERT_SHARED_LOCK(...)         __attribute__ ((assert_shared_lock(__VA_ARGS__)))
-#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__)))
-#define SHARED_TRYLOCK_FUNCTION(...)    __attribute__ ((shared_trylock_function(__VA_ARGS__)))
-#define UNLOCK_FUNCTION(...)            __attribute__ ((unlock_function(__VA_ARGS__)))
-#define LOCK_RETURNED(x)    __attribute__ ((lock_returned(x)))
-#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__)))
-#define EXCLUSIVE_LOCKS_REQUIRED(...) \
-  __attribute__ ((exclusive_locks_required(__VA_ARGS__)))
-#define SHARED_LOCKS_REQUIRED(...) \
-  __attribute__ ((shared_locks_required(__VA_ARGS__)))
-#define NO_THREAD_SAFETY_ANALYSIS  __attribute__ ((no_thread_safety_analysis))
+#define LOCKABLE             __attribute__((lockable))
+#define SCOPED_LOCKABLE      __attribute__((scoped_lockable))
+#define GUARDED_BY(x)        __attribute__((guarded_by(x)))
+#define GUARDED_VAR          __attribute__((guarded_var))
+#define PT_GUARDED_BY(x)     __attribute__((pt_guarded_by(x)))
+#define PT_GUARDED_VAR       __attribute__((pt_guarded_var))
+#define ACQUIRED_AFTER(...)  __attribute__((acquired_after(__VA_ARGS__)))
+#define ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
+#define EXCLUSIVE_LOCK_FUNCTION(...)    __attribute__((exclusive_lock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...)       __attribute__((shared_lock_function(__VA_ARGS__)))
+#define ASSERT_EXCLUSIVE_LOCK(...)      __attribute__((assert_exclusive_lock(__VA_ARGS__)))
+#define ASSERT_SHARED_LOCK(...)         __attribute__((assert_shared_lock(__VA_ARGS__)))
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__((exclusive_trylock_function(__VA_ARGS__)))
+#define SHARED_TRYLOCK_FUNCTION(...)    __attribute__((shared_trylock_function(__VA_ARGS__)))
+#define UNLOCK_FUNCTION(...)            __attribute__((unlock_function(__VA_ARGS__)))
+#define EXCLUSIVE_UNLOCK_FUNCTION(...)  __attribute__((release_capability(__VA_ARGS__)))
+#define SHARED_UNLOCK_FUNCTION(...)     __attribute__((release_shared_capability(__VA_ARGS__)))
+#define LOCK_RETURNED(x)                __attribute__((lock_returned(x)))
+#define LOCKS_EXCLUDED(...)             __attribute__((locks_excluded(__VA_ARGS__)))
+#define EXCLUSIVE_LOCKS_REQUIRED(...)   __attribute__((exclusive_locks_required(__VA_ARGS__)))
+#define SHARED_LOCKS_REQUIRED(...)      __attribute__((shared_locks_required(__VA_ARGS__)))
+#define NO_THREAD_SAFETY_ANALYSIS       __attribute__((no_thread_safety_analysis))
 
 
-class  __attribute__((lockable)) Mutex {
+class LOCKABLE Mutex {
  public:
   void Lock() __attribute__((exclusive_lock_function));
   void ReaderLock() __attribute__((shared_lock_function));
@@ -43,16 +43,18 @@ class  __attribute__((lockable)) Mutex {
   void AssertReaderHeld() ASSERT_SHARED_LOCK();
 };
 
-class __attribute__((scoped_lockable)) MutexLock {
+class SCOPED_LOCKABLE MutexLock {
  public:
-  MutexLock(Mutex *mu) __attribute__((exclusive_lock_function(mu)));
-  ~MutexLock() __attribute__((unlock_function));
+  MutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu);
+  MutexLock(Mutex *mu, bool adopt) EXCLUSIVE_LOCKS_REQUIRED(mu);
+  ~MutexLock() UNLOCK_FUNCTION();
 };
 
-class __attribute__((scoped_lockable)) ReaderMutexLock {
+class SCOPED_LOCKABLE ReaderMutexLock {
  public:
-  ReaderMutexLock(Mutex *mu) __attribute__((exclusive_lock_function(mu)));
-  ~ReaderMutexLock() __attribute__((unlock_function));
+  ReaderMutexLock(Mutex *mu) SHARED_LOCK_FUNCTION(mu);
+  ReaderMutexLock(Mutex *mu, bool adopt) SHARED_LOCKS_REQUIRED(mu);
+  ~ReaderMutexLock() UNLOCK_FUNCTION();
 };
 
 class SCOPED_LOCKABLE ReleasableMutexLock {
@@ -5055,6 +5057,37 @@ class Foo6 {
   }
 };
 
-
 }  // end namespace AcquiredBeforeAfterTest
 
+
+namespace ScopedAdoptTest {
+
+class Foo {
+  Mutex mu;
+  int a GUARDED_BY(mu);
+  int b;
+
+  void test1() EXCLUSIVE_UNLOCK_FUNCTION(mu) {
+    MutexLock slock(&mu, true);
+    a = 0;
+  }
+
+  void test2() SHARED_UNLOCK_FUNCTION(mu) {
+    ReaderMutexLock slock(&mu, true);
+    b = a;
+  }
+
+  void test3() EXCLUSIVE_LOCKS_REQUIRED(mu) {  // expected-note {{mutex acquired here}}
+    MutexLock slock(&mu, true);
+    a = 0;
+  }  // expected-warning {{expecting mutex 'mu' to be held at the end of function}}
+
+  void test4() SHARED_LOCKS_REQUIRED(mu) {     // expected-note {{mutex acquired here}}
+    ReaderMutexLock slock(&mu, true);
+    b = a;
+  }  // expected-warning {{expecting mutex 'mu' to be held at the end of function}}
+
+};
+
+}  // end namespace ScopedAdoptTest
+





More information about the cfe-commits mailing list