Skip to content

Commit

Permalink
Thread Safety Analysis: Differentiate between lock sets at real join …
Browse files Browse the repository at this point in the history
…points and expected/actual sets at function end (llvm#105526)

This fixes false positives related to returning a scoped lockable
object. At the end of a function, we check managed locks instead of
scoped locks.

At real join points, we skip checking managed locks because we assume
that the scope keeps track of its underlying mutexes and will release
them at its destruction. So, checking for the scopes is sufficient.
However, at the end of a function, we aim at comparing the expected and
the actual lock sets. There, we skip checking scoped locks to prevent to
get duplicate warnings for the same lock.
  • Loading branch information
malek203 authored Sep 4, 2024
1 parent 30f1cfb commit e64ef63
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 14 deletions.
8 changes: 6 additions & 2 deletions clang/lib/Analysis/ThreadSafety.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,9 @@ class ScopedLockableFactEntry : public FactEntry {
handleRemovalFromIntersection(const FactSet &FSet, FactManager &FactMan,
SourceLocation JoinLoc, LockErrorKind LEK,
ThreadSafetyHandler &Handler) const override {
if (LEK == LEK_LockedAtEndOfFunction || LEK == LEK_NotLockedAtEndOfFunction)
return;

for (const auto &UnderlyingMutex : UnderlyingMutexes) {
const auto *Entry = FSet.findLock(FactMan, UnderlyingMutex.Cap);
if ((UnderlyingMutex.Kind == UCK_Acquired && Entry) ||
Expand Down Expand Up @@ -2224,7 +2227,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &EntrySet,
if (join(FactMan[*EntryIt], ExitFact,
EntryLEK != LEK_LockedSomeLoopIterations))
*EntryIt = Fact;
} else if (!ExitFact.managed()) {
} else if (!ExitFact.managed() || EntryLEK == LEK_LockedAtEndOfFunction) {
ExitFact.handleRemovalFromIntersection(ExitSet, FactMan, JoinLoc,
EntryLEK, Handler);
}
Expand All @@ -2236,7 +2239,8 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &EntrySet,
const FactEntry *ExitFact = ExitSet.findLock(FactMan, *EntryFact);

if (!ExitFact) {
if (!EntryFact->managed() || ExitLEK == LEK_LockedSomeLoopIterations)
if (!EntryFact->managed() || ExitLEK == LEK_LockedSomeLoopIterations ||
ExitLEK == LEK_NotLockedAtEndOfFunction)
EntryFact->handleRemovalFromIntersection(EntrySetOrig, FactMan, JoinLoc,
ExitLEK, Handler);
if (ExitLEK == LEK_LockedSomePredecessors)
Expand Down
20 changes: 8 additions & 12 deletions clang/test/SemaCXX/warn-thread-safety-analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6077,24 +6077,20 @@ namespace ReturnScopedLockable {
class Object {
public:
MutexLock lock() EXCLUSIVE_LOCK_FUNCTION(mutex) {
// TODO: False positive because scoped lock isn't destructed.
return MutexLock(&mutex); // expected-note {{mutex acquired here}}
} // expected-warning {{mutex 'mutex' is still held at the end of function}}
return MutexLock(&mutex);
}

ReaderMutexLock lockShared() SHARED_LOCK_FUNCTION(mutex) {
// TODO: False positive because scoped lock isn't destructed.
return ReaderMutexLock(&mutex); // expected-note {{mutex acquired here}}
} // expected-warning {{mutex 'mutex' is still held at the end of function}}
return ReaderMutexLock(&mutex);
}

MutexLock adopt() EXCLUSIVE_LOCKS_REQUIRED(mutex) {
// TODO: False positive because scoped lock isn't destructed.
return MutexLock(&mutex, true); // expected-note {{mutex acquired here}}
} // expected-warning {{mutex 'mutex' is still held at the end of function}}
return MutexLock(&mutex, true);
}

ReaderMutexLock adoptShared() SHARED_LOCKS_REQUIRED(mutex) {
// TODO: False positive because scoped lock isn't destructed.
return ReaderMutexLock(&mutex, true); // expected-note {{mutex acquired here}}
} // expected-warning {{mutex 'mutex' is still held at the end of function}}
return ReaderMutexLock(&mutex, true);
}

int x GUARDED_BY(mutex);
void needsLock() EXCLUSIVE_LOCKS_REQUIRED(mutex);
Expand Down

0 comments on commit e64ef63

Please sign in to comment.