Thread safety analysis: fixed incorrect error message at the end of a locks_required function.

llvm-svn: 159607
This commit is contained in:
DeLesley Hutchins
2012-07-02 22:16:54 +00:00
parent 2a15baf968
commit 6e6dbb7618
5 changed files with 39 additions and 7 deletions

View File

@@ -60,7 +60,8 @@ enum AccessKind {
enum LockErrorKind { enum LockErrorKind {
LEK_LockedSomeLoopIterations, LEK_LockedSomeLoopIterations,
LEK_LockedSomePredecessors, LEK_LockedSomePredecessors,
LEK_LockedAtEndOfFunction LEK_LockedAtEndOfFunction,
LEK_NotLockedAtEndOfFunction
}; };
/// Handler class for thread safety warnings. /// Handler class for thread safety warnings.

View File

@@ -1775,6 +1775,9 @@ def warn_double_lock : Warning<
def warn_no_unlock : Warning< def warn_no_unlock : Warning<
"mutex '%0' is still locked at the end of function">, "mutex '%0' is still locked at the end of function">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore; InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
def warn_expecting_locked : Warning<
"expecting mutex '%0' to be locked at the end of function">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
// FIXME: improve the error message about locks not in scope // FIXME: improve the error message about locks not in scope
def warn_lock_some_predecessors : Warning< def warn_lock_some_predecessors : Warning<
"mutex '%0' is not locked on every path through here">, "mutex '%0' is not locked on every path through here">,

View File

@@ -951,7 +951,13 @@ public:
const CFGBlock *CurrBlock); const CFGBlock *CurrBlock);
Lockset intersectAndWarn(const Lockset &LSet1, const Lockset &LSet2, Lockset intersectAndWarn(const Lockset &LSet1, const Lockset &LSet2,
SourceLocation JoinLoc, LockErrorKind LEK); SourceLocation JoinLoc,
LockErrorKind LEK1, LockErrorKind LEK2);
Lockset intersectAndWarn(const Lockset &LSet1, const Lockset &LSet2,
SourceLocation JoinLoc, LockErrorKind LEK1) {
return intersectAndWarn(LSet1, LSet2, JoinLoc, LEK1, LEK1);
}
void runAnalysis(AnalysisDeclContext &AC); void runAnalysis(AnalysisDeclContext &AC);
}; };
@@ -1541,11 +1547,13 @@ void BuildLockset::VisitDeclStmt(DeclStmt *S) {
/// \param LSet1 The first lockset. /// \param LSet1 The first lockset.
/// \param LSet2 The second lockset. /// \param LSet2 The second lockset.
/// \param JoinLoc The location of the join point for error reporting /// \param JoinLoc The location of the join point for error reporting
/// \param LEK The error message to report. /// \param LEK1 The error message to report if a mutex is missing from LSet1
/// \param LEK2 The error message to report if a mutex is missing from Lset2
Lockset ThreadSafetyAnalyzer::intersectAndWarn(const Lockset &LSet1, Lockset ThreadSafetyAnalyzer::intersectAndWarn(const Lockset &LSet1,
const Lockset &LSet2, const Lockset &LSet2,
SourceLocation JoinLoc, SourceLocation JoinLoc,
LockErrorKind LEK) { LockErrorKind LEK1,
LockErrorKind LEK2) {
Lockset Intersection = LSet1; Lockset Intersection = LSet1;
for (Lockset::iterator I = LSet2.begin(), E = LSet2.end(); I != E; ++I) { for (Lockset::iterator I = LSet2.begin(), E = LSet2.end(); I != E; ++I) {
@@ -1564,7 +1572,7 @@ Lockset ThreadSafetyAnalyzer::intersectAndWarn(const Lockset &LSet1,
if (!LSet2LockData.Managed) if (!LSet2LockData.Managed)
Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(), Handler.handleMutexHeldEndOfScope(LSet2Mutex.getName(),
LSet2LockData.AcquireLoc, LSet2LockData.AcquireLoc,
JoinLoc, LEK); JoinLoc, LEK1);
} }
} }
@@ -1576,7 +1584,7 @@ Lockset ThreadSafetyAnalyzer::intersectAndWarn(const Lockset &LSet1,
if (!MissingLock.Managed) if (!MissingLock.Managed)
Handler.handleMutexHeldEndOfScope(Mutex.getName(), Handler.handleMutexHeldEndOfScope(Mutex.getName(),
MissingLock.AcquireLoc, MissingLock.AcquireLoc,
JoinLoc, LEK); JoinLoc, LEK2);
Intersection = LocksetFactory.remove(Intersection, Mutex); Intersection = LocksetFactory.remove(Intersection, Mutex);
} }
} }
@@ -1818,7 +1826,8 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// FIXME: Should we call this function for all blocks which exit the function? // FIXME: Should we call this function for all blocks which exit the function?
intersectAndWarn(Initial->EntrySet, Final->ExitSet, intersectAndWarn(Initial->EntrySet, Final->ExitSet,
Final->ExitLoc, Final->ExitLoc,
LEK_LockedAtEndOfFunction); LEK_LockedAtEndOfFunction,
LEK_NotLockedAtEndOfFunction);
} }
} // end anonymous namespace } // end anonymous namespace

View File

@@ -1061,6 +1061,9 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
case LEK_LockedAtEndOfFunction: case LEK_LockedAtEndOfFunction:
DiagID = diag::warn_no_unlock; DiagID = diag::warn_no_unlock;
break; break;
case LEK_NotLockedAtEndOfFunction:
DiagID = diag::warn_expecting_locked;
break;
} }
if (LocEndOfScope.isInvalid()) if (LocEndOfScope.isInvalid())
LocEndOfScope = FunEndLocation; LocEndOfScope = FunEndLocation;

View File

@@ -2451,6 +2451,22 @@ void Foo::foo() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
}; };
namespace UnlockBug {
class Foo {
public:
Mutex mutex_;
void foo1() EXCLUSIVE_LOCKS_REQUIRED(mutex_) { // expected-note {{mutex acquired here}}
mutex_.Unlock();
} // expected-warning {{expecting mutex 'mutex_' to be locked at the end of function}}
void foo2() SHARED_LOCKS_REQUIRED(mutex_) { // expected-note {{mutex acquired here}}
mutex_.Unlock();
} // expected-warning {{expecting mutex 'mutex_' to be locked at the end of function}}
};
} // end namespace UnlockBug