mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-02 13:56:07 +00:00
Thread safety analysis: expand set of expressions that can be used to denote locks.
llvm-svn: 151956
This commit is contained in:
parent
bc638767f8
commit
e2a3f75a12
@ -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 {
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user