Skip to content

Commit ffa1d6a

Browse files
committed
Thread safety analysis: Improve diagnostics for double locking
Summary: We use the existing diag::note_locked_here to tell the user where we saw the first locking. Reviewers: aaron.ballman, delesley Reviewed By: aaron.ballman Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D56967 llvm-svn: 352549
1 parent d55102a commit ffa1d6a

File tree

4 files changed

+38
-33
lines changed

4 files changed

+38
-33
lines changed

clang/include/clang/Analysis/Analyses/ThreadSafety.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,10 @@ class ThreadSafetyHandler {
128128
/// \param Kind -- the capability's name parameter (role, mutex, etc).
129129
/// \param LockName -- A StringRef name for the lock expression, to be printed
130130
/// in the error message.
131+
/// \param LocLocked -- The location of the first lock expression.
131132
/// \param Loc -- The location of the second lock expression.
132133
virtual void handleDoubleLock(StringRef Kind, Name LockName,
133-
SourceLocation Loc) {}
134+
SourceLocation LocLocked, SourceLocation Loc) {}
134135

135136
/// Warn about situations where a mutex is sometimes held and sometimes not.
136137
/// The three situations are:

clang/lib/Analysis/ThreadSafety.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,7 @@ class LockableFactEntry : public FactEntry {
873873
void handleLock(FactSet &FSet, FactManager &FactMan, const FactEntry &entry,
874874
ThreadSafetyHandler &Handler,
875875
StringRef DiagKind) const override {
876-
Handler.handleDoubleLock(DiagKind, entry.toString(), entry.loc());
876+
Handler.handleDoubleLock(DiagKind, entry.toString(), loc(), entry.loc());
877877
}
878878

879879
void handleUnlock(FactSet &FSet, FactManager &FactMan,
@@ -981,12 +981,13 @@ class ScopedLockableFactEntry : public FactEntry {
981981
void lock(FactSet &FSet, FactManager &FactMan, const CapabilityExpr &Cp,
982982
LockKind kind, SourceLocation loc, ThreadSafetyHandler *Handler,
983983
StringRef DiagKind) const {
984-
if (!FSet.findLock(FactMan, Cp)) {
984+
if (const FactEntry *Fact = FSet.findLock(FactMan, Cp)) {
985+
if (Handler)
986+
Handler->handleDoubleLock(DiagKind, Cp.toString(), Fact->loc(), loc);
987+
} else {
985988
FSet.removeLock(FactMan, !Cp);
986989
FSet.addLock(FactMan,
987990
llvm::make_unique<LockableFactEntry>(Cp, kind, loc));
988-
} else if (Handler) {
989-
Handler->handleDoubleLock(DiagKind, Cp.toString(), loc);
990991
}
991992
}
992993

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,17 +1638,6 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
16381638
return ONS;
16391639
}
16401640

1641-
// Helper functions
1642-
void warnLockMismatch(unsigned DiagID, StringRef Kind, Name LockName,
1643-
SourceLocation Loc) {
1644-
// Gracefully handle rare cases when the analysis can't get a more
1645-
// precise source location.
1646-
if (!Loc.isValid())
1647-
Loc = FunLocation;
1648-
PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << LockName);
1649-
Warnings.emplace_back(std::move(Warning), getNotes());
1650-
}
1651-
16521641
public:
16531642
ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL)
16541643
: S(S), FunLocation(FL), FunEndLocation(FEL),
@@ -1677,7 +1666,11 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
16771666

16781667
void handleUnmatchedUnlock(StringRef Kind, Name LockName,
16791668
SourceLocation Loc) override {
1680-
warnLockMismatch(diag::warn_unlock_but_no_lock, Kind, LockName, Loc);
1669+
if (Loc.isInvalid())
1670+
Loc = FunLocation;
1671+
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_but_no_lock)
1672+
<< Kind << LockName);
1673+
Warnings.emplace_back(std::move(Warning), getNotes());
16811674
}
16821675

16831676
void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
@@ -1691,8 +1684,18 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
16911684
Warnings.emplace_back(std::move(Warning), getNotes());
16921685
}
16931686

1694-
void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc) override {
1695-
warnLockMismatch(diag::warn_double_lock, Kind, LockName, Loc);
1687+
void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked,
1688+
SourceLocation Loc) override {
1689+
if (Loc.isInvalid())
1690+
Loc = FunLocation;
1691+
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_double_lock)
1692+
<< Kind << LockName);
1693+
OptionalNotes Notes =
1694+
LocLocked.isValid()
1695+
? getNotes(PartialDiagnosticAt(
1696+
LocLocked, S.PDiag(diag::note_locked_here) << Kind))
1697+
: getNotes();
1698+
Warnings.emplace_back(std::move(Warning), std::move(Notes));
16961699
}
16971700

16981701
void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,

clang/test/SemaCXX/warn-thread-safety-analysis.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ void sls_fun_bad_1() {
239239
}
240240

241241
void sls_fun_bad_2() {
242-
sls_mu.Lock();
242+
sls_mu.Lock(); // expected-note{{mutex acquired here}}
243243
sls_mu.Lock(); // \
244244
// expected-warning{{acquiring mutex 'sls_mu' that is already held}}
245245
sls_mu.Unlock();
@@ -365,7 +365,7 @@ void aa_fun_bad_1() {
365365
}
366366

367367
void aa_fun_bad_2() {
368-
glock.globalLock();
368+
glock.globalLock(); // expected-note{{mutex acquired here}}
369369
glock.globalLock(); // \
370370
// expected-warning{{acquiring mutex 'aa_mu' that is already held}}
371371
glock.globalUnlock();
@@ -1691,7 +1691,7 @@ struct TestScopedLockable {
16911691
}
16921692

16931693
void foo3() {
1694-
MutexLock mulock_a(&mu1);
1694+
MutexLock mulock_a(&mu1); // expected-note{{mutex acquired here}}
16951695
MutexLock mulock_b(&mu1); // \
16961696
// expected-warning {{acquiring mutex 'mu1' that is already held}}
16971697
}
@@ -2710,14 +2710,14 @@ void doubleUnlock() {
27102710
}
27112711

27122712
void doubleLock1() {
2713-
RelockableExclusiveMutexLock scope(&mu);
2713+
RelockableExclusiveMutexLock scope(&mu); // expected-note{{mutex acquired here}}
27142714
scope.Lock(); // expected-warning {{acquiring mutex 'mu' that is already held}}
27152715
}
27162716

27172717
void doubleLock2() {
27182718
RelockableExclusiveMutexLock scope(&mu);
27192719
scope.Unlock();
2720-
scope.Lock();
2720+
scope.Lock(); // expected-note{{mutex acquired here}}
27212721
scope.Lock(); // expected-warning {{acquiring mutex 'mu' that is already held}}
27222722
}
27232723

@@ -2754,7 +2754,7 @@ class SCOPED_LOCKABLE MemberLock {
27542754
};
27552755

27562756
void relockShared2() {
2757-
MemberLock lock;
2757+
MemberLock lock; // expected-note{{mutex acquired here}}
27582758
lock.Lock(); // expected-warning {{acquiring mutex 'lock.mutex' that is already held}}
27592759
}
27602760

@@ -2861,7 +2861,7 @@ void join() EXCLUSIVE_LOCKS_REQUIRED(mu) {
28612861

28622862
void doubleLock() EXCLUSIVE_LOCKS_REQUIRED(mu) {
28632863
MutexUnlock scope(&mu);
2864-
scope.Lock();
2864+
scope.Lock(); // expected-note{{mutex acquired here}}
28652865
scope.Lock(); // expected-warning {{acquiring mutex 'mu' that is already held}}
28662866
}
28672867

@@ -3164,7 +3164,7 @@ void Foo::test7() {
31643164

31653165

31663166
void Foo::test8() {
3167-
mu_->Lock();
3167+
mu_->Lock(); // expected-note 2 {{mutex acquired here}}
31683168
mu_.get()->Lock(); // expected-warning {{acquiring mutex 'mu_' that is already held}}
31693169
(*mu_).Lock(); // expected-warning {{acquiring mutex 'mu_' that is already held}}
31703170
mu_.get()->Unlock();
@@ -3298,7 +3298,7 @@ void test0() {
32983298
foo.lock();
32993299
foo.unlock();
33003300

3301-
foo.lock();
3301+
foo.lock(); // expected-note{{mutex acquired here}}
33023302
foo.lock(); // expected-warning {{acquiring mutex 'foo' that is already held}}
33033303
foo.unlock();
33043304
foo.unlock(); // expected-warning {{releasing mutex 'foo' that was not held}}
@@ -3311,7 +3311,7 @@ void test1() {
33113311
foo.a = 0;
33123312
foo.unlock1();
33133313

3314-
foo.lock1();
3314+
foo.lock1(); // expected-note{{mutex acquired here}}
33153315
foo.lock1(); // expected-warning {{acquiring mutex 'foo.mu1_' that is already held}}
33163316
foo.a = 0;
33173317
foo.unlock1();
@@ -3325,7 +3325,7 @@ int test2() {
33253325
int d1 = foo.a;
33263326
foo.unlock1();
33273327

3328-
foo.slock1();
3328+
foo.slock1(); // expected-note{{mutex acquired here}}
33293329
foo.slock1(); // expected-warning {{acquiring mutex 'foo.mu1_' that is already held}}
33303330
int d2 = foo.a;
33313331
foo.unlock1();
@@ -3342,7 +3342,7 @@ void test3() {
33423342
foo.c = 0;
33433343
foo.unlock3();
33443344

3345-
foo.lock3();
3345+
foo.lock3(); // expected-note 3 {{mutex acquired here}}
33463346
foo.lock3(); // \
33473347
// expected-warning {{acquiring mutex 'foo.mu1_' that is already held}} \
33483348
// expected-warning {{acquiring mutex 'foo.mu2_' that is already held}} \
@@ -3366,7 +3366,7 @@ void testlots() {
33663366
foo.c = 0;
33673367
foo.unlocklots();
33683368

3369-
foo.locklots();
3369+
foo.locklots(); // expected-note 3 {{mutex acquired here}}
33703370
foo.locklots(); // \
33713371
// expected-warning {{acquiring mutex 'foo.mu1_' that is already held}} \
33723372
// expected-warning {{acquiring mutex 'foo.mu2_' that is already held}} \
@@ -3524,7 +3524,7 @@ void test() {
35243524
LockAllGraphs();
35253525
g2.mu_.Unlock();
35263526

3527-
LockAllGraphs();
3527+
LockAllGraphs(); // expected-note{{mutex acquired here}}
35283528
g1.mu_.Lock(); // expected-warning {{acquiring mutex 'g1.mu_' that is already held}}
35293529
g1.mu_.Unlock();
35303530
}

0 commit comments

Comments
 (0)