[cfe-commits] r139801 - in /cfe/trunk: include/clang/Analysis/Analyses/ThreadSafety.h include/clang/Basic/DiagnosticSemaKinds.td lib/Analysis/ThreadSafety.cpp lib/Sema/AnalysisBasedWarnings.cpp test/SemaCXX/warn-thread-safety-analysis.cpp

Caitlin Sadowski supertri at google.com
Thu Sep 15 10:25:19 PDT 2011


Author: supertri
Date: Thu Sep 15 12:25:19 2011
New Revision: 139801

URL: http://llvm.org/viewvc/llvm-project?rev=139801&view=rev
Log:
Thread safety: refactoring various out of scope warnings to use the same inteface. This eliminates a lot of unnecessary duplicated code.

Modified:
    cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Analysis/ThreadSafety.cpp
    cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
    cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp

Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h?rev=139801&r1=139800&r2=139801&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafety.h Thu Sep 15 12:25:19 2011
@@ -49,6 +49,20 @@
   AK_Written /// Writing a variable
 };
 
+/// This enum distinguishes between different situations where we warn due to
+/// inconsistent locking.
+/// \enum SK_LockedSomeLoopIterations -- a mutex is locked for some but not all
+/// loop iterations.
+/// \enum SK_LockedSomePredecessors -- a mutex is locked in some but not all
+/// predecessors of a CFGBlock.
+/// \enum SK_LockedAtEndOfFunction -- a mutex is still locked at the end of a
+/// function.
+enum LockErrorKind {
+  LEK_LockedSomeLoopIterations,
+  LEK_LockedSomePredecessors,
+  LEK_LockedAtEndOfFunction
+};
+
 /// Handler class for thread safety warnings.
 class ThreadSafetyHandler {
 public:
@@ -73,27 +87,16 @@
   virtual void handleDoubleLock(Name LockName, SourceLocation Loc) {}
 
   /// Warn about situations where a mutex is sometimes held and sometimes not.
-  /// For example, a mutex is locked on an "if" branch but not the "else"
-  /// branch.
-  /// \param LockName -- A StringRef name for the lock expression, to be printed
-  /// in the error message.
-  /// \param Loc -- The location of the lock expression where the mutex is
-  /// locked
-  virtual void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc){}
-
-  /// Warn when a mutex is only held at the start of some loop iterations.
+  /// The three situations are:
+  /// 1. a mutex is locked on an "if" branch but not the "else" branch,
+  /// 2, or a mutex is only held at the start of some loop iterations,
+  /// 3. or when a mutex is locked but not unlocked inside a function.
   /// \param LockName -- A StringRef name for the lock expression, to be printed
   /// in the error message.
-  /// \param Loc -- The Loc of the lock expression.
-  virtual void handleNoLockLoopEntry(Name LockName, SourceLocation Loc) {}
-
-  /// Warn when a mutex is locked but not unlocked inside a function.
-  /// \param LockName -- A StringRef name for the lock expression, to be printed
-  /// in the error message.
-  /// \param FunName -- The name of the function
-  /// \param Loc -- The location of the lock expression
-  virtual void handleNoUnlock(Name LockName, Name FunName,
-                              SourceLocation Loc) {}
+  /// \param Loc -- The location of the lock expression where the mutex is locked
+  /// \param LEK -- which of the three above cases we should warn for
+  virtual void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc,
+                                         LockErrorKind LEK){}
 
   /// Warn when a mutex is held exclusively and shared at the same point. For
   /// example, if a mutex is locked exclusively during an if branch and shared

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=139801&r1=139800&r2=139801&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Sep 15 12:25:19 2011
@@ -1398,7 +1398,7 @@
   "locking '%0' that is already locked">,
   InGroup<ThreadSafety>, DefaultIgnore;
 def warn_no_unlock : Warning<
-  "mutex '%0' is still held at the end of function '%1'">,
+  "mutex '%0' is still held at the end of function">,
   InGroup<ThreadSafety>, DefaultIgnore;
 // FIXME: improve the error message about locks not in scope
 def warn_lock_at_end_of_scope : Warning<

Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=139801&r1=139800&r2=139801&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)
+++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Thu Sep 15 12:25:19 2011
@@ -598,13 +598,18 @@
 
 } // end anonymous namespace
 
-/// \brief Flags a warning for each lock that is in LSet2 but not LSet1, or
-/// else mutexes that are held shared in one lockset and exclusive in the other.
-static Lockset warnIfNotInFirstSetOrNotSameKind(ThreadSafetyHandler &Handler,
-                                                const Lockset LSet1,
-                                                const Lockset LSet2,
-                                                Lockset Intersection,
-                                                Lockset::Factory &Fact) {
+/// \brief Compute the intersection of two locksets and issue warnings for any
+/// locks in the symmetric difference.
+///
+/// This function is used at a merge point in the CFG when comparing the lockset
+/// of each branch being merged. For example, given the following sequence:
+/// A; if () then B; else C; D; we need to check that the lockset after B and C
+/// are the same. In the event of a difference, we use the intersection of these
+/// two locksets at the start of D.
+static Lockset intersectAndWarn(ThreadSafetyHandler &Handler,
+                                const Lockset LSet1, const Lockset LSet2,
+                                Lockset::Factory &Fact, LockErrorKind LEK) {
+  Lockset Intersection = LSet1;
   for (Lockset::iterator I = LSet2.begin(), E = LSet2.end(); I != E; ++I) {
     const MutexID &LSet2Mutex = I.getKey();
     const LockData &LSet2LockData = I.getData();
@@ -618,34 +623,16 @@
       }
     } else {
       Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(),
-                                        LSet2LockData.AcquireLoc);
+                                        LSet2LockData.AcquireLoc, LEK);
     }
   }
-  return Intersection;
-}
-
-
-/// \brief Compute the intersection of two locksets and issue warnings for any
-/// locks in the symmetric difference.
-///
-/// This function is used at a merge point in the CFG when comparing the lockset
-/// of each branch being merged. For example, given the following sequence:
-/// A; if () then B; else C; D; we need to check that the lockset after B and C
-/// are the same. In the event of a difference, we use the intersection of these
-/// two locksets at the start of D.
-static Lockset intersectAndWarn(ThreadSafetyHandler &Handler,
-                                const Lockset LSet1, const Lockset LSet2,
-                                Lockset::Factory &Fact) {
-  Lockset Intersection = LSet1;
-  Intersection = warnIfNotInFirstSetOrNotSameKind(Handler, LSet1, LSet2,
-                                                  Intersection, Fact);
 
   for (Lockset::iterator I = LSet1.begin(), E = LSet1.end(); I != E; ++I) {
     if (!LSet2.contains(I.getKey())) {
       const MutexID &Mutex = I.getKey();
       const LockData &MissingLock = I.getData();
       Handler.handleMutexHeldEndOfScope(Mutex.getName(),
-                                        MissingLock.AcquireLoc);
+                                        MissingLock.AcquireLoc, LEK);
       Intersection = Fact.remove(Intersection, Mutex);
     }
   }
@@ -669,34 +656,6 @@
   return Loc;
 }
 
-/// \brief Warn about different locksets along backedges of loops.
-/// This function is called when we encounter a back edge. At that point,
-/// we need to verify that the lockset before taking the backedge is the
-/// same as the lockset before entering the loop.
-///
-/// \param LoopEntrySet Locks before starting the loop
-/// \param LoopReentrySet Locks in the last CFG block of the loop
-static void warnBackEdgeUnequalLocksets(ThreadSafetyHandler &Handler,
-                                        const Lockset LoopReentrySet,
-                                        const Lockset LoopEntrySet,
-                                        SourceLocation FirstLocInLoop,
-                                        Lockset::Factory &Fact) {
-  assert(FirstLocInLoop.isValid());
-  // Warn for locks held at the start of the loop, but not the end.
-  for (Lockset::iterator I = LoopEntrySet.begin(), E = LoopEntrySet.end();
-       I != E; ++I) {
-    if (!LoopReentrySet.contains(I.getKey())) {
-      // We report this error at the location of the first statement in a loop
-      Handler.handleNoLockLoopEntry(I.getKey().getName(), FirstLocInLoop);
-    }
-  }
-
-  // Warn for locks held at the end of the loop, but not at the start.
-  warnIfNotInFirstSetOrNotSameKind(Handler, LoopEntrySet, LoopReentrySet,
-                                   LoopReentrySet, Fact);
-}
-
-
 namespace clang {
 namespace thread_safety {
 /// \brief Check a function's CFG for thread-safety violations.
@@ -763,7 +722,8 @@
         LocksetInitialized = true;
       } else {
         Entryset = intersectAndWarn(Handler, Entryset,
-                                    ExitLocksets[PrevBlockID], LocksetFactory);
+                                    ExitLocksets[PrevBlockID], LocksetFactory,
+                                    LEK_LockedSomePredecessors);
       }
     }
 
@@ -787,36 +747,17 @@
         continue;
 
       CFGBlock *FirstLoopBlock = *SI;
-      SourceLocation FirstLoopLocation = getFirstStmtLocation(FirstLoopBlock);
-
-      assert(FirstLoopLocation.isValid());
-
-      // Fail gracefully in release code.
-      if (!FirstLoopLocation.isValid())
-        continue;
-
       Lockset PreLoop = EntryLocksets[FirstLoopBlock->getBlockID()];
       Lockset LoopEnd = ExitLocksets[CurrBlockID];
-      warnBackEdgeUnequalLocksets(Handler, LoopEnd, PreLoop, FirstLoopLocation,
-                                  LocksetFactory);
+      intersectAndWarn(Handler, LoopEnd, PreLoop, LocksetFactory,
+                       LEK_LockedSomeLoopIterations);
     }
   }
 
+  Lockset InitialLockset = EntryLocksets[CFGraph->getEntry().getBlockID()];
   Lockset FinalLockset = ExitLocksets[CFGraph->getExit().getBlockID()];
-  if (!FinalLockset.isEmpty()) {
-    for (Lockset::iterator I=FinalLockset.begin(), E=FinalLockset.end();
-         I != E; ++I) {
-      const MutexID &Mutex = I.getKey();
-      const LockData &MissingLock = I.getData();
-
-      std::string FunName = "<unknown>";
-      if (const NamedDecl *ContextDecl = dyn_cast<NamedDecl>(AC.getDecl())) {
-        FunName = ContextDecl->getDeclName().getAsString();
-      }
-
-      Handler.handleNoUnlock(Mutex.getName(), FunName, MissingLock.AcquireLoc);
-    }
-  }
+  intersectAndWarn(Handler, InitialLockset, FinalLockset, LocksetFactory,
+                   LEK_LockedAtEndOfFunction);
 }
 
 /// \brief Helper function that returns a LockKind required for the given level

Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=139801&r1=139800&r2=139801&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Thu Sep 15 12:25:19 2011
@@ -633,20 +633,23 @@
     warnLockMismatch(diag::warn_double_lock, LockName, Loc);
   }
 
-  void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc){
-    warnLockMismatch(diag::warn_lock_at_end_of_scope, LockName, Loc);
-  }
-
-  void handleNoLockLoopEntry(Name LockName, SourceLocation Loc) {
-    warnLockMismatch(diag::warn_expecting_lock_held_on_loop, LockName, Loc);
+  void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc,
+                                 LockErrorKind LEK){
+    unsigned DiagID = 0;
+    switch (LEK) {
+      case LEK_LockedSomePredecessors:
+        DiagID = diag::warn_lock_at_end_of_scope;
+        break;
+      case LEK_LockedSomeLoopIterations:
+        DiagID = diag::warn_expecting_lock_held_on_loop;
+        break;
+      case LEK_LockedAtEndOfFunction:
+        DiagID = diag::warn_no_unlock;
+        break;
+    }
+    warnLockMismatch(DiagID, LockName, Loc);
   }
 
-  void handleNoUnlock(Name LockName, llvm::StringRef FunName,
-                      SourceLocation Loc) {
-    PartialDiagnostic Warning =
-      S.PDiag(diag::warn_no_unlock) << LockName << FunName;
-    Warnings.push_back(DelayedDiag(Loc, Warning));
-  }
 
   void handleExclusiveAndShared(Name LockName, SourceLocation Loc1,
                                 SourceLocation Loc2) {

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=139801&r1=139800&r2=139801&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp Thu Sep 15 12:25:19 2011
@@ -176,9 +176,9 @@
 }
 
 void sls_fun_bad_7() {
-  sls_mu.Lock();
-  while (getBool()) { // \
-      // expected-warning{{expecting lock on 'sls_mu' to be held at start of each loop}}
+  sls_mu.Lock(); // \
+    // expected-warning{{expecting lock on 'sls_mu' to be held at start of each loop}}
+  while (getBool()) {
     sls_mu.Unlock();
     if (getBool()) {
       if (getBool()) {
@@ -192,26 +192,26 @@
 }
 
 void sls_fun_bad_8() {
-  sls_mu.Lock();
+  sls_mu.Lock(); // \
+    // expected-warning{{expecting lock on 'sls_mu' to be held at start of each loop}}
   do {
-    sls_mu.Unlock();  // \
-      // expected-warning{{expecting lock on 'sls_mu' to be held at start of each loop}}
+    sls_mu.Unlock();
   } while (getBool());
 }
 
 void sls_fun_bad_9() {
   do {
     sls_mu.Lock(); // \
-      // expected-warning{{mutex 'sls_mu' is still held at the end of its scope}}
+      // expected-warning{{expecting lock on 'sls_mu' to be held at start of each loop}}
   } while (getBool());
   sls_mu.Unlock();
 }
 
 void sls_fun_bad_10() {
   sls_mu.Lock(); // \
-    // expected-warning{{mutex 'sls_mu' is still held at the end of function 'sls_fun_bad_10'}}
-  while(getBool()) { // \
-      // expected-warning{{expecting lock on 'sls_mu' to be held at start of each loop}}
+    // expected-warning{{mutex 'sls_mu' is still held at the end of function 'sls_fun_bad_10'}} \
+    // expected-warning{{expecting lock on 'sls_mu' to be held at start of each loop}}
+  while(getBool()) {
     sls_mu.Unlock();
   }
 }
@@ -219,7 +219,7 @@
 void sls_fun_bad_11() {
   while (getBool()) {
     sls_mu.Lock(); // \
-      // expected-warning{{mutex 'sls_mu' is still held at the end of its scope}}
+      // expected-warning{{expecting lock on 'sls_mu' to be held at start of each loop}}
   }
   sls_mu.Unlock(); // \
     // expected-warning{{unlocking 'sls_mu' that was not locked}}
@@ -519,11 +519,12 @@
 }
 
 void shared_fun_1() {
-  sls_mu.ReaderLock();
+  sls_mu.ReaderLock(); // \
+    // expected-warning {{lock 'sls_mu' is exclusive and shared in the same scope}}
   do {
     sls_mu.Unlock();
-    sls_mu.Lock(); // \
-      // expected-warning {{lock 'sls_mu' is exclusive and shared in the same scope}}
+    sls_mu.Lock();  // \
+      // expected-note {{the other lock of mutex 'sls_mu' is here}}
   } while (getBool());
   sls_mu.Unlock();
 }
@@ -557,11 +558,12 @@
 }
 
 void shared_bad_0() {
-  sls_mu.Lock();
+  sls_mu.Lock();  // \
+    // expected-warning {{lock 'sls_mu' is exclusive and shared in the same scope}}
   do {
     sls_mu.Unlock();
-    sls_mu.ReaderLock(); // \
-      // expected-warning {{lock 'sls_mu' is exclusive and shared in the same scope}}
+    sls_mu.ReaderLock();  // \
+      // expected-note {{the other lock of mutex 'sls_mu' is here}}
   } while (getBool());
   sls_mu.Unlock();
 }





More information about the cfe-commits mailing list