diff options
Diffstat (limited to 'include/clang/Analysis')
-rw-r--r-- | include/clang/Analysis/Analyses/LiveVariables.h | 6 | ||||
-rw-r--r-- | include/clang/Analysis/PathDiagnostic.h | 19 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/AnalysisContext.h | 14 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/BugReporter.h | 21 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/BugType.h | 30 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/Checker.h | 101 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/CheckerVisitor.def | 18 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h | 33 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/ExplodedGraph.h | 14 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRCoreEngine.h | 4 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRExprEngine.h | 131 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRState.h | 28 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/MemRegion.h | 161 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/ValueManager.h | 3 |
14 files changed, 329 insertions, 254 deletions
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h index 8674943..0077a85 100644 --- a/include/clang/Analysis/Analyses/LiveVariables.h +++ b/include/clang/Analysis/Analyses/LiveVariables.h @@ -23,6 +23,7 @@ namespace clang { class Stmt; class DeclRefExpr; class SourceManager; +class AnalysisContext; struct LiveVariables_ValueTypes { @@ -39,8 +40,9 @@ struct LiveVariables_ValueTypes { struct AnalysisDataTy : public StmtDeclBitVector_Types::AnalysisDataTy { ObserverTy* Observer; ValTy AlwaysLive; + AnalysisContext *AC; - AnalysisDataTy() : Observer(NULL) {} + AnalysisDataTy() : Observer(NULL), AC(NULL) {} }; //===-----------------------------------------------------===// @@ -66,7 +68,7 @@ class LiveVariables : public DataflowValues<LiveVariables_ValueTypes, public: typedef LiveVariables_ValueTypes::ObserverTy ObserverTy; - LiveVariables(ASTContext& Ctx, CFG& cfg); + LiveVariables(AnalysisContext &AC); /// IsLive - Return true if a variable is live at beginning of a /// specified block. diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h index efc6677..cad702c 100644 --- a/include/clang/Analysis/PathDiagnostic.h +++ b/include/clang/Analysis/PathDiagnostic.h @@ -14,31 +14,24 @@ #ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H #define LLVM_CLANG_PATH_DIAGNOSTIC_H -#include "clang/Basic/SourceManager.h" #include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/FoldingSet.h" - -#include <vector> #include <deque> +#include <iterator> #include <string> -#include <algorithm> +#include <vector> namespace clang { - -class Stmt; + class Decl; -class Preprocessor; - +class SourceManager; +class Stmt; + //===----------------------------------------------------------------------===// // High-level interface for handlers of path-sensitive diagnostics. //===----------------------------------------------------------------------===// class PathDiagnostic; - -class Stmt; -class Decl; -class Preprocessor; class PathDiagnosticClient : public DiagnosticClient { public: diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h index 9b58f74..8b1a329 100644 --- a/include/clang/Analysis/PathSensitive/AnalysisContext.h +++ b/include/clang/Analysis/PathSensitive/AnalysisContext.h @@ -19,6 +19,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Allocator.h" namespace clang { @@ -38,17 +39,26 @@ class AnalysisContext { CFG *cfg; LiveVariables *liveness; ParentMap *PM; - + llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars; + llvm::BumpPtrAllocator A; public: - AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0) {} + AnalysisContext(const Decl *d) : D(d), cfg(0), liveness(0), PM(0), + ReferencedBlockVars(0) {} + ~AnalysisContext(); + ASTContext &getASTContext() { return D->getASTContext(); } const Decl *getDecl() { return D; } Stmt *getBody(); CFG *getCFG(); ParentMap &getParentMap(); LiveVariables *getLiveVariables(); + typedef const VarDecl * const * referenced_decls_iterator; + + std::pair<referenced_decls_iterator, referenced_decls_iterator> + getReferencedBlockVars(const BlockDecl *BD); + /// Return the ImplicitParamDecl* associated with 'self' if this /// AnalysisContext wraps an ObjCMethodDecl. Returns NULL otherwise. const ImplicitParamDecl *getSelfDecl() const; diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h index f429735..58c8018 100644 --- a/include/clang/Analysis/PathSensitive/BugReporter.h +++ b/include/clang/Analysis/PathSensitive/BugReporter.h @@ -309,32 +309,33 @@ public: void EmitReport(BugReport *R); - void EmitBasicReport(const char* BugName, const char* BugStr, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, SourceLocation Loc, SourceRange* RangeBeg, unsigned NumRanges); - void EmitBasicReport(const char* BugName, const char* BugCategory, - const char* BugStr, SourceLocation Loc, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory, + llvm::StringRef BugStr, SourceLocation Loc, SourceRange* RangeBeg, unsigned NumRanges); - void EmitBasicReport(const char* BugName, const char* BugStr, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, SourceLocation Loc) { EmitBasicReport(BugName, BugStr, Loc, 0, 0); } - void EmitBasicReport(const char* BugName, const char* BugCategory, - const char* BugStr, SourceLocation Loc) { + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory, + llvm::StringRef BugStr, SourceLocation Loc) { EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0); } - void EmitBasicReport(const char* BugName, const char* BugStr, + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr, SourceLocation Loc, SourceRange R) { EmitBasicReport(BugName, BugStr, Loc, &R, 1); } - void EmitBasicReport(const char* BugName, const char* Category, - const char* BugStr, SourceLocation Loc, SourceRange R) { + void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category, + llvm::StringRef BugStr, SourceLocation Loc, + SourceRange R) { EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1); } @@ -432,7 +433,7 @@ class DiagBugReport : public RangedBugReport { std::list<std::string> Strs; FullSourceLoc L; public: - DiagBugReport(BugType& D, const char* desc, FullSourceLoc l) : + DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) : RangedBugReport(D, desc, 0), L(l) {} virtual ~DiagBugReport() {} diff --git a/include/clang/Analysis/PathSensitive/BugType.h b/include/clang/Analysis/PathSensitive/BugType.h index 8303dee..4f1523a 100644 --- a/include/clang/Analysis/PathSensitive/BugType.h +++ b/include/clang/Analysis/PathSensitive/BugType.h @@ -34,13 +34,13 @@ private: friend class BugReporter; bool SuppressonSink; public: - BugType(const char *name, const char* cat) + BugType(llvm::StringRef name, llvm::StringRef cat) : Name(name), Category(cat), SuppressonSink(false) {} virtual ~BugType(); // FIXME: Should these be made strings as well? - const std::string& getName() const { return Name; } - const std::string& getCategory() const { return Category; } + llvm::StringRef getName() const { return Name; } + llvm::StringRef getCategory() const { return Category; } /// isSuppressOnSink - Returns true if bug reports associated with this bug /// type should be suppressed if the end node of the report is post-dominated @@ -60,33 +60,15 @@ public: }; class BuiltinBug : public BugType { - GRExprEngine *Eng; -protected: const std::string desc; public: BuiltinBug(const char *name, const char *description) - : BugType(name, "Logic error"), Eng(0), desc(description) {} + : BugType(name, "Logic error"), desc(description) {} BuiltinBug(const char *name) - : BugType(name, "Logic error"), Eng(0), desc(name) {} + : BugType(name, "Logic error"), desc(name) {} - BuiltinBug(GRExprEngine *eng, const char* n, const char* d) - : BugType(n, "Logic error"), Eng(eng), desc(d) {} - - BuiltinBug(GRExprEngine *eng, const char* n) - : BugType(n, "Logic error"), Eng(eng), desc(n) {} - - const std::string &getDescription() const { return desc; } - - virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {} - - void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, *Eng); } - - virtual void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) {} - - template <typename ITER> void Emit(BugReporter& BR, ITER I, ITER E); + llvm::StringRef getDescription() const { return desc; } }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/Checker.h b/include/clang/Analysis/PathSensitive/Checker.h index b7ed20f..91a4b6d 100644 --- a/include/clang/Analysis/PathSensitive/Checker.h +++ b/include/clang/Analysis/PathSensitive/Checker.h @@ -40,24 +40,35 @@ class CheckerContext { SaveAndRestore<ProgramPoint::Kind> OldPointKind; SaveOr OldHasGen; const GRState *state; - + const Stmt *statement; + const unsigned size; + bool DoneEvaluating; // FIXME: This is not a permanent API change. public: CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder, GRExprEngine &eng, ExplodedNode *pred, const void *tag, ProgramPoint::Kind K, - const GRState *st = 0) + const Stmt *stmt = 0, const GRState *st = 0) : Dst(dst), B(builder), Eng(eng), Pred(pred), OldSink(B.BuildSinks), OldTag(B.Tag, tag), OldPointKind(B.PointKind, K), OldHasGen(B.HasGeneratedNode), - state(st) {} + state(st), statement(stmt), size(Dst.size()), + DoneEvaluating(false) {} - ~CheckerContext() { - if (!B.BuildSinks && !B.HasGeneratedNode) - Dst.Add(Pred); + ~CheckerContext(); + + // FIXME: This were added to support CallAndMessageChecker to indicating + // to GRExprEngine to "stop evaluating" a message expression under certain + // cases. This is *not* meant to be a permanent API change, and was added + // to aid in the transition of removing logic for checks from GRExprEngine. + void setDoneEvaluating() { + DoneEvaluating = true; } - + bool isDoneEvaluating() const { + return DoneEvaluating; + } + ConstraintManager &getConstraintManager() { return Eng.getConstraintManager(); } @@ -83,27 +94,70 @@ public: return getBugReporter().getSourceManager(); } - ExplodedNode *GenerateNode(const Stmt *S, bool markAsSink = false) { - return GenerateNode(S, getState(), markAsSink); + ValueManager &getValueManager() { + return Eng.getValueManager(); } - ExplodedNode *GenerateNode(const Stmt* S, const GRState *state, - bool markAsSink = false) { - ExplodedNode *node = B.generateNode(S, state, Pred); + ExplodedNode *GenerateNode(bool autoTransition = true) { + assert(statement && "Only transitions with statements currently supported"); + ExplodedNode *N = GenerateNodeImpl(statement, getState(), false); + if (N && autoTransition) + Dst.Add(N); + return N; + } + + ExplodedNode *GenerateNode(const Stmt *stmt, const GRState *state, + bool autoTransition = true) { + assert(state); + ExplodedNode *N = GenerateNodeImpl(stmt, state, false); + if (N && autoTransition) + addTransition(N); + return N; + } - if (markAsSink && node) - node->markAsSink(); + ExplodedNode *GenerateNode(const GRState *state, bool autoTransition = true) { + assert(statement && "Only transitions with statements currently supported"); + ExplodedNode *N = GenerateNodeImpl(statement, state, false); + if (N && autoTransition) + addTransition(N); + return N; + } - return node; + ExplodedNode *GenerateSink(const Stmt *stmt, const GRState *state = 0) { + return GenerateNodeImpl(stmt, state ? state : getState(), true); + } + + ExplodedNode *GenerateSink(const GRState *state = 0) { + assert(statement && "Only transitions with statements currently supported"); + return GenerateNodeImpl(statement, state ? state : getState(), true); } void addTransition(ExplodedNode *node) { Dst.Add(node); } + + void addTransition(const GRState *state) { + assert(state); + if (state != getState() || + (state && state != B.GetState(Pred))) + GenerateNode(state, true); + else + Dst.Add(Pred); + } void EmitReport(BugReport *R) { Eng.getBugReporter().EmitReport(R); } + +private: + ExplodedNode *GenerateNodeImpl(const Stmt* stmt, const GRState *state, + bool markAsSink) { + ExplodedNode *node = B.generateNode(stmt, state, Pred); + if (markAsSink && node) + node->markAsSink(); + return node; + } + }; class Checker { @@ -111,18 +165,19 @@ private: friend class GRExprEngine; // FIXME: Remove the 'tag' option. - void GR_Visit(ExplodedNodeSet &Dst, + bool GR_Visit(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder, GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, void *tag, bool isPrevisit) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind); + ProgramPoint::PostStmtKind, S); if (isPrevisit) _PreVisit(C, S); else _PostVisit(C, S); + return C.isDoneEvaluating(); } // FIXME: Remove the 'tag' option. @@ -134,7 +189,7 @@ private: bool isPrevisit) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit ? ProgramPoint::PreStmtKind : - ProgramPoint::PostStmtKind); + ProgramPoint::PostStmtKind, StoreE); assert(isPrevisit && "Only previsit supported for now."); PreVisitBind(C, AssignE, StoreE, location, val); } @@ -149,7 +204,7 @@ private: void *tag, bool isLoad) { CheckerContext C(Dst, Builder, Eng, Pred, tag, isLoad ? ProgramPoint::PreLoadKind : - ProgramPoint::PreStoreKind, state); + ProgramPoint::PreStoreKind, S, state); VisitLocation(C, S, location); } @@ -157,12 +212,12 @@ private: GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred, SymbolReaper &SymReaper, void *tag) { CheckerContext C(Dst, Builder, Eng, Pred, tag, - ProgramPoint::PostPurgeDeadSymbolsKind, Pred->getState()); + ProgramPoint::PostPurgeDeadSymbolsKind, S); EvalDeadSymbols(C, S, SymReaper); } public: - virtual ~Checker() {} + virtual ~Checker(); virtual void _PreVisit(CheckerContext &C, const Stmt *S) {} virtual void _PostVisit(CheckerContext &C, const Stmt *S) {} virtual void VisitLocation(CheckerContext &C, const Stmt *S, SVal location) {} @@ -172,6 +227,10 @@ public: SymbolReaper &SymReaper) {} virtual void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng) {} + + virtual void VisitBranchCondition(GRBranchNodeBuilder &Builder, + GRExprEngine &Eng, + Stmt *Condition, void *tag) {} }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/CheckerVisitor.def b/include/clang/Analysis/PathSensitive/CheckerVisitor.def index 090a5d3..4144d1a 100644 --- a/include/clang/Analysis/PathSensitive/CheckerVisitor.def +++ b/include/clang/Analysis/PathSensitive/CheckerVisitor.def @@ -11,7 +11,14 @@ // //===---------------------------------------------------------------------===// -#ifdef PREVISIT +#ifndef PREVISIT +#define PREVISIT(NODE) +#endif + +#ifndef POSTVISIT +#define POSTVISIT(NODE) +#endif + PREVISIT(ArraySubscriptExpr) PREVISIT(BinaryOperator) PREVISIT(CallExpr) @@ -19,11 +26,10 @@ PREVISIT(CastExpr) PREVISIT(DeclStmt) PREVISIT(ObjCMessageExpr) PREVISIT(ReturnStmt) -#undef PREVISIT -#endif -#ifdef POSTVISIT POSTVISIT(CallExpr) -#undef POSTVISIT -#endif +POSTVISIT(BlockExpr) +POSTVISIT(BinaryOperator) +#undef PREVISIT +#undef POSTVISIT diff --git a/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h b/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h deleted file mode 100644 index 13437eb..0000000 --- a/include/clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h +++ /dev/null @@ -1,33 +0,0 @@ -//===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This defines UndefinedAssginmentChecker, a builtin check in GRExprEngine that -// checks for assigning undefined values. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_UNDEFASSIGNMENTCHECKER -#define LLVM_CLANG_UNDEFASSIGNMENTCHECKER - -#include "clang/Analysis/PathSensitive/CheckerVisitor.h" - -namespace clang { -class UndefinedAssignmentChecker - : public CheckerVisitor<UndefinedAssignmentChecker> { - BugType *BT; -public: - UndefinedAssignmentChecker() : BT(0) {} - static void *getTag(); - virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE, - const Stmt *StoreE, SVal location, - SVal val); -}; -} -#endif - diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h index a7bbdf9..76cab1d 100644 --- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h +++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h @@ -352,10 +352,16 @@ public: typedef ImplTy::iterator iterator; typedef ImplTy::const_iterator const_iterator; - inline unsigned size() const { return Impl.size(); } - inline bool empty() const { return Impl.empty(); } - - inline void clear() { Impl.clear(); } + unsigned size() const { return Impl.size(); } + bool empty() const { return Impl.empty(); } + + void clear() { Impl.clear(); } + void insert(const ExplodedNodeSet &S) { + if (empty()) + Impl = S.Impl; + else + Impl.insert(S.begin(), S.end()); + } inline iterator begin() { return Impl.begin(); } inline iterator end() { return Impl.end(); } diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h index 02e0b027..b78cc6a 100644 --- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -215,7 +215,7 @@ public: void setAuditor(GRAuditor* A) { Auditor = A; } const GRState* GetState(ExplodedNode* Pred) const { - if ((ExplodedNode*) Pred == getBasePredecessor()) + if (Pred == getBasePredecessor()) return CleanedState; else return Pred->getState(); @@ -405,6 +405,8 @@ class GREndPathNodeBuilder { GRCoreEngine& Eng; CFGBlock& B; ExplodedNode* Pred; + +public: bool HasGeneratedNode; public: diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 1b6d0bd..a7302c0 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -88,55 +88,6 @@ class GRExprEngine : public GRSubEngine { GRBugReporter BR; public: - typedef llvm::SmallPtrSet<ExplodedNode*,2> ErrorNodes; - typedef llvm::DenseMap<ExplodedNode*, Expr*> UndefArgsTy; - - /// NilReceiverStructRetExplicit - Nodes in the ExplodedGraph that resulted - /// from [x ...] with 'x' definitely being nil and the result was a 'struct' - // (an undefined value). - ErrorNodes NilReceiverStructRetExplicit; - - /// NilReceiverStructRetImplicit - Nodes in the ExplodedGraph that resulted - /// from [x ...] with 'x' possibly being nil and the result was a 'struct' - // (an undefined value). - ErrorNodes NilReceiverStructRetImplicit; - - /// NilReceiverLargerThanVoidPtrRetExplicit - Nodes in the ExplodedGraph that - /// resulted from [x ...] with 'x' definitely being nil and the result's size - // was larger than sizeof(void *) (an undefined value). - ErrorNodes NilReceiverLargerThanVoidPtrRetExplicit; - - /// NilReceiverLargerThanVoidPtrRetImplicit - Nodes in the ExplodedGraph that - /// resulted from [x ...] with 'x' possibly being nil and the result's size - // was larger than sizeof(void *) (an undefined value). - ErrorNodes NilReceiverLargerThanVoidPtrRetImplicit; - - /// UndefBranches - Nodes in the ExplodedGraph that result from - /// taking a branch based on an undefined value. - ErrorNodes UndefBranches; - - /// UndefStores - Sinks in the ExplodedGraph that result from - /// making a store to an undefined lvalue. - ErrorNodes UndefStores; - - /// NoReturnCalls - Sinks in the ExplodedGraph that result from - // calling a function with the attribute "noreturn". - ErrorNodes NoReturnCalls; - - /// UndefResults - Nodes in the ExplodedGraph where the operands are defined - /// by the result is not. Excludes divide-by-zero errors. - ErrorNodes UndefResults; - - /// UndefReceiver - Nodes in the ExplodedGraph resulting from message - /// ObjC message expressions where the receiver is undefined (uninitialized). - ErrorNodes UndefReceivers; - - /// MsgExprUndefArgs - Nodes in the ExplodedGraph resulting from - /// message expressions where a pass-by-value argument has an undefined - /// value. - UndefArgsTy MsgExprUndefArgs; - -public: GRExprEngine(AnalysisManager &mgr); ~GRExprEngine(); @@ -178,8 +129,6 @@ public: ExplodedGraph& getGraph() { return G; } const ExplodedGraph& getGraph() const { return G; } - void RegisterInternalChecks(); - template <typename CHECKER> void registerCheck(CHECKER *check) { unsigned entry = Checkers.size(); @@ -195,58 +144,6 @@ public: return static_cast<CHECKER*>(lookupChecker(CHECKER::getTag())); } - bool isNoReturnCall(const ExplodedNode* N) const { - return N->isSink() && NoReturnCalls.count(const_cast<ExplodedNode*>(N)) != 0; - } - - typedef ErrorNodes::iterator undef_branch_iterator; - undef_branch_iterator undef_branches_begin() { return UndefBranches.begin(); } - undef_branch_iterator undef_branches_end() { return UndefBranches.end(); } - - typedef ErrorNodes::iterator nil_receiver_struct_ret_iterator; - - nil_receiver_struct_ret_iterator nil_receiver_struct_ret_begin() { - return NilReceiverStructRetExplicit.begin(); - } - - nil_receiver_struct_ret_iterator nil_receiver_struct_ret_end() { - return NilReceiverStructRetExplicit.end(); - } - - typedef ErrorNodes::iterator nil_receiver_larger_than_voidptr_ret_iterator; - - nil_receiver_larger_than_voidptr_ret_iterator - nil_receiver_larger_than_voidptr_ret_begin() { - return NilReceiverLargerThanVoidPtrRetExplicit.begin(); - } - - nil_receiver_larger_than_voidptr_ret_iterator - nil_receiver_larger_than_voidptr_ret_end() { - return NilReceiverLargerThanVoidPtrRetExplicit.end(); - } - - typedef ErrorNodes::iterator undef_result_iterator; - undef_result_iterator undef_results_begin() { return UndefResults.begin(); } - undef_result_iterator undef_results_end() { return UndefResults.end(); } - - typedef UndefArgsTy::iterator undef_arg_iterator; - undef_arg_iterator msg_expr_undef_arg_begin() { - return MsgExprUndefArgs.begin(); - } - undef_arg_iterator msg_expr_undef_arg_end() { - return MsgExprUndefArgs.end(); - } - - typedef ErrorNodes::iterator undef_receivers_iterator; - - undef_receivers_iterator undef_receivers_begin() { - return UndefReceivers.begin(); - } - - undef_receivers_iterator undef_receivers_end() { - return UndefReceivers.end(); - } - void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C); void AddCheck(GRSimpleAPICheck* A); @@ -312,7 +209,7 @@ public: protected: /// CheckerVisit - Dispatcher for performing checker-specific logic /// at specific statements. - void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + bool CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit); void CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, @@ -345,6 +242,9 @@ protected: AsmStmt::inputs_iterator I, AsmStmt::inputs_iterator E, ExplodedNode* Pred, ExplodedNodeSet& Dst); + + /// VisitBlockExpr - Transfer function logic for BlockExprs. + void VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet &Dst); /// VisitBinaryOperator - Transfer function logic for binary operators. void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, @@ -361,33 +261,38 @@ protected: unsigned ParamIdx = 0); /// VisitCast - Transfer function logic for all casts (implicit and explicit). - void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue); /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs. - void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst, - bool asLValue); + void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); /// VisitDeclStmt - Transfer function logic for DeclStmts. void VisitDeclStmt(DeclStmt* DS, ExplodedNode* Pred, ExplodedNodeSet& Dst); /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose - void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, + ExplodedNodeSet& Dst); - void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitLogicalExpr - Transfer function logic for '&&', '||' - void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst); + void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitMemberExpr - Transfer function for member expressions. - void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst,bool asLValue); + void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst, + bool asLValue); /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs. - void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, ExplodedNodeSet& Dst, - bool asLValue); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred, + ExplodedNodeSet& Dst, bool asLValue); /// VisitObjCForCollectionStmt - Transfer function logic for /// ObjCForCollectionStmt. diff --git a/include/clang/Analysis/PathSensitive/GRState.h b/include/clang/Analysis/PathSensitive/GRState.h index ef0c36c..d8bc241 100644 --- a/include/clang/Analysis/PathSensitive/GRState.h +++ b/include/clang/Analysis/PathSensitive/GRState.h @@ -33,7 +33,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include <functional> @@ -264,8 +263,21 @@ public: const llvm::APSInt *getSymVal(SymbolRef sym); bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; + + bool scanReachableSymbols(const SVal *I, const SVal *E, + SymbolVisitor &visitor) const; + + bool scanReachableSymbols(const MemRegion * const *I, + const MemRegion * const *E, + SymbolVisitor &visitor) const; template <typename CB> CB scanReachableSymbols(SVal val) const; + template <typename CB> CB scanReachableSymbols(const SVal *beg, + const SVal *end) const; + + template <typename CB> CB + scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const; //==---------------------------------------------------------------------==// // Accessing the Generic Data Map (GDM). @@ -726,7 +738,21 @@ CB GRState::scanReachableSymbols(SVal val) const { scanReachableSymbols(val, cb); return cb; } + +template <typename CB> +CB GRState::scanReachableSymbols(const SVal *beg, const SVal *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} +template <typename CB> +CB GRState::scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} } // end clang namespace #endif diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index 06d0d97..ed96497 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -35,6 +35,7 @@ namespace clang { class MemRegionManager; class MemSpaceRegion; class LocationContext; +class VarRegion; //===----------------------------------------------------------------------===// // Base region classes. @@ -42,13 +43,16 @@ class LocationContext; /// MemRegion - The root abstract class for all memory regions. class MemRegion : public llvm::FoldingSetNode { + friend class MemRegionManager; public: enum Kind { MemSpaceRegionKind, SymbolicRegionKind, AllocaRegionKind, // Typed regions. BEG_TYPED_REGIONS, - CodeTextRegionKind, + FunctionTextRegionKind, + BlockTextRegionKind, + BlockDataRegionKind, CompoundLiteralRegionKind, StringRegionKind, ElementRegionKind, // Decl Regions. @@ -237,45 +241,123 @@ public: } }; -/// CodeTextRegion - A region that represents code texts of a function. It wraps -/// two kinds of code texts: real function and symbolic function. Real function -/// is a function declared in the program. Symbolic function is a function -/// pointer that we don't know which function it points to. -class CodeTextRegion : public TypedRegion { - const FunctionDecl *FD; +class CodeTextRegion : public TypedRegion { +protected: + CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {} public: - - CodeTextRegion(const FunctionDecl* fd, const MemRegion* sreg) - : TypedRegion(sreg, CodeTextRegionKind), FD(fd) {} - QualType getValueType(ASTContext &C) const { // Do not get the object type of a CodeTextRegion. assert(0); return QualType(); } + + bool isBoundable() const { return false; } + + static bool classof(const MemRegion* R) { + Kind k = R->getKind(); + return k >= FunctionTextRegionKind && k <= BlockTextRegionKind; + } +}; +/// FunctionTextRegion - A region that represents code texts of function. +class FunctionTextRegion : public CodeTextRegion { + const FunctionDecl *FD; +public: + FunctionTextRegion(const FunctionDecl* fd, const MemRegion* sreg) + : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {} + QualType getLocationType(ASTContext &C) const { return C.getPointerType(FD->getType()); } - + const FunctionDecl *getDecl() const { return FD; } - - bool isBoundable() const { return false; } - + virtual void dumpToStream(llvm::raw_ostream& os) const; - + void Profile(llvm::FoldingSetNodeID& ID) const; - + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD, const MemRegion*); - + + static bool classof(const MemRegion* R) { + return R->getKind() == FunctionTextRegionKind; + } +}; + + +/// BlockTextRegion - A region that represents code texts of blocks (closures). +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +class BlockTextRegion : public CodeTextRegion { + const BlockDecl *BD; + CanQualType locTy; +public: + BlockTextRegion(const BlockDecl *bd, CanQualType lTy, const MemRegion* sreg) + : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), locTy(lTy) {} + + QualType getLocationType(ASTContext &C) const { + return locTy; + } + + const BlockDecl *getDecl() const { + return BD; + } + + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, + CanQualType, const MemRegion*); + static bool classof(const MemRegion* R) { - return R->getKind() == CodeTextRegionKind; + return R->getKind() == BlockTextRegionKind; } }; + +/// BlockDataRegion - A region that represents a block instance. +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +/// BlockDataRegion - A region that represents code texts of blocks (closures). +class BlockDataRegion : public SubRegion { + const BlockTextRegion *BC; + const LocationContext *LC; + void *ReferencedVars; +public: + BlockDataRegion(const BlockTextRegion *bc, + const LocationContext *lc, + const MemRegion *sreg) + : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), ReferencedVars(0) {} + + const BlockTextRegion *getCodeRegion() const { return BC; } + + typedef const MemRegion * const * referenced_vars_iterator; + referenced_vars_iterator referenced_vars_begin() const; + referenced_vars_iterator referenced_vars_end() const; + + virtual void dumpToStream(llvm::raw_ostream& os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const BlockTextRegion *BC, + const LocationContext *LC, const MemRegion *); + + static bool classof(const MemRegion* R) { + return R->getKind() == BlockDataRegionKind; + } +private: + void LazyInitializeReferencedVars(); +}; /// SymbolicRegion - A special, "non-concrete" region. Unlike other region /// clases, SymbolicRegion represents a region that serves as an alias for @@ -577,9 +659,11 @@ public: : C(c), A(a), globals(0), stack(0), stackArguments(0), heap(0), unknown(0), code(0) {} - ~MemRegionManager() {} + ~MemRegionManager(); ASTContext &getContext() { return C; } + + llvm::BumpPtrAllocator &getAllocator() { return A; } /// getStackRegion - Retrieve the memory region associated with the /// current stack frame. @@ -656,7 +740,10 @@ public: ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* superRegion); - CodeTextRegion *getCodeTextRegion(const FunctionDecl *FD); + FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD); + BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, CanQualType locTy); + BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc, + const LocationContext *lc); template <typename RegionTy, typename A1> RegionTy* getRegion(const A1 a1); @@ -667,6 +754,10 @@ public: template <typename RegionTy, typename A1, typename A2> RegionTy* getRegion(const A1 a1, const A2 a2); + template <typename RegionTy, typename A1, typename A2> + RegionTy* getSubRegion(const A1 a1, const A2 a2, + const MemRegion* superRegion); + bool isGlobalsRegion(const MemRegion* R) { assert(R); return R == globals; @@ -745,6 +836,25 @@ RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { return R; } + +template <typename RegionTy, typename A1, typename A2> +RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, + const MemRegion *superRegion) { + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, a2, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate<RegionTy>(); + new (R) RegionTy(a1, a2, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} //===----------------------------------------------------------------------===// // Traits for constructing regions. @@ -801,18 +911,21 @@ template <> struct MemRegionManagerTrait<SymbolicRegion> { } }; -template<> struct MemRegionManagerTrait<CodeTextRegion> { +template<> struct MemRegionManagerTrait<FunctionTextRegion> { typedef MemSpaceRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, const FunctionDecl*) { return MRMgr.getCodeRegion(); } +}; +template<> struct MemRegionManagerTrait<BlockTextRegion> { + typedef MemSpaceRegion SuperRegionTy; static const SuperRegionTy* getSuperRegion(MemRegionManager& MRMgr, - SymbolRef, QualType) { + const BlockDecl*, CanQualType) { return MRMgr.getCodeRegion(); } }; - + } // end clang namespace //===----------------------------------------------------------------------===// diff --git a/include/clang/Analysis/PathSensitive/ValueManager.h b/include/clang/Analysis/PathSensitive/ValueManager.h index 8d162a6..ef4e069 100644 --- a/include/clang/Analysis/PathSensitive/ValueManager.h +++ b/include/clang/Analysis/PathSensitive/ValueManager.h @@ -114,6 +114,9 @@ public: const TypedRegion *R); DefinedSVal getFunctionPointer(const FunctionDecl *FD); + + DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy, + const LocationContext *LC); NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) { return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals)); |