Thread safety analysis: expand set of expressions that can be used to denote locks.

llvm-svn: 151956
This commit is contained in:
DeLesley Hutchins 2012-03-02 23:36:05 +00:00
parent bc638767f8
commit e2a3f75a12
2 changed files with 144 additions and 27 deletions

View File

@ -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 {

View File

@ -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