diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index 4aa87443e4c2..d449afcf2161 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -1,4 +1,4 @@ -//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*---// +//==- BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -17,12 +17,26 @@ #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H #include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableList.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Allocator.h" +#include +#include +#include namespace clang { + +class CXXBaseSpecifier; +class DeclaratorDecl; + namespace ento { class CompoundValData : public llvm::FoldingSetNode { @@ -34,7 +48,8 @@ public: assert(NonLoc::isCompoundType(t)); } - typedef llvm::ImmutableList::iterator iterator; + using iterator = llvm::ImmutableList::iterator; + iterator begin() const { return L.begin(); } iterator end() const { return L.end(); } @@ -47,6 +62,7 @@ public: class LazyCompoundValData : public llvm::FoldingSetNode { StoreRef store; const TypedValueRegion *region; + public: LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r) : store(st), region(r) { @@ -63,16 +79,17 @@ public: void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); } }; -class PointerToMemberData: public llvm::FoldingSetNode { +class PointerToMemberData : public llvm::FoldingSetNode { const DeclaratorDecl *D; llvm::ImmutableList L; public: PointerToMemberData(const DeclaratorDecl *D, llvm::ImmutableList L) - : D(D), L(L) {} + : D(D), L(L) {} + + using iterator = llvm::ImmutableList::iterator; - typedef llvm::ImmutableList::iterator iterator; iterator begin() const { return L.begin(); } iterator end() const { return L.end(); } @@ -81,24 +98,25 @@ public: void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, D, L); } const DeclaratorDecl *getDeclaratorDecl() const {return D;} + llvm::ImmutableList getCXXBaseList() const { return L; } }; class BasicValueFactory { - typedef llvm::FoldingSet > - APSIntSetTy; + using APSIntSetTy = + llvm::FoldingSet>; ASTContext &Ctx; llvm::BumpPtrAllocator& BPAlloc; - APSIntSetTy APSIntSet; - void * PersistentSVals; - void * PersistentSValPairs; + APSIntSetTy APSIntSet; + void *PersistentSVals = nullptr; + void *PersistentSValPairs = nullptr; llvm::ImmutableList::Factory SValListFactory; - llvm::ImmutableList::Factory CXXBaseListFactory; + llvm::ImmutableList::Factory CXXBaseListFactory; llvm::FoldingSet CompoundValDataSet; llvm::FoldingSet LazyCompoundValDataSet; llvm::FoldingSet PointerToMemberDataSet; @@ -109,9 +127,8 @@ class BasicValueFactory { public: BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator &Alloc) - : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(nullptr), - PersistentSValPairs(nullptr), SValListFactory(Alloc), - CXXBaseListFactory(Alloc) {} + : Ctx(ctx), BPAlloc(Alloc), SValListFactory(Alloc), + CXXBaseListFactory(Alloc) {} ~BasicValueFactory(); @@ -147,57 +164,57 @@ public: return getValue(TargetType.convert(From)); } - const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) { + const llvm::APSInt &getIntValue(uint64_t X, bool isUnsigned) { QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy; return getValue(X, T); } - inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) { + const llvm::APSInt &getMaxValue(const llvm::APSInt &v) { return getValue(APSIntType(v).getMaxValue()); } - inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) { + const llvm::APSInt &getMinValue(const llvm::APSInt &v) { return getValue(APSIntType(v).getMinValue()); } - inline const llvm::APSInt& getMaxValue(QualType T) { + const llvm::APSInt &getMaxValue(QualType T) { return getValue(getAPSIntType(T).getMaxValue()); } - inline const llvm::APSInt& getMinValue(QualType T) { + const llvm::APSInt &getMinValue(QualType T) { return getValue(getAPSIntType(T).getMinValue()); } - inline const llvm::APSInt& Add1(const llvm::APSInt& V) { + const llvm::APSInt &Add1(const llvm::APSInt &V) { llvm::APSInt X = V; ++X; return getValue(X); } - inline const llvm::APSInt& Sub1(const llvm::APSInt& V) { + const llvm::APSInt &Sub1(const llvm::APSInt &V) { llvm::APSInt X = V; --X; return getValue(X); } - inline const llvm::APSInt& getZeroWithTypeSize(QualType T) { + const llvm::APSInt &getZeroWithTypeSize(QualType T) { assert(T->isScalarType()); return getValue(0, Ctx.getTypeSize(T), true); } - inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { + const llvm::APSInt &getZeroWithPtrWidth(bool isUnsigned = true) { return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); } - inline const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) { + const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) { return getValue(X, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); } - inline const llvm::APSInt& getTruthValue(bool b, QualType T) { + const llvm::APSInt &getTruthValue(bool b, QualType T) { return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false); } - inline const llvm::APSInt& getTruthValue(bool b) { + const llvm::APSInt &getTruthValue(bool b) { return getTruthValue(b, Ctx.getLogicalOperationType()); } @@ -229,7 +246,7 @@ public: return CXXBaseListFactory.add(CBS, L); } - const clang::ento::PointerToMemberData *accumCXXBase( + const PointerToMemberData *accumCXXBase( llvm::iterator_range PathRange, const nonloc::PointerToMember &PTM); @@ -246,8 +263,8 @@ public: const SVal* getPersistentSVal(SVal X); }; -} // end GR namespace +} // namespace ento -} // end clang namespace +} // namespace clang -#endif +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index 2232532e2df1..6d479d6b01aa 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -1,4 +1,4 @@ -//==- CoreEngine.h - Path-Sensitive Dataflow Engine ----------------*- C++ -*-// +//===- CoreEngine.h - Path-Sensitive Dataflow Engine ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,22 +15,33 @@ #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H -#include "clang/AST/Expr.h" +#include "clang/AST/Stmt.h" #include "clang/Analysis/AnalysisDeclContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/ProgramPoint.h" +#include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" -#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" +#include #include +#include +#include namespace clang { -class ProgramPointTag; - +class AnalyzerOptions; +class CXXBindTemporaryExpr; +class Expr; +class LabelDecl; + namespace ento { -class NodeBuilder; +class FunctionSummariesTy; +class SubEngine; //===----------------------------------------------------------------------===// /// CoreEngine - Implements the core logic of the graph-reachability @@ -42,23 +53,23 @@ class NodeBuilder; /// at the statement and block-level. The analyses themselves must implement /// any transfer function logic and the sub-expression level (if any). class CoreEngine { - friend struct NodeBuilderContext; - friend class NodeBuilder; - friend class ExprEngine; friend class CommonNodeBuilder; - friend class IndirectGotoNodeBuilder; - friend class SwitchNodeBuilder; friend class EndOfFunctionNodeBuilder; + friend class ExprEngine; + friend class IndirectGotoNodeBuilder; + friend class NodeBuilder; + friend struct NodeBuilderContext; + friend class SwitchNodeBuilder; + public: - typedef std::vector > - BlocksExhausted; + using BlocksExhausted = + std::vector>; - typedef std::vector > - BlocksAborted; + using BlocksAborted = + std::vector>; private: - - SubEngine& SubEng; + SubEngine &SubEng; /// G - The simulation graph. Each node is a (location,state) pair. mutable ExplodedGraph G; @@ -107,9 +118,6 @@ private: ExplodedNode *Pred); private: - CoreEngine(const CoreEngine &) = delete; - void operator=(const CoreEngine &) = delete; - ExplodedNode *generateCallExitBeginNode(ExplodedNode *N, const ReturnStmt *RS); @@ -119,6 +127,9 @@ public: FunctionSummariesTy *FS, AnalyzerOptions &Opts); + CoreEngine(const CoreEngine &) = delete; + CoreEngine &operator=(const CoreEngine &) = delete; + /// getGraph - Returns the exploded graph. ExplodedGraph &getGraph() { return G; } @@ -126,6 +137,7 @@ public: /// steps. Returns true if there is still simulation state on the worklist. bool ExecuteWorkList(const LocationContext *L, unsigned Steps, ProgramStateRef InitState); + /// Returns true if there is still simulation state on the worklist. bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps, @@ -155,12 +167,15 @@ public: BlocksExhausted::const_iterator blocks_exhausted_begin() const { return blocksExhausted.begin(); } + BlocksExhausted::const_iterator blocks_exhausted_end() const { return blocksExhausted.end(); } + BlocksAborted::const_iterator blocks_aborted_begin() const { return blocksAborted.begin(); } + BlocksAborted::const_iterator blocks_aborted_end() const { return blocksAborted.end(); } @@ -185,8 +200,9 @@ struct NodeBuilderContext { const CoreEngine &Eng; const CFGBlock *Block; const LocationContext *LC; + NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N) - : Eng(E), Block(B), LC(N->getLocationContext()) { assert(B); } + : Eng(E), Block(B), LC(N->getLocationContext()) { assert(B); } /// \brief Return the CFGBlock associated with this builder. const CFGBlock *getBlock() const { return Block; } @@ -211,29 +227,29 @@ struct NodeBuilderContext { /// constructed nodes) but did not have any outgoing transitions added. class NodeBuilder { virtual void anchor(); + protected: const NodeBuilderContext &C; /// Specifies if the builder results have been finalized. For example, if it /// is set to false, autotransitions are yet to be generated. bool Finalized; - bool HasGeneratedNodes; + + bool HasGeneratedNodes = false; + /// \brief The frontier set - a set of nodes which need to be propagated after /// the builder dies. ExplodedNodeSet &Frontier; /// Checkes if the results are ready. virtual bool checkResults() { - if (!Finalized) - return false; - return true; + return Finalized; } bool hasNoSinksInFrontier() { - for (iterator I = Frontier.begin(), E = Frontier.end(); I != E; ++I) { - if ((*I)->isSink()) + for (const auto I : Frontier) + if (I->isSink()) return false; - } return true; } @@ -248,18 +264,18 @@ protected: public: NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, const NodeBuilderContext &Ctx, bool F = true) - : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { + : C(Ctx), Finalized(F), Frontier(DstSet) { Frontier.Add(SrcNode); } NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, const NodeBuilderContext &Ctx, bool F = true) - : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { + : C(Ctx), Finalized(F), Frontier(DstSet) { Frontier.insert(SrcSet); assert(hasNoSinksInFrontier()); } - virtual ~NodeBuilder() {} + virtual ~NodeBuilder() = default; /// \brief Generates a node in the ExplodedGraph. ExplodedNode *generateNode(const ProgramPoint &PP, @@ -285,14 +301,16 @@ public: return Frontier; } - typedef ExplodedNodeSet::iterator iterator; + using iterator = ExplodedNodeSet::iterator; + /// \brief Iterators through the results frontier. - inline iterator begin() { + iterator begin() { finalizeResults(); assert(checkResults()); return Frontier.begin(); } - inline iterator end() { + + iterator end() { finalizeResults(); return Frontier.end(); } @@ -301,9 +319,10 @@ public: bool hasGeneratedNodes() { return HasGeneratedNodes; } void takeNodes(const ExplodedNodeSet &S) { - for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I ) - Frontier.erase(*I); + for (const auto I : S) + Frontier.erase(I); } + void takeNodes(ExplodedNode *N) { Frontier.erase(N); } void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); } void addNodes(ExplodedNode *N) { Frontier.Add(N); } @@ -313,6 +332,7 @@ public: /// \brief This node builder keeps track of the generated sink nodes. class NodeBuilderWithSinks: public NodeBuilder { void anchor() override; + protected: SmallVector sinksGenerated; ProgramPoint &Location; @@ -320,7 +340,7 @@ protected: public: NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet, const NodeBuilderContext &Ctx, ProgramPoint &L) - : NodeBuilder(Pred, DstSet, Ctx), Location(L) {} + : NodeBuilder(Pred, DstSet, Ctx), Location(L) {} ExplodedNode *generateNode(ProgramStateRef State, ExplodedNode *Pred, @@ -349,15 +369,15 @@ public: /// that it creates a statement specific ProgramPoint. class StmtNodeBuilder: public NodeBuilder { NodeBuilder *EnclosingBldr; -public: +public: /// \brief Constructs a StmtNodeBuilder. If the builder is going to process /// nodes currently owned by another builder(with larger scope), use /// Enclosing builder to transfer ownership. StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = nullptr) - : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) { + : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) { if (EnclosingBldr) EnclosingBldr->takeNodes(SrcNode); } @@ -365,11 +385,10 @@ public: StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = nullptr) - : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) { + : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) { if (EnclosingBldr) - for (ExplodedNodeSet::iterator I = SrcSet.begin(), - E = SrcSet.end(); I != E; ++I ) - EnclosingBldr->takeNodes(*I); + for (const auto I : SrcSet) + EnclosingBldr->takeNodes(I); } ~StmtNodeBuilder() override; @@ -401,19 +420,20 @@ public: /// \brief BranchNodeBuilder is responsible for constructing the nodes /// corresponding to the two branches of the if statement - true and false. class BranchNodeBuilder: public NodeBuilder { - void anchor() override; const CFGBlock *DstT; const CFGBlock *DstF; bool InFeasibleTrue; bool InFeasibleFalse; + void anchor() override; + public: BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, const NodeBuilderContext &C, const CFGBlock *dstT, const CFGBlock *dstF) - : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF), - InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { + : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF), + InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { // The branch node builder does not generate autotransitions. // If there are no successors it means that both branches are infeasible. takeNodes(SrcNode); @@ -422,8 +442,8 @@ public: BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, const NodeBuilderContext &C, const CFGBlock *dstT, const CFGBlock *dstF) - : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF), - InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { + : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF), + InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { takeNodes(SrcSet); } @@ -456,15 +476,16 @@ class IndirectGotoNodeBuilder { public: IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src, const Expr *e, const CFGBlock *dispatch, CoreEngine* eng) - : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} + : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} class iterator { + friend class IndirectGotoNodeBuilder; + CFGBlock::const_succ_iterator I; - friend class IndirectGotoNodeBuilder; iterator(CFGBlock::const_succ_iterator i) : I(i) {} - public: + public: iterator &operator++() { ++I; return *this; } bool operator!=(const iterator &X) const { return I != X.I; } @@ -502,12 +523,13 @@ class SwitchNodeBuilder { public: SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src, const Expr *condition, CoreEngine* eng) - : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} + : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} class iterator { + friend class SwitchNodeBuilder; + CFGBlock::const_succ_reverse_iterator I; - friend class SwitchNodeBuilder; iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {} public: @@ -546,7 +568,8 @@ public: } }; -} // end ento namespace -} // end clang namespace +} // namespace ento -#endif +} // namespace clang + +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 25d20a17afaa..84afb08708c3 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -1,4 +1,4 @@ -//== Store.h - Interface for maps from Locations to Values ------*- C++ -*--==// +//===- Store.h - Interface for maps from Locations to Values ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,27 +14,42 @@ #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H +#include "clang/AST/Type.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include +#include +#include namespace clang { -class Stmt; -class Expr; -class ObjCIvarDecl; +class ASTContext; +class CastExpr; +class CompoundLiteralExpr; class CXXBasePath; +class Decl; +class Expr; +class LocationContext; +class ObjCIvarDecl; class StackFrameContext; namespace ento { class CallEvent; -class ProgramState; class ProgramStateManager; class ScanReachableSymbols; +class SymbolReaper; -typedef llvm::DenseSet InvalidatedSymbols; +using InvalidatedSymbols = llvm::DenseSet; class StoreManager { protected: @@ -48,7 +63,7 @@ protected: StoreManager(ProgramStateManager &stateMgr); public: - virtual ~StoreManager() {} + virtual ~StoreManager() = default; /// Return the value bound to specified location in a given state. /// \param[in] store The store in which to make the lookup. @@ -168,7 +183,7 @@ public: const MemRegion *castRegion(const MemRegion *region, QualType CastToTy); virtual StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx, - SymbolReaper& SymReaper) = 0; + SymbolReaper &SymReaper) = 0; virtual bool includedInBindings(Store store, const MemRegion *region) const = 0; @@ -182,7 +197,7 @@ public: /// associated with the object is recycled. virtual void decrementReferenceCount(Store store) {} - typedef SmallVector InvalidatedRegions; + using InvalidatedRegions = SmallVector; /// invalidateRegions - Clears out the specified regions from the store, /// marking their values as unknown. Depending on the store, this may also @@ -235,6 +250,7 @@ public: class BindingsHandler { public: virtual ~BindingsHandler(); + virtual bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion *region, SVal val) = 0; }; @@ -242,16 +258,16 @@ public: class FindUniqueBinding : public BindingsHandler { SymbolRef Sym; - const MemRegion* Binding; - bool First; + const MemRegion* Binding = nullptr; + bool First = true; public: - FindUniqueBinding(SymbolRef sym) - : Sym(sym), Binding(nullptr), First(true) {} + FindUniqueBinding(SymbolRef sym) : Sym(sym) {} + + explicit operator bool() { return First && Binding; } bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, SVal val) override; - explicit operator bool() { return First && Binding; } const MemRegion *getRegion() { return Binding; } }; @@ -273,15 +289,14 @@ private: SVal getLValueFieldOrIvar(const Decl *decl, SVal base); }; - inline StoreRef::StoreRef(Store store, StoreManager & smgr) - : store(store), mgr(smgr) { + : store(store), mgr(smgr) { if (store) mgr.incrementReferenceCount(store); } -inline StoreRef::StoreRef(const StoreRef &sr) - : store(sr.store), mgr(sr.mgr) +inline StoreRef::StoreRef(const StoreRef &sr) + : store(sr.store), mgr(sr.mgr) { if (store) mgr.incrementReferenceCount(store); @@ -308,8 +323,8 @@ CreateRegionStoreManager(ProgramStateManager &StMgr); std::unique_ptr CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr); -} // end GR namespace +} // namespace ento -} // end clang namespace +} // namespace clang -#endif +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h index 958c8c377ea2..c5b4e5036bdf 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h @@ -1,4 +1,4 @@ -//== StoreRef.h - Smart pointer for store objects ---------------*- C++ -*--==// +//===- StoreRef.h - Smart pointer for store objects -------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -19,33 +19,36 @@ namespace clang { namespace ento { +class StoreManager; + /// Store - This opaque type encapsulates an immutable mapping from /// locations to values. At a high-level, it represents the symbolic /// memory model. Different subclasses of StoreManager may choose /// different types to represent the locations and values. -typedef const void *Store; - -class StoreManager; +using Store = const void *; class StoreRef { Store store; StoreManager &mgr; + public: - StoreRef(Store, StoreManager &); - StoreRef(const StoreRef &); - StoreRef &operator=(StoreRef const &); + StoreRef(Store store, StoreManager &smgr); + StoreRef(const StoreRef &sr); + StoreRef &operator=(StoreRef const &newStore); + ~StoreRef(); bool operator==(const StoreRef &x) const { assert(&mgr == &x.mgr); return x.store == store; } + bool operator!=(const StoreRef &x) const { return !operator==(x); } - ~StoreRef(); - Store getStore() const { return store; } const StoreManager &getStoreManager() const { return mgr; } }; -}} -#endif +} // namespace ento +} // namespace clang + +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STOREREF_H diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h index 9780d0144746..85551f936078 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h @@ -1,4 +1,4 @@ -//== SymExpr.h - Management of Symbolic Values ------------------*- C++ -*--==// +//===- SymExpr.h - Management of Symbolic Values ----------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,9 +15,10 @@ #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMEXPR_H #include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/raw_ostream.h" +#include namespace clang { namespace ento { @@ -49,7 +50,7 @@ protected: } public: - virtual ~SymExpr() {} + virtual ~SymExpr() = default; Kind getKind() const { return K; } @@ -67,10 +68,11 @@ public: /// treated as SymbolData - the iterator will NOT visit the parent region. class symbol_iterator { SmallVector itr; + void expand(); public: - symbol_iterator() {} + symbol_iterator() = default; symbol_iterator(const SymExpr *SE); symbol_iterator &operator++(); @@ -104,23 +106,24 @@ inline raw_ostream &operator<<(raw_ostream &os, return os; } -typedef const SymExpr *SymbolRef; -typedef SmallVector SymbolRefSmallVectorTy; +using SymbolRef = const SymExpr *; +using SymbolRefSmallVectorTy = SmallVector; +using SymbolID = unsigned; -typedef unsigned SymbolID; /// \brief A symbol representing data which can be stored in a memory location /// (region). class SymbolData : public SymExpr { - void anchor() override; const SymbolID Sym; + void anchor() override; + protected: SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) { assert(classof(this)); } public: - ~SymbolData() override {} + ~SymbolData() override = default; SymbolID getSymbolID() const { return Sym; } @@ -134,4 +137,4 @@ public: } // namespace ento } // namespace clang -#endif +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMEXPR_H diff --git a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp index 11658816ed25..db4c1432ccc3 100644 --- a/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -1,4 +1,4 @@ -//=== BasicValueFactory.cpp - Basic values for Path Sens analysis --*- C++ -*-// +//===- BasicValueFactory.cpp - Basic values for Path Sens analysis --------===// // // The LLVM Compiler Infrastructure // @@ -13,9 +13,18 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/ASTContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableList.h" +#include "llvm/ADT/STLExtras.h" +#include +#include +#include using namespace clang; using namespace ento; @@ -40,10 +49,11 @@ void PointerToMemberData::Profile( ID.AddPointer(L.getInternalPointer()); } -typedef std::pair SValData; -typedef std::pair SValPair; +using SValData = std::pair; +using SValPair = std::pair; namespace llvm { + template<> struct FoldingSetTrait { static inline void Profile(const SValData& X, llvm::FoldingSetNodeID& ID) { X.first.Profile(ID); @@ -57,20 +67,21 @@ template<> struct FoldingSetTrait { X.second.Profile(ID); } }; -} -typedef llvm::FoldingSet > - PersistentSValsTy; +} // namespace llvm -typedef llvm::FoldingSet > - PersistentSValPairsTy; +using PersistentSValsTy = + llvm::FoldingSet>; + +using PersistentSValPairsTy = + llvm::FoldingSet>; BasicValueFactory::~BasicValueFactory() { // Note that the dstor for the contents of APSIntSet will never be called, // so we iterate over the set and invoke the dstor for each APSInt. This // frees an aux. memory allocated to represent very large constants. - for (APSIntSetTy::iterator I=APSIntSet.begin(), E=APSIntSet.end(); I!=E; ++I) - I->getValue().~APSInt(); + for (const auto &I : APSIntSet) + I.getValue().~APSInt(); delete (PersistentSValsTy*) PersistentSVals; delete (PersistentSValPairsTy*) PersistentSValPairs; @@ -79,7 +90,8 @@ BasicValueFactory::~BasicValueFactory() { const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) { llvm::FoldingSetNodeID ID; void *InsertPos; - typedef llvm::FoldingSetNodeWrapper FoldNodeTy; + + using FoldNodeTy = llvm::FoldingSetNodeWrapper; X.Profile(ID); FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos); @@ -107,14 +119,12 @@ const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth, } const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) { - return getValue(getAPSIntType(T).getValue(X)); } const CompoundValData* BasicValueFactory::getCompoundValData(QualType T, llvm::ImmutableList Vals) { - llvm::FoldingSetNodeID ID; CompoundValData::Profile(ID, T, Vals); void *InsertPos; @@ -150,7 +160,7 @@ BasicValueFactory::getLazyCompoundValData(const StoreRef &store, } const PointerToMemberData *BasicValueFactory::getPointerToMemberData( - const DeclaratorDecl *DD, llvm::ImmutableList L) { + const DeclaratorDecl *DD, llvm::ImmutableList L) { llvm::FoldingSetNodeID ID; PointerToMemberData::Profile(ID, DD, L); void *InsertPos; @@ -167,7 +177,7 @@ const PointerToMemberData *BasicValueFactory::getPointerToMemberData( return D; } -const clang::ento::PointerToMemberData *BasicValueFactory::accumCXXBase( +const PointerToMemberData *BasicValueFactory::accumCXXBase( llvm::iterator_range PathRange, const nonloc::PointerToMember &PTM) { nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData(); @@ -195,10 +205,9 @@ const clang::ento::PointerToMemberData *BasicValueFactory::accumCXXBase( const llvm::APSInt* BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt& V1, const llvm::APSInt& V2) { - switch (Op) { default: - assert (false && "Invalid Opcode."); + assert(false && "Invalid Opcode."); case BO_Mul: return &getValue( V1 * V2 ); @@ -220,7 +229,6 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, return &getValue( V1 - V2 ); case BO_Shl: { - // FIXME: This logic should probably go higher up, where we can // test these conditions symbolically. @@ -242,7 +250,6 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, } case BO_Shr: { - // FIXME: This logic should probably go higher up, where we can // test these conditions symbolically. @@ -288,10 +295,8 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op, } } - const std::pair& BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) { - // Lazily create the folding set. if (!PersistentSVals) PersistentSVals = new PersistentSValsTy(); @@ -302,7 +307,8 @@ BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) { PersistentSValsTy& Map = *((PersistentSValsTy*) PersistentSVals); - typedef llvm::FoldingSetNodeWrapper FoldNodeTy; + using FoldNodeTy = llvm::FoldingSetNodeWrapper; + FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); if (!P) { @@ -316,7 +322,6 @@ BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) { const std::pair& BasicValueFactory::getPersistentSValPair(const SVal& V1, const SVal& V2) { - // Lazily create the folding set. if (!PersistentSValPairs) PersistentSValPairs = new PersistentSValPairsTy(); @@ -327,7 +332,8 @@ BasicValueFactory::getPersistentSValPair(const SVal& V1, const SVal& V2) { PersistentSValPairsTy& Map = *((PersistentSValPairsTy*) PersistentSValPairs); - typedef llvm::FoldingSetNodeWrapper FoldNodeTy; + using FoldNodeTy = llvm::FoldingSetNodeWrapper; + FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos); if (!P) { diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index efc83c37601b..592f0ba621ea 100644 --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -1,4 +1,4 @@ -//==- CoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- C++ -*-// +//===- CoreEngine.cpp - Path-Sensitive Dataflow Engine --------------------===// // // The LLVM Compiler Infrastructure // @@ -15,14 +15,33 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "llvm/ADT/Statistic.h" +#include "clang/Analysis/AnalysisDeclContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/ProgramPoint.h" +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/Support/Casting.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/PriorityQueue.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include +#include +#include +#include +#include using namespace clang; using namespace ento; @@ -44,8 +63,10 @@ STATISTIC(MaxReachableSize, "Maximum size of auxiliary worklist set"); //===----------------------------------------------------------------------===// namespace { + class DFS : public WorkList { - SmallVector Stack; + SmallVector Stack; + public: bool hasWork() const override { return !Stack.empty(); @@ -56,7 +77,7 @@ public: } WorkListUnit dequeue() override { - assert (!Stack.empty()); + assert(!Stack.empty()); const WorkListUnit& U = Stack.back(); Stack.pop_back(); // This technically "invalidates" U, but we are fine. return U; @@ -65,6 +86,7 @@ public: class BFS : public WorkList { std::deque Queue; + public: bool hasWork() const override { return !Queue.empty(); @@ -79,14 +101,13 @@ public: Queue.pop_front(); return U; } - }; -} // end anonymous namespace +} // namespace // Place the dstor for WorkList here because it contains virtual member // functions, and we the code for the dstor generated in one compilation unit. -WorkList::~WorkList() {} +WorkList::~WorkList() = default; std::unique_ptr WorkList::makeDFS() { return llvm::make_unique(); @@ -97,9 +118,11 @@ std::unique_ptr WorkList::makeBFS() { } namespace { + class BFSBlockDFSContents : public WorkList { std::deque Queue; - SmallVector Stack; + SmallVector Stack; + public: bool hasWork() const override { return !Queue.empty() || !Stack.empty(); @@ -128,23 +151,25 @@ namespace { return U; } }; -} // end anonymous namespace + +} // namespace std::unique_ptr WorkList::makeBFSBlockDFSContents() { return llvm::make_unique(); } namespace { -class UnexploredFirstStack : public WorkList { +class UnexploredFirstStack : public WorkList { /// Stack of nodes known to have statements we have not traversed yet. SmallVector StackUnexplored; /// Stack of all other nodes. SmallVector StackOthers; - typedef unsigned BlockID; - typedef std::pair LocIdentifier; + using BlockID = unsigned; + using LocIdentifier = std::pair; + llvm::DenseSet Reachable; public: @@ -157,7 +182,6 @@ public: auto BE = N->getLocation().getAs(); if (!BE) { - // Assume the choice of the order of the preceeding block entrance was // correct. StackUnexplored.push_back(U); @@ -188,26 +212,27 @@ public: } } }; -} // end anonymous namespace + +} // namespace std::unique_ptr WorkList::makeUnexploredFirst() { return llvm::make_unique(); } class UnexploredFirstPriorityQueue : public WorkList { - typedef unsigned BlockID; - typedef std::pair LocIdentifier; + using BlockID = unsigned; + using LocIdentifier = std::pair; // How many times each location was visited. // Is signed because we negate it later in order to have a reversed // comparison. - typedef llvm::DenseMap VisitedTimesMap; + using VisitedTimesMap = llvm::DenseMap; // Compare by number of times the location was visited first (negated // to prefer less often visited locations), then by insertion time (prefer // expanding nodes inserted sooner first). - typedef std::pair QueuePriority; - typedef std::pair QueueItem; + using QueuePriority = std::pair; + using QueueItem = std::pair; struct ExplorationComparator { bool operator() (const QueueItem &LHS, const QueueItem &RHS) { @@ -275,27 +300,22 @@ static std::unique_ptr generateWorkList(AnalyzerOptions &Opts) { } } -CoreEngine::CoreEngine(SubEngine &subengine, - FunctionSummariesTy *FS, - AnalyzerOptions &Opts) : SubEng(subengine), - WList(generateWorkList(Opts)), - BCounterFactory(G.getAllocator()), - FunctionSummaries(FS) {} +CoreEngine::CoreEngine(SubEngine &subengine, FunctionSummariesTy *FS, + AnalyzerOptions &Opts) + : SubEng(subengine), WList(generateWorkList(Opts)), + BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {} /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, ProgramStateRef InitState) { - if (G.num_roots() == 0) { // Initialize the analysis by constructing // the root if none exists. const CFGBlock *Entry = &(L->getCFG()->getEntry()); - assert (Entry->empty() && - "Entry block must be empty."); + assert(Entry->empty() && "Entry block must be empty."); - assert (Entry->succ_size() == 1 && - "Entry block must have 1 successor."); + assert(Entry->succ_size() == 1 && "Entry block must have 1 successor."); // Mark the entry block as visited. FunctionSummaries->markVisitedBasicBlock(Entry->getBlockID(), @@ -317,7 +337,7 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, bool IsNew; ExplodedNode *Node = G.getNode(StartLoc, InitState, false, &IsNew); - assert (IsNew); + assert(IsNew); G.addRoot(Node); NodeBuilderContext BuilderCtx(*this, StartLoc.getDst(), Node); @@ -373,13 +393,12 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, break; case ProgramPoint::BlockExitKind: - assert (false && "BlockExit location never occur in forward analysis."); + assert(false && "BlockExit location never occur in forward analysis."); break; - case ProgramPoint::CallEnterKind: { + case ProgramPoint::CallEnterKind: HandleCallEnter(Loc.castAs(), Pred); break; - } case ProgramPoint::CallExitBeginKind: SubEng.processCallExit(Pred); @@ -417,7 +436,6 @@ bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L, } void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { - const CFGBlock *Blk = L.getDst(); NodeBuilderContext BuilderCtx(*this, Blk, Pred); @@ -429,9 +447,8 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { // Check if we are entering the EXIT block. if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { - - assert (L.getLocationContext()->getCFG()->getExit().size() == 0 - && "EXIT block cannot contain Stmts."); + assert(L.getLocationContext()->getCFG()->getExit().empty() && + "EXIT block cannot contain Stmts."); // Get return statement.. const ReturnStmt *RS = nullptr; @@ -465,7 +482,6 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { void CoreEngine::HandleBlockEntrance(const BlockEntrance &L, ExplodedNode *Pred) { - // Increment the block counter. const LocationContext *LC = Pred->getLocationContext(); unsigned BlockId = L.getBlock()->getBlockID(); @@ -484,7 +500,6 @@ void CoreEngine::HandleBlockEntrance(const BlockEntrance &L, } void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { - if (const Stmt *Term = B->getTerminator()) { switch (Term->getStmtClass()) { default: @@ -517,7 +532,7 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { HandleBranch(cast(Term)->getCond(), Term, B, Pred); return; - case Stmt::CXXTryStmtClass: { + case Stmt::CXXTryStmtClass: // Generate a node for each of the successors. // Our logic for EH analysis can certainly be improved. for (CFGBlock::const_succ_iterator it = B->succ_begin(), @@ -528,7 +543,6 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { } } return; - } case Stmt::DoStmtClass: HandleBranch(cast(Term)->getCond(), Term, B, Pred); @@ -553,7 +567,7 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { case Stmt::IndirectGotoStmtClass: { // Only 1 successor: the indirect goto dispatch block. - assert (B->succ_size() == 1); + assert(B->succ_size() == 1); IndirectGotoNodeBuilder builder(Pred, B, cast(Term)->getTarget(), @@ -563,7 +577,7 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { return; } - case Stmt::ObjCForCollectionStmtClass: { + case Stmt::ObjCForCollectionStmtClass: // In the case of ObjCForCollectionStmt, it appears twice in a CFG: // // (1) inside a basic block, which represents the binding of the @@ -576,7 +590,6 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { // contain nil elements. HandleBranch(Term, Term, B, Pred); return; - } case Stmt::SwitchStmtClass: { SwitchNodeBuilder builder(Pred, B, cast(Term)->getCond(), @@ -592,8 +605,8 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { } } - assert (B->succ_size() == 1 && - "Blocks with no terminator should have at most 1 successor."); + assert(B->succ_size() == 1 && + "Blocks with no terminator should have at most 1 successor."); generateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()), Pred->State, Pred); @@ -638,9 +651,8 @@ void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B, enqueue(Dst); } - void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, - ExplodedNode *Pred) { + ExplodedNode *Pred) { assert(B); assert(!B->empty()); @@ -657,14 +669,13 @@ void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, void CoreEngine::generateNode(const ProgramPoint &Loc, ProgramStateRef State, ExplodedNode *Pred) { - bool IsNew; ExplodedNode *Node = G.getNode(Loc, State, false, &IsNew); if (Pred) Node->addPredecessor(Pred, G); // Link 'Node' with its predecessor. else { - assert (IsNew); + assert(IsNew); G.addRoot(Node); // 'Node' has no predecessor. Make it a root. } @@ -675,7 +686,7 @@ void CoreEngine::generateNode(const ProgramPoint &Loc, void CoreEngine::enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx) { assert(Block); - assert (!N->isSink()); + assert(!N->isSink()); // Check if this node entered a callee. if (N->getLocation().getAs()) { @@ -725,8 +736,7 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N, ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N, const ReturnStmt *RS) { // Create a CallExitBegin node and enqueue it. - const StackFrameContext *LocCtx - = cast(N->getLocationContext()); + const auto *LocCtx = cast(N->getLocationContext()); // Use the callee location context. CallExitBegin Loc(LocCtx, RS); @@ -737,40 +747,33 @@ ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N, return isNew ? Node : nullptr; } - void CoreEngine::enqueue(ExplodedNodeSet &Set) { - for (ExplodedNodeSet::iterator I = Set.begin(), - E = Set.end(); I != E; ++I) { - WList->enqueue(*I); - } + for (const auto I : Set) + WList->enqueue(I); } void CoreEngine::enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx) { - for (ExplodedNodeSet::iterator I = Set.begin(), - E = Set.end(); I != E; ++I) { - enqueueStmtNode(*I, Block, Idx); - } + for (const auto I : Set) + enqueueStmtNode(I, Block, Idx); } void CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS) { - for (ExplodedNodeSet::iterator I = Set.begin(), E = Set.end(); I != E; ++I) { - ExplodedNode *N = *I; + for (auto I : Set) { // If we are in an inlined call, generate CallExitBegin node. - if (N->getLocationContext()->getParent()) { - N = generateCallExitBeginNode(N, RS); - if (N) - WList->enqueue(N); + if (I->getLocationContext()->getParent()) { + I = generateCallExitBeginNode(I, RS); + if (I) + WList->enqueue(I); } else { // TODO: We should run remove dead bindings here. - G.addEndOfPath(N); + G.addEndOfPath(I); NumPathsExplored++; } } } - -void NodeBuilder::anchor() { } +void NodeBuilder::anchor() {} ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc, ProgramStateRef State, @@ -791,16 +794,15 @@ ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc, return N; } -void NodeBuilderWithSinks::anchor() { } +void NodeBuilderWithSinks::anchor() {} StmtNodeBuilder::~StmtNodeBuilder() { if (EnclosingBldr) - for (ExplodedNodeSet::iterator I = Frontier.begin(), - E = Frontier.end(); I != E; ++I ) - EnclosingBldr->addNodes(*I); + for (const auto I : Frontier) + EnclosingBldr->addNodes(I); } -void BranchNodeBuilder::anchor() { } +void BranchNodeBuilder::anchor() {} ExplodedNode *BranchNodeBuilder::generateNode(ProgramStateRef State, bool branch, @@ -834,11 +836,9 @@ IndirectGotoNodeBuilder::generateNode(const iterator &I, return Succ; } - ExplodedNode* SwitchNodeBuilder::generateCaseStmtNode(const iterator &I, ProgramStateRef St) { - bool IsNew; ExplodedNode *Succ = Eng.G.getNode(BlockEdge(Src, I.getBlock(), Pred->getLocationContext()), @@ -851,7 +851,6 @@ SwitchNodeBuilder::generateCaseStmtNode(const iterator &I, return Succ; } - ExplodedNode* SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St, bool IsSink) { diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp index 173fdd8d0056..212dc593899d 100644 --- a/clang/lib/StaticAnalyzer/Core/Store.cpp +++ b/clang/lib/StaticAnalyzer/Core/Store.cpp @@ -1,4 +1,4 @@ -//== Store.cpp - Interface for maps from Locations to Values ----*- C++ -*--==// +//===- Store.cpp - Interface for maps from Locations to Values ------------===// // // The LLVM Compiler Infrastructure // @@ -12,18 +12,37 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include using namespace clang; using namespace ento; StoreManager::StoreManager(ProgramStateManager &stateMgr) - : svalBuilder(stateMgr.getSValBuilder()), StateMgr(stateMgr), - MRMgr(svalBuilder.getRegionManager()), Ctx(stateMgr.getContext()) {} + : svalBuilder(stateMgr.getSValBuilder()), StateMgr(stateMgr), + MRMgr(svalBuilder.getRegionManager()), Ctx(stateMgr.getContext()) {} StoreRef StoreManager::enterStackFrame(Store OldStore, const CallEvent &Call, @@ -33,11 +52,8 @@ StoreRef StoreManager::enterStackFrame(Store OldStore, SmallVector InitialBindings; Call.getInitialStackFrameContents(LCtx, InitialBindings); - for (CallEvent::BindingsTy::iterator I = InitialBindings.begin(), - E = InitialBindings.end(); - I != E; ++I) { - Store = Bind(Store.getStore(), I->first, I->second); - } + for (const auto &I : InitialBindings) + Store = Bind(Store.getStore(), I.first, I.second); return Store; } @@ -61,7 +77,6 @@ const ElementRegion *StoreManager::GetElementZeroRegion(const SubRegion *R, } const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) { - ASTContext &Ctx = StateMgr.getContext(); // Handle casts to Objective-C objects. @@ -92,7 +107,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) // Handle casts from compatible types. if (R->isBoundable()) - if (const TypedValueRegion *TR = dyn_cast(R)) { + if (const auto *TR = dyn_cast(R)) { QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); if (CanonPointeeTy == ObjTy) return R; @@ -164,7 +179,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy) // Edge case: we are at 0 bytes off the beginning of baseR. We // check to see if type we are casting to is the same as the base // region. If so, just return the base region. - if (const TypedValueRegion *TR = dyn_cast(baseR)) { + if (const auto *TR = dyn_cast(baseR)) { QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); if (CanonPointeeTy == ObjTy) @@ -219,7 +234,7 @@ static bool regionMatchesCXXRecordType(SVal V, QualType Ty) { if (!MR) return true; - const TypedValueRegion *TVR = dyn_cast(MR); + const auto *TVR = dyn_cast(MR); if (!TVR) return true; @@ -253,11 +268,9 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) { SVal StoreManager::evalDerivedToBase(SVal Derived, const CXXBasePath &Path) { // Walk through the path to create nested CXXBaseRegions. SVal Result = Derived; - for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end(); - I != E; ++I) { - Result = evalDerivedToBase(Result, I->Base->getType(), - I->Base->isVirtual()); - } + for (const auto &I : Path) + Result = evalDerivedToBase(Result, I.Base->getType(), + I.Base->isVirtual()); return Result; } @@ -286,9 +299,9 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType, /// symbolic regions, where the dynamic type is merely bounded (and even then, /// only ostensibly!), but does not take advantage of any dynamic type info. static const CXXRecordDecl *getCXXRecordType(const MemRegion *MR) { - if (const TypedValueRegion *TVR = dyn_cast(MR)) + if (const auto *TVR = dyn_cast(MR)) return TVR->getValueType()->getAsCXXRecordDecl(); - if (const SymbolicRegion *SR = dyn_cast(MR)) + if (const auto *SR = dyn_cast(MR)) return SR->getSymbol()->getType()->getPointeeCXXRecordDecl(); return nullptr; } @@ -327,7 +340,7 @@ SVal StoreManager::attemptDownCast(SVal Base, QualType TargetType, return evalDerivedToBase(loc::MemRegionVal(MR), Paths.front()); } - if (const CXXBaseObjectRegion *BaseR = dyn_cast(MR)) { + if (const auto *BaseR = dyn_cast(MR)) { // Drill down the chain to get the derived classes. MR = BaseR->getSuperRegion(); continue; @@ -361,13 +374,11 @@ SVal StoreManager::attemptDownCast(SVal Base, QualType TargetType, return UnknownVal(); } - /// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted /// as another region. SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R, QualType castTy, bool performTestOnly) { - if (castTy.isNull() || V.isUnknownOrUndef()) return V; @@ -421,7 +432,7 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) { // NOTE: We must have this check first because ObjCIvarDecl is a subclass // of FieldDecl. - if (const ObjCIvarDecl *ID = dyn_cast(D)) + if (const auto *ID = dyn_cast(D)) return loc::MemRegionVal(MRMgr.getObjCIvarRegion(ID, BaseR)); return loc::MemRegionVal(MRMgr.getFieldRegion(cast(D), BaseR)); @@ -433,7 +444,6 @@ SVal StoreManager::getLValueIvar(const ObjCIvarDecl *decl, SVal base) { SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset, SVal Base) { - // If the base is an unknown or undefined value, just return it back. // FIXME: For absolute pointer addresses, we just return that value back as // well, although in reality we should return the offset added to that @@ -448,13 +458,12 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset, Base.castAs().getRegionAs(); // Pointer of any type can be cast and used as array base. - const ElementRegion *ElemR = dyn_cast(BaseRegion); + const auto *ElemR = dyn_cast(BaseRegion); // Convert the offset to the appropriate size and signedness. Offset = svalBuilder.convertToArrayIndex(Offset).castAs(); if (!ElemR) { - // // If the base region is not an ElementRegion, create one. // This can happen in the following example: // @@ -462,7 +471,6 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset, // p[1] = 8; // // Observe that 'p' binds to an AllocaRegion. - // return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset, BaseRegion, Ctx)); } @@ -499,7 +507,7 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset, Ctx)); } -StoreManager::BindingsHandler::~BindingsHandler() {} +StoreManager::BindingsHandler::~BindingsHandler() = default; bool StoreManager::FindUniqueBinding::HandleBinding(StoreManager& SMgr, Store store,