Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions clang/lib/Analysis/ThreadSafety.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TrailingObjects.h"
#include "llvm/Support/raw_ostream.h"
Expand Down Expand Up @@ -2820,6 +2821,12 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
case CFGElement::AutomaticObjectDtor: {
CFGAutomaticObjDtor AD = BI.castAs<CFGAutomaticObjDtor>();
const auto *DD = AD.getDestructorDecl(AC.getASTContext());
// Function parameters as they are constructed in caller's context and
// the CFG does not contain the ctors. Ignore them as their
// capabilities cannot be analysed because of this missing
// information.
if (isa_and_nonnull<ParmVarDecl>(AD.getVarDecl()))
break;
if (!DD || !DD->hasAttrs())
break;

Expand Down
37 changes: 37 additions & 0 deletions clang/test/SemaCXX/warn-thread-safety-analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1849,6 +1849,43 @@ struct TestScopedLockable {
}
};

namespace test_function_param_lock_unlock {
class A {
public:
A() EXCLUSIVE_LOCK_FUNCTION(mu_) { mu_.Lock(); }
~A() UNLOCK_FUNCTION(mu_) { mu_.Unlock(); }
private:
Mutex mu_;
};
int do_something(A a) { return 0; }

// Unlock in dtor without lock in ctor.
// FIXME: We cannot detect that we are releasing a lock that was never held!
class B {
public:
B() {}
B(int) {}
~B() UNLOCK_FUNCTION(mu_) { mu_.Unlock(); }
private:
Mutex mu_;
};
int do_something(B b) { return 0; }

class SCOPED_LOCKABLE MutexWrapper {
public:
MutexWrapper(Mutex *mu) : mu_(mu) {}
~MutexWrapper() UNLOCK_FUNCTION(mu_) { mu_->Unlock(); }
void Lock() EXCLUSIVE_LOCK_FUNCTION(mu_) { mu_->Lock(); }

Mutex *mu_;
};
// FIXME: This is a false-positive as the lock is released by the dtor.
void do_something(MutexWrapper mw) {
mw.Lock(); // expected-note {{mutex acquired here}}
} // expected-warning {{mutex 'mw.mu_' is still held at the end of function}}

} // namespace test_function_param_lock_unlock

} // end namespace test_scoped_lockable


Expand Down
Loading