diff options
-rw-r--r-- | lib/Analysis/ThreadSafety.cpp | 56 | ||||
-rw-r--r-- | test/SemaCXX/warn-thread-safety-analysis.cpp | 115 |
2 files changed, 144 insertions, 27 deletions
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index 40ad79b25c..b2f89cce6b 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -126,12 +126,56 @@ class MutexID { DeclSeq.push_back(0); // Use 0 to represent 'this'. return; // mutexID is still valid in this case } - } else if (UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) + } else if (CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) { + DeclSeq.push_back(CMCE->getMethodDecl()->getCanonicalDecl()); + buildMutexID(CMCE->getImplicitObjectArgument(), + D, Parent, NumArgs, FunArgs); + unsigned NumCallArgs = CMCE->getNumArgs(); + Expr** CallArgs = CMCE->getArgs(); + for (unsigned i = 0; i < NumCallArgs; ++i) { + buildMutexID(CallArgs[i], D, Parent, NumArgs, FunArgs); + } + } else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) { + buildMutexID(CE->getCallee(), D, Parent, NumArgs, FunArgs); + unsigned NumCallArgs = CE->getNumArgs(); + Expr** CallArgs = CE->getArgs(); + for (unsigned i = 0; i < NumCallArgs; ++i) { + buildMutexID(CallArgs[i], D, Parent, NumArgs, FunArgs); + } + } else if (BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) { + buildMutexID(BOE->getLHS(), D, Parent, NumArgs, FunArgs); + buildMutexID(BOE->getRHS(), D, Parent, NumArgs, FunArgs); + } else if (UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) { buildMutexID(UOE->getSubExpr(), D, Parent, NumArgs, FunArgs); - else if (CastExpr *CE = dyn_cast<CastExpr>(Exp)) + } else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(Exp)) { + buildMutexID(ASE->getBase(), D, Parent, NumArgs, FunArgs); + buildMutexID(ASE->getIdx(), D, Parent, NumArgs, FunArgs); + } else if (AbstractConditionalOperator *CE = + dyn_cast<AbstractConditionalOperator>(Exp)) { + buildMutexID(CE->getCond(), D, Parent, NumArgs, FunArgs); + buildMutexID(CE->getTrueExpr(), D, Parent, NumArgs, FunArgs); + buildMutexID(CE->getFalseExpr(), D, Parent, NumArgs, FunArgs); + } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) { + buildMutexID(CE->getCond(), D, Parent, NumArgs, FunArgs); + buildMutexID(CE->getLHS(), D, Parent, NumArgs, FunArgs); + buildMutexID(CE->getRHS(), D, Parent, NumArgs, FunArgs); + } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp)) { buildMutexID(CE->getSubExpr(), D, Parent, NumArgs, FunArgs); - else - DeclSeq.clear(); // Mark as invalid lock expression. + } else if (ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) { + buildMutexID(PE->getSubExpr(), D, Parent, NumArgs, FunArgs); + } else if (isa<CharacterLiteral>(Exp) || + isa<CXXNullPtrLiteralExpr>(Exp) || + isa<GNUNullExpr>(Exp) || + isa<CXXBoolLiteralExpr>(Exp) || + isa<FloatingLiteral>(Exp) || + isa<ImaginaryLiteral>(Exp) || + isa<IntegerLiteral>(Exp) || + isa<StringLiteral>(Exp) || + isa<ObjCStringLiteral>(Exp)) { + return; // FIXME: Ignore literals for now + } else { + // Ignore. FIXME: mark as invalid expression? + } } /// \brief Construct a MutexID from an expression. @@ -233,11 +277,11 @@ public: /// The caret will point unambiguously to the lock expression, so using this /// name in diagnostics is a way to get simple, and consistent, mutex names. /// We do not want to output the entire expression text for security reasons. - StringRef getName() const { + std::string getName() const { assert(isValid()); if (!DeclSeq.front()) return "this"; // Use 0 to represent 'this'. - return DeclSeq.front()->getName(); + return DeclSeq.front()->getNameAsString(); } void Profile(llvm::FoldingSetNodeID &ID) const { diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp index 1bf00c2243..715645c4f0 100644 --- a/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -766,27 +766,7 @@ void es_bad_7() { // Unparseable lock expressions // ----------------------------------------------// -Mutex UPmu; -// FIXME: add support for lock expressions involving arrays. -Mutex mua[5]; - -int x __attribute__((guarded_by(UPmu = sls_mu))); -int y __attribute__((guarded_by(mua[0]))); - - -void testUnparse() { - x = 5; // \ - // expected-warning{{cannot resolve lock expression}} - y = 5; // \ - // expected-warning{{cannot resolve lock expression}} -} - -void testUnparse2() { - mua[0].Lock(); // \ - // expected-warning{{cannot resolve lock expression}} - (&(mua[0]) + 4)->Lock(); // \ - // expected-warning{{cannot resolve lock expression}} -} +// FIXME -- derive new tests for unhandled expressions //----------------------------------------------------------------------------// @@ -2168,3 +2148,96 @@ class Foo { } // end namespace WarnNoDecl + +namespace MoreLockExpressions { + +class Foo { +public: + Mutex mu_; + int a GUARDED_BY(mu_); +}; + +class Bar { +public: + int b; + Foo* f; + + Foo& getFoo() { return *f; } + Foo& getFoo2(int c) { return *f; } + Foo& getFoo3(int c, int d) { return *f; } + + Foo& getFooey() { return *f; } +}; + +Foo& getBarFoo(Bar &bar, int c) { return bar.getFoo2(c); } + +void test() { + Foo foo; + Foo *fooArray; + Bar bar; + int a; + int b; + int c; + + bar.getFoo().mu_.Lock(); + bar.getFoo().a = 0; + bar.getFoo().mu_.Unlock(); + + (bar.getFoo().mu_).Lock(); // test parenthesis + bar.getFoo().a = 0; + (bar.getFoo().mu_).Unlock(); + + bar.getFoo2(a).mu_.Lock(); + bar.getFoo2(a).a = 0; + bar.getFoo2(a).mu_.Unlock(); + + bar.getFoo3(a, b).mu_.Lock(); + bar.getFoo3(a, b).a = 0; + bar.getFoo3(a, b).mu_.Unlock(); + + getBarFoo(bar, a).mu_.Lock(); + getBarFoo(bar, a).a = 0; + getBarFoo(bar, a).mu_.Unlock(); + + bar.getFoo2(10).mu_.Lock(); + bar.getFoo2(10).a = 0; + bar.getFoo2(10).mu_.Unlock(); + + bar.getFoo2(a + 1).mu_.Lock(); + bar.getFoo2(a + 1).a = 0; + bar.getFoo2(a + 1).mu_.Unlock(); + + (a > 0 ? fooArray[1] : fooArray[b]).mu_.Lock(); + (a > 0 ? fooArray[1] : fooArray[b]).a = 0; + (a > 0 ? fooArray[1] : fooArray[b]).mu_.Unlock(); + + bar.getFoo().mu_.Lock(); + bar.getFooey().a = 0; // \ + // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}} + bar.getFoo().mu_.Unlock(); + + bar.getFoo2(a).mu_.Lock(); + bar.getFoo2(b).a = 0; // \ + // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}} + bar.getFoo2(a).mu_.Unlock(); + + bar.getFoo3(a, b).mu_.Lock(); + bar.getFoo3(a, c).a = 0; // \ + // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}} + bar.getFoo3(a, b).mu_.Unlock(); + + getBarFoo(bar, a).mu_.Lock(); + getBarFoo(bar, b).a = 0; // \ + // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}} + getBarFoo(bar, a).mu_.Unlock(); + + (a > 0 ? fooArray[1] : fooArray[b]).mu_.Lock(); + (a > 0 ? fooArray[b] : fooArray[c]).a = 0; // \ + // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}} + (a > 0 ? fooArray[1] : fooArray[b]).mu_.Unlock(); +} + + +} // end namespace + + |