diff options
author | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
commit | c72c57c9e9b69944e3e009cd5e209634839581d3 (patch) | |
tree | 4fc2f184c499d106f29a386c452b49e5197bf63d /lib/Analysis/ThreadSafety.cpp | |
parent | 5b20025c30d23d521e12c1f33ec8fa6b821952cd (diff) | |
download | FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.zip FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.tar.gz |
Vendor import of clang trunk r178860:
http://llvm.org/svn/llvm-project/cfe/trunk@178860
Diffstat (limited to 'lib/Analysis/ThreadSafety.cpp')
-rw-r--r-- | lib/Analysis/ThreadSafety.cpp | 290 |
1 files changed, 180 insertions, 110 deletions
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index c7f1f62..4fe342d 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -16,17 +16,18 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Analyses/ThreadSafety.h" -#include "clang/Analysis/Analyses/PostOrderCFGView.h" -#include "clang/Analysis/AnalysisContext.h" -#include "clang/Analysis/CFG.h" -#include "clang/Analysis/CFGStmtMap.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/SourceLocation.h" +#include "clang/Analysis/Analyses/PostOrderCFGView.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/CFGStmtMap.h" #include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableMap.h" @@ -164,15 +165,16 @@ private: /// should be evaluated; multiple calling contexts can be chained together /// by the lock_returned attribute. struct CallingContext { - const NamedDecl* AttrDecl; // The decl to which the attribute is attached. - Expr* SelfArg; // Implicit object argument -- e.g. 'this' - bool SelfArrow; // is Self referred to with -> or .? - unsigned NumArgs; // Number of funArgs - Expr** FunArgs; // Function arguments - CallingContext* PrevCtx; // The previous context; or 0 if none. - - CallingContext(const NamedDecl *D = 0, Expr *S = 0, - unsigned N = 0, Expr **A = 0, CallingContext *P = 0) + const NamedDecl* AttrDecl; // The decl to which the attribute is attached. + const Expr* SelfArg; // Implicit object argument -- e.g. 'this' + bool SelfArrow; // is Self referred to with -> or .? + unsigned NumArgs; // Number of funArgs + const Expr* const* FunArgs; // Function arguments + CallingContext* PrevCtx; // The previous context; or 0 if none. + + CallingContext(const NamedDecl *D = 0, const Expr *S = 0, + unsigned N = 0, const Expr* const *A = 0, + CallingContext *P = 0) : AttrDecl(D), SelfArg(S), SelfArrow(false), NumArgs(N), FunArgs(A), PrevCtx(P) { } @@ -272,15 +274,16 @@ private: /// NDeref returns the number of Derefence and AddressOf operations /// preceeding the Expr; this is used to decide whether to pretty-print /// SExprs with . or ->. - unsigned buildSExpr(Expr *Exp, CallingContext* CallCtx, int* NDeref = 0) { + unsigned buildSExpr(const Expr *Exp, CallingContext* CallCtx, + int* NDeref = 0) { if (!Exp) return 0; - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) { - NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl()); - ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(ND); + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) { + const NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl()); + const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(ND); if (PV) { - FunctionDecl *FD = + const FunctionDecl *FD = cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl(); unsigned i = PV->getFunctionScopeIndex(); @@ -309,18 +312,18 @@ private: makeThis(); return 1; } - } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) { - NamedDecl *ND = ME->getMemberDecl(); + } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) { + const NamedDecl *ND = ME->getMemberDecl(); int ImplicitDeref = ME->isArrow() ? 1 : 0; unsigned Root = makeDot(ND, false); unsigned Sz = buildSExpr(ME->getBase(), CallCtx, &ImplicitDeref); NodeVec[Root].setArrow(ImplicitDeref > 0); NodeVec[Root].setSize(Sz + 1); return Sz + 1; - } else if (CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) { + } else if (const CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) { // When calling a function with a lock_returned attribute, replace // the function call with the expression in lock_returned. - CXXMethodDecl* MD = + const CXXMethodDecl* MD = cast<CXXMethodDecl>(CMCE->getMethodDecl()->getMostRecentDecl()); if (LockReturnedAttr* At = MD->getAttr<LockReturnedAttr>()) { CallingContext LRCallCtx(CMCE->getMethodDecl()); @@ -343,14 +346,14 @@ private: unsigned NumCallArgs = CMCE->getNumArgs(); unsigned Root = makeMCall(NumCallArgs, CMCE->getMethodDecl()); unsigned Sz = buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx); - Expr** CallArgs = CMCE->getArgs(); + const Expr* const* CallArgs = CMCE->getArgs(); for (unsigned i = 0; i < NumCallArgs; ++i) { Sz += buildSExpr(CallArgs[i], CallCtx); } NodeVec[Root].setSize(Sz + 1); return Sz + 1; - } else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) { - FunctionDecl* FD = + } else if (const CallExpr *CE = dyn_cast<CallExpr>(Exp)) { + const FunctionDecl* FD = cast<FunctionDecl>(CE->getDirectCallee()->getMostRecentDecl()); if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) { CallingContext LRCallCtx(CE->getDirectCallee()); @@ -361,7 +364,7 @@ private: } // Treat smart pointers and iterators as pointers; // ignore the * and -> operators. - if (CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(CE)) { + if (const CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(CE)) { OverloadedOperatorKind k = OE->getOperator(); if (k == OO_Star) { if (NDeref) ++(*NDeref); @@ -374,19 +377,19 @@ private: unsigned NumCallArgs = CE->getNumArgs(); unsigned Root = makeCall(NumCallArgs, 0); unsigned Sz = buildSExpr(CE->getCallee(), CallCtx); - Expr** CallArgs = CE->getArgs(); + const Expr* const* CallArgs = CE->getArgs(); for (unsigned i = 0; i < NumCallArgs; ++i) { Sz += buildSExpr(CallArgs[i], CallCtx); } NodeVec[Root].setSize(Sz+1); return Sz+1; - } else if (BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) { + } else if (const BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) { unsigned Root = makeBinary(); unsigned Sz = buildSExpr(BOE->getLHS(), CallCtx); Sz += buildSExpr(BOE->getRHS(), CallCtx); NodeVec[Root].setSize(Sz); return Sz; - } else if (UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) { + } else if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) { // Ignore & and * operators -- they're no-ops. // However, we try to figure out whether the expression is a pointer, // so we can use . and -> appropriately in error messages. @@ -412,13 +415,14 @@ private: unsigned Sz = buildSExpr(UOE->getSubExpr(), CallCtx); NodeVec[Root].setSize(Sz); return Sz; - } else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(Exp)) { + } else if (const ArraySubscriptExpr *ASE = + dyn_cast<ArraySubscriptExpr>(Exp)) { unsigned Root = makeIndex(); unsigned Sz = buildSExpr(ASE->getBase(), CallCtx); Sz += buildSExpr(ASE->getIdx(), CallCtx); NodeVec[Root].setSize(Sz); return Sz; - } else if (AbstractConditionalOperator *CE = + } else if (const AbstractConditionalOperator *CE = dyn_cast<AbstractConditionalOperator>(Exp)) { unsigned Root = makeUnknown(3); unsigned Sz = buildSExpr(CE->getCond(), CallCtx); @@ -426,20 +430,20 @@ private: Sz += buildSExpr(CE->getFalseExpr(), CallCtx); NodeVec[Root].setSize(Sz); return Sz; - } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) { + } else if (const ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) { unsigned Root = makeUnknown(3); unsigned Sz = buildSExpr(CE->getCond(), CallCtx); Sz += buildSExpr(CE->getLHS(), CallCtx); Sz += buildSExpr(CE->getRHS(), CallCtx); NodeVec[Root].setSize(Sz); return Sz; - } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp)) { + } else if (const CastExpr *CE = dyn_cast<CastExpr>(Exp)) { return buildSExpr(CE->getSubExpr(), CallCtx, NDeref); - } else if (ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) { + } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) { return buildSExpr(PE->getSubExpr(), CallCtx, NDeref); - } else if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Exp)) { + } else if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Exp)) { return buildSExpr(EWC->getSubExpr(), CallCtx, NDeref); - } else if (CXXBindTemporaryExpr *E = dyn_cast<CXXBindTemporaryExpr>(Exp)) { + } else if (const CXXBindTemporaryExpr *E = dyn_cast<CXXBindTemporaryExpr>(Exp)) { return buildSExpr(E->getSubExpr(), CallCtx, NDeref); } else if (isa<CharacterLiteral>(Exp) || isa<CXXNullPtrLiteralExpr>(Exp) || @@ -463,12 +467,12 @@ private: /// \param DeclExp An expression involving the Decl on which the attribute /// occurs. /// \param D The declaration to which the lock/unlock attribute is attached. - void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D, - VarDecl *SelfDecl = 0) { + void buildSExprFromExpr(const Expr *MutexExp, const Expr *DeclExp, + const NamedDecl *D, VarDecl *SelfDecl = 0) { CallingContext CallCtx(D); if (MutexExp) { - if (StringLiteral* SLit = dyn_cast<StringLiteral>(MutexExp)) { + if (const 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. @@ -488,18 +492,21 @@ private: // Examine DeclExp to find SelfArg and FunArgs, which are used to substitute // for formal parameters when we call buildMutexID later. - if (MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) { + if (const MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) { CallCtx.SelfArg = ME->getBase(); CallCtx.SelfArrow = ME->isArrow(); - } else if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) { + } else if (const CXXMemberCallExpr *CE = + dyn_cast<CXXMemberCallExpr>(DeclExp)) { CallCtx.SelfArg = CE->getImplicitObjectArgument(); CallCtx.SelfArrow = dyn_cast<MemberExpr>(CE->getCallee())->isArrow(); CallCtx.NumArgs = CE->getNumArgs(); CallCtx.FunArgs = CE->getArgs(); - } else if (CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) { + } else if (const CallExpr *CE = + dyn_cast<CallExpr>(DeclExp)) { CallCtx.NumArgs = CE->getNumArgs(); CallCtx.FunArgs = CE->getArgs(); - } else if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(DeclExp)) { + } else if (const CXXConstructExpr *CE = + dyn_cast<CXXConstructExpr>(DeclExp)) { CallCtx.SelfArg = 0; // Will be set below CallCtx.NumArgs = CE->getNumArgs(); CallCtx.FunArgs = CE->getArgs(); @@ -543,7 +550,7 @@ public: /// occurs. /// \param D The declaration to which the lock/unlock attribute is attached. /// Caller must check isValid() after construction. - SExpr(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D, + SExpr(const Expr* MutexExp, const Expr *DeclExp, const NamedDecl* D, VarDecl *SelfDecl=0) { buildSExprFromExpr(MutexExp, DeclExp, D, SelfDecl); } @@ -566,8 +573,9 @@ public: } /// Issue a warning about an invalid lock expression - static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp, - Expr *DeclExp, const NamedDecl* D) { + static void warnInvalidLock(ThreadSafetyHandler &Handler, + const Expr *MutexExp, + const Expr *DeclExp, const NamedDecl* D) { SourceLocation Loc; if (DeclExp) Loc = DeclExp->getExprLoc(); @@ -776,7 +784,7 @@ struct LockData { /// \brief A FactEntry stores a single fact that is known at a particular point /// in the program execution. Currently, this is information regarding a lock -/// that is held at that point. +/// that is held at that point. struct FactEntry { SExpr MutID; LockData LDat; @@ -789,7 +797,7 @@ struct FactEntry { typedef unsigned short FactID; -/// \brief FactManager manages the memory for all facts that are created during +/// \brief FactManager manages the memory for all facts that are created during /// the analysis of a single routine. class FactManager { private: @@ -807,9 +815,9 @@ public: /// \brief A FactSet is the set of facts that are known to be true at a -/// particular program point. FactSets must be small, because they are +/// particular program point. FactSets must be small, because they are /// frequently copied, and are thus implemented as a set of indices into a -/// table maintained by a FactManager. A typical FactSet only holds 1 or 2 +/// table maintained by a FactManager. A typical FactSet only holds 1 or 2 /// locks, so we can get away with doing a linear search for lookup. Note /// that a hashtable or map is inappropriate in this case, because lookups /// may involve partial pattern matches, rather than exact matches. @@ -1342,8 +1350,8 @@ void LocalVariableMap::traverseCFG(CFG *CFGraph, BE = CurrBlock->end(); BI != BE; ++BI) { switch (BI->getKind()) { case CFGElement::Statement: { - const CFGStmt *CS = cast<CFGStmt>(&*BI); - VMapBuilder.Visit(const_cast<Stmt*>(CS->getStmt())); + CFGStmt CS = BI->castAs<CFGStmt>(); + VMapBuilder.Visit(const_cast<Stmt*>(CS.getStmt())); break; } default: @@ -1389,7 +1397,7 @@ static void findBlockLocations(CFG *CFGraph, for (CFGBlock::const_reverse_iterator BI = CurrBlock->rbegin(), BE = CurrBlock->rend(); BI != BE; ++BI) { // FIXME: Handle other CFGElement kinds. - if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) { + if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) { CurrBlockInfo->ExitLoc = CS->getStmt()->getLocStart(); break; } @@ -1402,7 +1410,7 @@ static void findBlockLocations(CFG *CFGraph, for (CFGBlock::const_iterator BI = CurrBlock->begin(), BE = CurrBlock->end(); BI != BE; ++BI) { // FIXME: Handle other CFGElement kinds. - if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) { + if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) { CurrBlockInfo->EntryLoc = CS->getStmt()->getLocStart(); break; } @@ -1733,14 +1741,15 @@ class BuildLockset : public StmtVisitor<BuildLockset> { unsigned CtxIndex; // Helper functions - const ValueDecl *getValueDecl(Expr *Exp); + const ValueDecl *getValueDecl(const Expr *Exp); - void warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, AccessKind AK, + void warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK, Expr *MutexExp, ProtectedOperationKind POK); - void warnIfMutexHeld(const NamedDecl *D, Expr *Exp, Expr *MutexExp); + void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp); + + void checkAccess(const Expr *Exp, AccessKind AK); + void checkPtAccess(const Expr *Exp, AccessKind AK); - void checkAccess(Expr *Exp, AccessKind AK); - void checkDereference(Expr *Exp, AccessKind AK); void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = 0); public: @@ -1762,7 +1771,10 @@ public: /// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs -const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) { +const ValueDecl *BuildLockset::getValueDecl(const Expr *Exp) { + if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Exp)) + return getValueDecl(CE->getSubExpr()); + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Exp)) return DR->getDecl(); @@ -1774,7 +1786,7 @@ const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) { /// \brief Warn if the LSet does not contain a lock sufficient to protect access /// of at least the passed in AccessKind. -void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, +void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK, Expr *MutexExp, ProtectedOperationKind POK) { LockKind LK = getLockKindFromAccessKind(AK); @@ -1813,7 +1825,7 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, } /// \brief Warn if the LSet contains the given lock. -void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp, +void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr* Exp, Expr *MutexExp) { SExpr Mutex(MutexExp, Exp, D); if (!Mutex.isValid()) { @@ -1831,51 +1843,61 @@ void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp, } -/// \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. -/// FIXME: We need to check for other types of pointer dereferences -/// (e.g. [], ->) and deal with them here. -/// \param Exp An expression that has been read or written. -void BuildLockset::checkDereference(Expr *Exp, AccessKind AK) { - UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp); - if (!UO || UO->getOpcode() != clang::UO_Deref) +/// \brief Checks guarded_by and pt_guarded_by attributes. +/// Whenever we identify an access (read or write) to a DeclRefExpr that is +/// marked with guarded_by, we must ensure the appropriate mutexes are held. +/// Similarly, we check if the access is to an expression that dereferences +/// a pointer marked with pt_guarded_by. +void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK) { + Exp = Exp->IgnoreParenCasts(); + + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp)) { + // For dereferences + if (UO->getOpcode() == clang::UO_Deref) + checkPtAccess(UO->getSubExpr(), AK); return; - Exp = UO->getSubExpr()->IgnoreParenCasts(); + } + + if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) { + if (ME->isArrow()) + checkPtAccess(ME->getBase(), AK); + else + checkAccess(ME->getBase(), AK); + } const ValueDecl *D = getValueDecl(Exp); - if(!D || !D->hasAttrs()) + if (!D || !D->hasAttrs()) return; - if (D->getAttr<PtGuardedVarAttr>() && FSet.isEmpty()) - Analyzer->Handler.handleNoMutexHeld(D, POK_VarDereference, AK, + if (D->getAttr<GuardedVarAttr>() && FSet.isEmpty()) + Analyzer->Handler.handleNoMutexHeld(D, POK_VarAccess, AK, Exp->getExprLoc()); const AttrVec &ArgAttrs = D->getAttrs(); - for(unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i) - if (PtGuardedByAttr *PGBAttr = dyn_cast<PtGuardedByAttr>(ArgAttrs[i])) - warnIfMutexNotHeld(D, Exp, AK, PGBAttr->getArg(), POK_VarDereference); + for (unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i) + if (GuardedByAttr *GBAttr = dyn_cast<GuardedByAttr>(ArgAttrs[i])) + warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarAccess); } -/// \brief Checks guarded_by and guarded_var attributes. -/// Whenever we identify an access (read or write) of a DeclRefExpr or -/// MemberExpr, we need to check whether there are any guarded_by or -/// guarded_var attributes, and make sure we hold the appropriate mutexes. -void BuildLockset::checkAccess(Expr *Exp, AccessKind AK) { +/// \brief Checks pt_guarded_by and pt_guarded_var attributes. +void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) { + Exp = Exp->IgnoreParenCasts(); + const ValueDecl *D = getValueDecl(Exp); - if(!D || !D->hasAttrs()) + if (!D || !D->hasAttrs()) return; - if (D->getAttr<GuardedVarAttr>() && FSet.isEmpty()) - Analyzer->Handler.handleNoMutexHeld(D, POK_VarAccess, AK, + if (D->getAttr<PtGuardedVarAttr>() && FSet.isEmpty()) + Analyzer->Handler.handleNoMutexHeld(D, POK_VarDereference, AK, Exp->getExprLoc()); const AttrVec &ArgAttrs = D->getAttrs(); - for(unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i) - if (GuardedByAttr *GBAttr = dyn_cast<GuardedByAttr>(ArgAttrs[i])) - warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarAccess); + for (unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i) + if (PtGuardedByAttr *GBAttr = dyn_cast<PtGuardedByAttr>(ArgAttrs[i])) + warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarDereference); } + /// \brief Process a function call, method call, constructor call, /// or destructor call. This involves looking at the attributes on the /// corresponding function/method/constructor/destructor, issuing warnings, @@ -2009,9 +2031,7 @@ void BuildLockset::VisitUnaryOperator(UnaryOperator *UO) { case clang::UO_PostInc: case clang::UO_PreDec: case clang::UO_PreInc: { - Expr *SubExp = UO->getSubExpr()->IgnoreParenCasts(); - checkAccess(SubExp, AK_Written); - checkDereference(SubExp, AK_Written); + checkAccess(UO->getSubExpr(), AK_Written); break; } default: @@ -2029,9 +2049,7 @@ void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) { // adjust the context LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, BO, LVarCtx); - Expr *LHSExp = BO->getLHS()->IgnoreParenCasts(); - checkAccess(LHSExp, AK_Written); - checkDereference(LHSExp, AK_Written); + checkAccess(BO->getLHS(), AK_Written); } /// Whenever we do an LValue to Rvalue cast, we are reading a variable and @@ -2040,13 +2058,46 @@ void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) { void BuildLockset::VisitCastExpr(CastExpr *CE) { if (CE->getCastKind() != CK_LValueToRValue) return; - Expr *SubExp = CE->getSubExpr()->IgnoreParenCasts(); - checkAccess(SubExp, AK_Read); - checkDereference(SubExp, AK_Read); + checkAccess(CE->getSubExpr(), AK_Read); } void BuildLockset::VisitCallExpr(CallExpr *Exp) { + if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(Exp)) { + MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee()); + // ME can be null when calling a method pointer + CXXMethodDecl *MD = CE->getMethodDecl(); + + if (ME && MD) { + if (ME->isArrow()) { + if (MD->isConst()) { + checkPtAccess(CE->getImplicitObjectArgument(), AK_Read); + } else { // FIXME -- should be AK_Written + checkPtAccess(CE->getImplicitObjectArgument(), AK_Read); + } + } else { + if (MD->isConst()) + checkAccess(CE->getImplicitObjectArgument(), AK_Read); + else // FIXME -- should be AK_Written + checkAccess(CE->getImplicitObjectArgument(), AK_Read); + } + } + } else if (CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(Exp)) { + switch (OE->getOperator()) { + case OO_Equal: { + const Expr *Target = OE->getArg(0); + const Expr *Source = OE->getArg(1); + checkAccess(Target, AK_Written); + checkAccess(Source, AK_Read); + break; + } + default: { + const Expr *Source = OE->getArg(0); + checkAccess(Source, AK_Read); + break; + } + } + } NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl()); if(!D || !D->hasAttrs()) return; @@ -2054,6 +2105,11 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) { } void BuildLockset::VisitCXXConstructExpr(CXXConstructExpr *Exp) { + const CXXConstructorDecl *D = Exp->getConstructor(); + if (D && D->isCopyConstructor()) { + const Expr* Source = Exp->getArg(0); + checkAccess(Source, AK_Read); + } // FIXME -- only handles constructors in DeclStmt below. } @@ -2164,6 +2220,21 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1, } +// Return true if block B never continues to its successors. +inline bool neverReturns(const CFGBlock* B) { + if (B->hasNoReturnElement()) + return true; + if (B->empty()) + return false; + + CFGElement Last = B->back(); + if (Optional<CFGStmt> S = Last.getAs<CFGStmt>()) { + if (isa<CXXThrowExpr>(S->getStmt())) + return true; + } + return false; +} + /// \brief Check a function's CFG for thread-safety violations. /// @@ -2281,7 +2352,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { // union because the real error is probably that we forgot to unlock M on // all code paths. bool LocksetInitialized = false; - llvm::SmallVector<CFGBlock*, 8> SpecialBlocks; + SmallVector<CFGBlock *, 8> SpecialBlocks; for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(), PE = CurrBlock->pred_end(); PI != PE; ++PI) { @@ -2293,7 +2364,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID]; // Ignore edges from blocks that can't return. - if ((*PI)->hasNoReturnElement() || !PrevBlockInfo->Reachable) + if (neverReturns(*PI) || !PrevBlockInfo->Reachable) continue; // Okay, we can reach this block from the entry. @@ -2310,7 +2381,6 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { } } - FactSet PrevLockset; getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock); @@ -2368,22 +2438,22 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { BE = CurrBlock->end(); BI != BE; ++BI) { switch (BI->getKind()) { case CFGElement::Statement: { - const CFGStmt *CS = cast<CFGStmt>(&*BI); - LocksetBuilder.Visit(const_cast<Stmt*>(CS->getStmt())); + CFGStmt CS = BI->castAs<CFGStmt>(); + LocksetBuilder.Visit(const_cast<Stmt*>(CS.getStmt())); break; } // Ignore BaseDtor, MemberDtor, and TemporaryDtor for now. case CFGElement::AutomaticObjectDtor: { - const CFGAutomaticObjDtor *AD = cast<CFGAutomaticObjDtor>(&*BI); - CXXDestructorDecl *DD = const_cast<CXXDestructorDecl*>( - AD->getDestructorDecl(AC.getASTContext())); + CFGAutomaticObjDtor AD = BI->castAs<CFGAutomaticObjDtor>(); + CXXDestructorDecl *DD = const_cast<CXXDestructorDecl *>( + AD.getDestructorDecl(AC.getASTContext())); if (!DD->hasAttrs()) break; // Create a dummy expression, - VarDecl *VD = const_cast<VarDecl*>(AD->getVarDecl()); + VarDecl *VD = const_cast<VarDecl*>(AD.getVarDecl()); DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue, - AD->getTriggerStmt()->getLocEnd()); + AD.getTriggerStmt()->getLocEnd()); LocksetBuilder.handleCall(&DRE, DD); break; } |