diff options
Diffstat (limited to 'include/clang/Analysis/Analyses/ThreadSafetyCommon.h')
-rw-r--r-- | include/clang/Analysis/Analyses/ThreadSafetyCommon.h | 140 |
1 files changed, 121 insertions, 19 deletions
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h index 09c614c..be81121 100644 --- a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h +++ b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h @@ -19,21 +19,63 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_THREAD_SAFETY_COMMON_H -#define LLVM_CLANG_THREAD_SAFETY_COMMON_H +#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H +#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" +#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Basic/OperatorKinds.h" - #include <memory> +#include <ostream> +#include <sstream> #include <vector> namespace clang { namespace threadSafety { + +// Various helper functions on til::SExpr +namespace sx { + +inline bool equals(const til::SExpr *E1, const til::SExpr *E2) { + return til::EqualsComparator::compareExprs(E1, E2); +} + +inline bool matches(const til::SExpr *E1, const til::SExpr *E2) { + // We treat a top-level wildcard as the "univsersal" lock. + // It matches everything for the purpose of checking locks, but not + // for unlocking them. + if (isa<til::Wildcard>(E1)) + return isa<til::Wildcard>(E2); + if (isa<til::Wildcard>(E2)) + return isa<til::Wildcard>(E1); + + return til::MatchComparator::compareExprs(E1, E2); +} + +inline bool partiallyMatches(const til::SExpr *E1, const til::SExpr *E2) { + const auto *PE1 = dyn_cast_or_null<til::Project>(E1); + if (!PE1) + return false; + const auto *PE2 = dyn_cast_or_null<til::Project>(E2); + if (!PE2) + return false; + return PE1->clangDecl() == PE2->clangDecl(); +} + +inline std::string toString(const til::SExpr *E) { + std::stringstream ss; + til::StdPrinter::print(E, ss); + return ss.str(); +} + +} // end namespace sx + + + // This class defines the interface of a clang CFG Visitor. // CFGWalker will invoke the following methods. // Note that methods are not virtual; the visitor is templatized. @@ -206,6 +248,59 @@ private: }; + + +class CapabilityExpr { + // TODO: move this back into ThreadSafety.cpp + // This is specific to thread safety. It is here because + // translateAttrExpr needs it, but that should be moved too. + +private: + const til::SExpr* CapExpr; ///< The capability expression. + bool Negated; ///< True if this is a negative capability + +public: + CapabilityExpr(const til::SExpr *E, bool Neg) : CapExpr(E), Negated(Neg) {} + + const til::SExpr* sexpr() const { return CapExpr; } + bool negative() const { return Negated; } + + CapabilityExpr operator!() const { + return CapabilityExpr(CapExpr, !Negated); + } + + bool equals(const CapabilityExpr &other) const { + return (Negated == other.Negated) && sx::equals(CapExpr, other.CapExpr); + } + + bool matches(const CapabilityExpr &other) const { + return (Negated == other.Negated) && sx::matches(CapExpr, other.CapExpr); + } + + bool matchesUniv(const CapabilityExpr &CapE) const { + return isUniversal() || matches(CapE); + } + + bool partiallyMatches(const CapabilityExpr &other) const { + return (Negated == other.Negated) && + sx::partiallyMatches(CapExpr, other.CapExpr); + } + + std::string toString() const { + if (Negated) + return "!" + sx::toString(CapExpr); + return sx::toString(CapExpr); + } + + bool shouldIgnore() const { return CapExpr == nullptr; } + + bool isInvalid() const { return sexpr() && isa<til::Undefined>(sexpr()); } + + bool isUniversal() const { return sexpr() && isa<til::Wildcard>(sexpr()); } +}; + + + // Translate clang::Expr to til::SExpr. class SExprBuilder { public: @@ -219,18 +314,16 @@ public: /// should be evaluated; multiple calling contexts can be chained together /// by the lock_returned attribute. struct CallingContext { + CallingContext *Prev; // The previous context; or 0 if none. const NamedDecl *AttrDecl; // The decl to which the attr is attached. const Expr *SelfArg; // Implicit object argument -- e.g. 'this' unsigned NumArgs; // Number of funArgs const Expr *const *FunArgs; // Function arguments - CallingContext *Prev; // The previous context; or 0 if none. bool SelfArrow; // is Self referred to with -> or .? - CallingContext(const NamedDecl *D = nullptr, const Expr *S = nullptr, - unsigned N = 0, const Expr *const *A = nullptr, - CallingContext *P = nullptr) - : AttrDecl(D), SelfArg(S), NumArgs(N), FunArgs(A), Prev(P), - SelfArrow(false) + CallingContext(CallingContext *P, const NamedDecl *D = nullptr) + : Prev(P), AttrDecl(D), SelfArg(nullptr), + NumArgs(0), FunArgs(nullptr), SelfArrow(false) {} }; @@ -242,6 +335,13 @@ public: SelfVar->setKind(til::Variable::VK_SFun); } + // Translate a clang expression in an attribute to a til::SExpr. + // Constructs the context from D, DeclExp, and SelfDecl. + CapabilityExpr translateAttrExpr(const Expr *AttrExp, const NamedDecl *D, + const Expr *DeclExp, VarDecl *SelfD=nullptr); + + CapabilityExpr translateAttrExpr(const Expr *AttrExp, CallingContext *Ctx); + // Translate a clang statement or expression to a TIL expression. // Also performs substitution of variables; Ctx provides the context. // Dispatches on the type of S. @@ -262,7 +362,8 @@ private: CallingContext *Ctx) ; til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx); til::SExpr *translateMemberExpr(const MemberExpr *ME, CallingContext *Ctx); - til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx); + til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx, + const Expr *SelfE = nullptr); til::SExpr *translateCXXMemberCallExpr(const CXXMemberCallExpr *ME, CallingContext *Ctx); til::SExpr *translateCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE, @@ -280,10 +381,8 @@ private: til::SExpr *translateCastExpr(const CastExpr *CE, CallingContext *Ctx); til::SExpr *translateArraySubscriptExpr(const ArraySubscriptExpr *E, CallingContext *Ctx); - til::SExpr *translateConditionalOperator(const ConditionalOperator *C, - CallingContext *Ctx); - til::SExpr *translateBinaryConditionalOperator( - const BinaryConditionalOperator *C, CallingContext *Ctx); + til::SExpr *translateAbstractConditionalOperator( + const AbstractConditionalOperator *C, CallingContext *Ctx); til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx); @@ -362,21 +461,24 @@ private: void mergePhiNodesBackEdge(const CFGBlock *Blk); private: + // Set to true when parsing capability expressions, which get translated + // inaccurately in order to hack around smart pointers etc. + static const bool CapabilityExprMode = true; + til::MemRegionRef Arena; til::Variable *SelfVar; // Variable to use for 'this'. May be null. - til::SCFG *Scfg; + til::SCFG *Scfg; StatementMap SMap; // Map from Stmt to TIL Variables LVarIndexMap LVarIdxMap; // Indices of clang local vars. std::vector<til::BasicBlock *> BlockMap; // Map from clang to til BBs. std::vector<BlockInfo> BBInfo; // Extra information per BB. // Indexed by clang BlockID. - std::unique_ptr<SExprBuilder::CallingContext> CallCtx; // Root calling context LVarDefinitionMap CurrentLVarMap; - std::vector<til::Variable*> CurrentArguments; - std::vector<til::Variable*> CurrentInstructions; - std::vector<til::Variable*> IncompleteArgs; + std::vector<til::Phi*> CurrentArguments; + std::vector<til::SExpr*> CurrentInstructions; + std::vector<til::Phi*> IncompleteArgs; til::BasicBlock *CurrentBB; BlockInfo *CurrentBlockInfo; }; |