aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/ThreadSafety.cpp
diff options
context:
space:
mode:
authorDeLesley Hutchins <delesley@google.com>2012-09-07 17:34:53 +0000
committerDeLesley Hutchins <delesley@google.com>2012-09-07 17:34:53 +0000
commit0b4db3e08a201c35f0011489bd5cd5d39bbe54fb (patch)
tree802adac80c460bdcda595a7a1cb4b48f41d584fe /lib/Analysis/ThreadSafety.cpp
parent99d68e9b4cc4a6bdb526722469d3f7412abd82be (diff)
Thread-safety analysis: Add support for selectively turning off warnings
within part of a particular method. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163397 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/ThreadSafety.cpp')
-rw-r--r--lib/Analysis/ThreadSafety.cpp163
1 files changed, 93 insertions, 70 deletions
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index b3e97afd90..d016c3eb2d 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -70,18 +70,19 @@ namespace {
class SExpr {
private:
enum ExprOp {
- EOP_Nop, ///< No-op
- EOP_Wildcard, ///< Matches anything.
- EOP_This, ///< This keyword.
- EOP_NVar, ///< Named variable.
- EOP_LVar, ///< Local variable.
- EOP_Dot, ///< Field access
- EOP_Call, ///< Function call
- EOP_MCall, ///< Method call
- EOP_Index, ///< Array index
- EOP_Unary, ///< Unary operation
- EOP_Binary, ///< Binary operation
- EOP_Unknown ///< Catchall for everything else
+ EOP_Nop, ///< No-op
+ EOP_Wildcard, ///< Matches anything.
+ EOP_Universal, ///< Universal lock.
+ EOP_This, ///< This keyword.
+ EOP_NVar, ///< Named variable.
+ EOP_LVar, ///< Local variable.
+ EOP_Dot, ///< Field access
+ EOP_Call, ///< Function call
+ EOP_MCall, ///< Method call
+ EOP_Index, ///< Array index
+ EOP_Unary, ///< Unary operation
+ EOP_Binary, ///< Binary operation
+ EOP_Unknown ///< Catchall for everything else
};
@@ -118,18 +119,19 @@ private:
unsigned arity() const {
switch (Op) {
- case EOP_Nop: return 0;
- case EOP_Wildcard: return 0;
- case EOP_NVar: return 0;
- case EOP_LVar: return 0;
- case EOP_This: return 0;
- case EOP_Dot: return 1;
- case EOP_Call: return Flags+1; // First arg is function.
- case EOP_MCall: return Flags+1; // First arg is implicit obj.
- case EOP_Index: return 2;
- case EOP_Unary: return 1;
- case EOP_Binary: return 2;
- case EOP_Unknown: return Flags;
+ case EOP_Nop: return 0;
+ case EOP_Wildcard: return 0;
+ case EOP_Universal: return 0;
+ case EOP_NVar: return 0;
+ case EOP_LVar: return 0;
+ case EOP_This: return 0;
+ case EOP_Dot: return 1;
+ case EOP_Call: return Flags+1; // First arg is function.
+ case EOP_MCall: return Flags+1; // First arg is implicit obj.
+ case EOP_Index: return 2;
+ case EOP_Unary: return 1;
+ case EOP_Binary: return 2;
+ case EOP_Unknown: return Flags;
}
return 0;
}
@@ -194,6 +196,11 @@ private:
return NodeVec.size()-1;
}
+ unsigned makeUniversal() {
+ NodeVec.push_back(SExprNode(EOP_Universal, 0, 0));
+ return NodeVec.size()-1;
+ }
+
unsigned makeNamedVar(const NamedDecl *D) {
NodeVec.push_back(SExprNode(EOP_NVar, 0, D));
return NodeVec.size()-1;
@@ -447,10 +454,18 @@ private:
void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) {
CallingContext CallCtx(D);
- // Ignore string literals
- if (MutexExp && isa<StringLiteral>(MutexExp)) {
- makeNop();
- return;
+
+ if (MutexExp) {
+ if (StringLiteral* SLit = dyn_cast<StringLiteral>(MutexExp)) {
+ if (SLit->getString() == StringRef("*"))
+ // The "*" expr is a universal lock, which essentially turns off
+ // checks until it is removed from the lockset.
+ makeUniversal();
+ else
+ // Ignore other string literals for now.
+ makeNop();
+ return;
+ }
}
// If we are processing a raw attribute expression, with no substitutions.
@@ -520,6 +535,11 @@ public:
return NodeVec[0].kind() == EOP_Nop;
}
+ bool isUniversal() const {
+ assert(NodeVec.size() > 0 && "Invalid Mutex");
+ return NodeVec[0].kind() == EOP_Universal;
+ }
+
/// Issue a warning about an invalid lock expression
static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp,
Expr *DeclExp, const NamedDecl* D) {
@@ -567,6 +587,8 @@ public:
return "_";
case EOP_Wildcard:
return "(?)";
+ case EOP_Universal:
+ return "*";
case EOP_This:
return "this";
case EOP_NVar:
@@ -709,6 +731,10 @@ struct LockData {
ID.AddInteger(AcquireLoc.getRawEncoding());
ID.AddInteger(LKind);
}
+
+ bool isAtLeast(LockKind LK) {
+ return (LK == LK_Shared) || (LKind == LK_Exclusive);
+ }
};
@@ -796,7 +822,16 @@ public:
LockData* findLock(FactManager& FM, const SExpr& M) const {
for (const_iterator I=begin(), E=end(); I != E; ++I) {
- if (FM[*I].MutID.matches(M)) return &FM[*I].LDat;
+ const SExpr& E = FM[*I].MutID;
+ if (E.matches(M)) return &FM[*I].LDat;
+ }
+ return 0;
+ }
+
+ LockData* findLockUniv(FactManager& FM, const SExpr& M) const {
+ for (const_iterator I=begin(), E=end(); I != E; ++I) {
+ const SExpr& E = FM[*I].MutID;
+ if (E.matches(M) || E.isUniversal()) return &FM[*I].LDat;
}
return 0;
}
@@ -1654,39 +1689,12 @@ class BuildLockset : public StmtVisitor<BuildLockset> {
void warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, AccessKind AK,
Expr *MutexExp, ProtectedOperationKind POK);
+ void warnIfMutexHeld(const NamedDecl *D, Expr *Exp, Expr *MutexExp);
void checkAccess(Expr *Exp, AccessKind AK);
void checkDereference(Expr *Exp, AccessKind AK);
void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = 0);
- /// \brief Returns true if the lockset contains a lock, regardless of whether
- /// the lock is held exclusively or shared.
- bool locksetContains(const SExpr &Mu) const {
- return FSet.findLock(Analyzer->FactMan, Mu);
- }
-
- /// \brief Returns true if the lockset contains a lock with the passed in
- /// locktype.
- bool locksetContains(const SExpr &Mu, LockKind KindRequested) const {
- const LockData *LockHeld = FSet.findLock(Analyzer->FactMan, Mu);
- return (LockHeld && KindRequested == LockHeld->LKind);
- }
-
- /// \brief Returns true if the lockset contains a lock with at least the
- /// passed in locktype. So for example, if we pass in LK_Shared, this function
- /// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in
- /// LK_Exclusive, this function returns true if the lock is held LK_Exclusive.
- bool locksetContainsAtLeast(const SExpr &Lock,
- LockKind KindRequested) const {
- switch (KindRequested) {
- case LK_Shared:
- return locksetContains(Lock);
- case LK_Exclusive:
- return locksetContains(Lock, KindRequested);
- }
- llvm_unreachable("Unknown LockKind");
- }
-
public:
BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info)
: StmtVisitor<BuildLockset>(),
@@ -1724,15 +1732,35 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp,
LockKind LK = getLockKindFromAccessKind(AK);
SExpr Mutex(MutexExp, Exp, D);
- if (!Mutex.isValid())
+ if (!Mutex.isValid()) {
SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);
- else if (Mutex.shouldIgnore())
- return; // A Nop is an invalid mutex that we've decided to ignore.
- else if (!locksetContainsAtLeast(Mutex, LK))
+ return;
+ } else if (Mutex.shouldIgnore()) {
+ return;
+ }
+
+ LockData* LDat = FSet.findLockUniv(Analyzer->FactMan, Mutex);
+ if (!LDat || !LDat->isAtLeast(LK))
Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK,
Exp->getExprLoc());
}
+/// \brief Warn if the LSet contains the given lock.
+void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp,
+ Expr *MutexExp) {
+ SExpr Mutex(MutexExp, Exp, D);
+ if (!Mutex.isValid()) {
+ SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D);
+ return;
+ }
+
+ LockData* LDat = FSet.findLock(Analyzer->FactMan, Mutex);
+ if (LDat)
+ Analyzer->Handler.handleFunExcludesLock(D->getName(), Mutex.toString(),
+ Exp->getExprLoc());
+}
+
+
/// \brief This method identifies variable dereferences and checks pt_guarded_by
/// and pt_guarded_var annotations. Note that we only check these annotations
/// at the time a pointer is dereferenced.
@@ -1841,15 +1869,10 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
case attr::LocksExcluded: {
LocksExcludedAttr *A = cast<LocksExcludedAttr>(At);
+
for (LocksExcludedAttr::args_iterator I = A->args_begin(),
E = A->args_end(); I != E; ++I) {
- SExpr Mutex(*I, Exp, D);
- if (!Mutex.isValid())
- SExpr::warnInvalidLock(Analyzer->Handler, *I, Exp, D);
- else if (locksetContains(Mutex))
- Analyzer->Handler.handleFunExcludesLock(D->getName(),
- Mutex.toString(),
- Exp->getExprLoc());
+ warnIfMutexHeld(D, Exp, *I);
}
break;
}
@@ -2037,7 +2060,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
JoinLoc, LEK1);
}
}
- else if (!LDat2.Managed)
+ else if (!LDat2.Managed && !FSet2Mutex.isUniversal())
Handler.handleMutexHeldEndOfScope(FSet2Mutex.toString(),
LDat2.AcquireLoc,
JoinLoc, LEK1);
@@ -2060,7 +2083,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
JoinLoc, LEK1);
}
}
- else if (!LDat1.Managed)
+ else if (!LDat1.Managed && !FSet1Mutex.isUniversal())
Handler.handleMutexHeldEndOfScope(FSet1Mutex.toString(),
LDat1.AcquireLoc,
JoinLoc, LEK2);