r342794 - Update smart pointer detection for thread safety analysis.
Richard Trieu via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 21 18:50:52 PDT 2018
Author: rtrieu
Date: Fri Sep 21 18:50:52 2018
New Revision: 342794
URL: http://llvm.org/viewvc/llvm-project?rev=342794&view=rev
Log:
Update smart pointer detection for thread safety analysis.
Objects are determined to be smart pointers if they have both a star and arrow
operator. Some implementations of smart pointers have these overloaded
operators in a base class, while the check only searched the derived class.
This fix will also look for the operators in the base class.
Modified:
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=342794&r1=342793&r2=342794&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Sep 21 18:50:52 2018
@@ -425,17 +425,36 @@ static bool isIntOrBool(Expr *Exp) {
// Check to see if the type is a smart pointer of some kind. We assume
// it's a smart pointer if it defines both operator-> and operator*.
static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) {
- DeclContextLookupResult Res1 = RT->getDecl()->lookup(
- S.Context.DeclarationNames.getCXXOperatorName(OO_Star));
- if (Res1.empty())
- return false;
+ auto IsOverloadedOperatorPresent = [&S](const RecordDecl *Record,
+ OverloadedOperatorKind Op) {
+ DeclContextLookupResult Result =
+ Record->lookup(S.Context.DeclarationNames.getCXXOperatorName(Op));
+ return !Result.empty();
+ };
+
+ const RecordDecl *Record = RT->getDecl();
+ bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star);
+ bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow);
+ if (foundStarOperator && foundArrowOperator)
+ return true;
- DeclContextLookupResult Res2 = RT->getDecl()->lookup(
- S.Context.DeclarationNames.getCXXOperatorName(OO_Arrow));
- if (Res2.empty())
+ const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record);
+ if (!CXXRecord)
return false;
- return true;
+ for (auto BaseSpecifier : CXXRecord->bases()) {
+ if (!foundStarOperator)
+ foundStarOperator = IsOverloadedOperatorPresent(
+ BaseSpecifier.getType()->getAsRecordDecl(), OO_Star);
+ if (!foundArrowOperator)
+ foundArrowOperator = IsOverloadedOperatorPresent(
+ BaseSpecifier.getType()->getAsRecordDecl(), OO_Arrow);
+ }
+
+ if (foundStarOperator && foundArrowOperator)
+ return true;
+
+ return false;
}
/// Check if passed in Decl is a pointer type.
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=342794&r1=342793&r2=342794&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp Fri Sep 21 18:50:52 2018
@@ -5481,3 +5481,98 @@ void f() {
int &i = i; // expected-warning {{reference 'i' is not yet bound to a value when used within its own initialization}}
}
}
+
+namespace Derived_Smart_Pointer {
+template <class T>
+class SmartPtr_Derived : public SmartPtr<T> {};
+
+class Foo {
+public:
+ SmartPtr_Derived<Mutex> mu_;
+ int a GUARDED_BY(mu_);
+ int b GUARDED_BY(mu_.get());
+ int c GUARDED_BY(*mu_);
+
+ void Lock() EXCLUSIVE_LOCK_FUNCTION(mu_);
+ void Unlock() UNLOCK_FUNCTION(mu_);
+
+ void test0() {
+ a = 1; // expected-warning {{writing variable 'a' requires holding mutex 'mu_' exclusively}}
+ b = 1; // expected-warning {{writing variable 'b' requires holding mutex 'mu_' exclusively}}
+ c = 1; // expected-warning {{writing variable 'c' requires holding mutex 'mu_' exclusively}}
+ }
+
+ void test1() {
+ Lock();
+ a = 1;
+ b = 1;
+ c = 1;
+ Unlock();
+ }
+};
+
+class Bar {
+ SmartPtr_Derived<Foo> foo;
+
+ void test0() {
+ foo->a = 1; // expected-warning {{writing variable 'a' requires holding mutex 'foo->mu_' exclusively}}
+ (*foo).b = 1; // expected-warning {{writing variable 'b' requires holding mutex 'foo->mu_' exclusively}}
+ foo.get()->c = 1; // expected-warning {{writing variable 'c' requires holding mutex 'foo->mu_' exclusively}}
+ }
+
+ void test1() {
+ foo->Lock();
+ foo->a = 1;
+ foo->Unlock();
+
+ foo->mu_->Lock();
+ foo->b = 1;
+ foo->mu_->Unlock();
+
+ MutexLock lock(foo->mu_.get());
+ foo->c = 1;
+ }
+};
+
+class PointerGuard {
+ Mutex mu1;
+ Mutex mu2;
+ SmartPtr_Derived<int> i GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+
+ void test0() {
+ i.get(); // expected-warning {{reading variable 'i' requires holding mutex 'mu1'}}
+ *i = 2; // expected-warning {{reading variable 'i' requires holding mutex 'mu1'}} \
+ // expected-warning {{reading the value pointed to by 'i' requires holding mutex 'mu2'}}
+
+ }
+
+ void test1() {
+ mu1.Lock();
+
+ i.get();
+ *i = 2; // expected-warning {{reading the value pointed to by 'i' requires holding mutex 'mu2'}}
+
+ mu1.Unlock();
+ }
+
+ void test2() {
+ mu2.Lock();
+
+ i.get(); // expected-warning {{reading variable 'i' requires holding mutex 'mu1'}}
+ *i = 2; // expected-warning {{reading variable 'i' requires holding mutex 'mu1'}}
+
+ mu2.Unlock();
+ }
+
+ void test3() {
+ mu1.Lock();
+ mu2.Lock();
+
+ i.get();
+ *i = 2;
+
+ mu2.Unlock();
+ mu1.Unlock();
+ }
+};
+}
More information about the cfe-commits
mailing list