[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