[StaticAnalyzer] Fix some Clang-tidy modernize and Include What You Use warnings; other minor fixes (NFC).

llvm-svn: 326633
This commit is contained in:
Eugene Zelenko 2018-03-02 23:11:49 +00:00
parent e29375d04c
commit e029a2ff23
8 changed files with 339 additions and 265 deletions

View File

@ -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 <cassert>
#include <cstdint>
#include <utility>
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<SVal>::iterator iterator;
using iterator = llvm::ImmutableList<SVal>::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<const CXXBaseSpecifier *> L;
public:
PointerToMemberData(const DeclaratorDecl *D,
llvm::ImmutableList<const CXXBaseSpecifier *> L)
: D(D), L(L) {}
: D(D), L(L) {}
using iterator = llvm::ImmutableList<const CXXBaseSpecifier *>::iterator;
typedef llvm::ImmutableList<const CXXBaseSpecifier *>::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<const CXXBaseSpecifier *> getCXXBaseList() const {
return L;
}
};
class BasicValueFactory {
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
APSIntSetTy;
using APSIntSetTy =
llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt>>;
ASTContext &Ctx;
llvm::BumpPtrAllocator& BPAlloc;
APSIntSetTy APSIntSet;
void * PersistentSVals;
void * PersistentSValPairs;
APSIntSetTy APSIntSet;
void *PersistentSVals = nullptr;
void *PersistentSValPairs = nullptr;
llvm::ImmutableList<SVal>::Factory SValListFactory;
llvm::ImmutableList<const CXXBaseSpecifier*>::Factory CXXBaseListFactory;
llvm::ImmutableList<const CXXBaseSpecifier *>::Factory CXXBaseListFactory;
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
llvm::FoldingSet<PointerToMemberData> 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<CastExpr::path_const_iterator> 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

View File

@ -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 <cassert>
#include <memory>
#include <utility>
#include <vector>
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<std::pair<BlockEdge, const ExplodedNode*> >
BlocksExhausted;
using BlocksExhausted =
std::vector<std::pair<BlockEdge, const ExplodedNode *>>;
typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> >
BlocksAborted;
using BlocksAborted =
std::vector<std::pair<const CFGBlock *, const ExplodedNode *>>;
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<ExplodedNode*, 2> 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

View File

@ -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 <cassert>
#include <cstdint>
#include <memory>
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<SymbolRef> InvalidatedSymbols;
using InvalidatedSymbols = llvm::DenseSet<SymbolRef>;
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<const MemRegion *, 8> InvalidatedRegions;
using InvalidatedRegions = SmallVector<const MemRegion *, 8>;
/// 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<StoreManager>
CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr);
} // end GR namespace
} // namespace ento
} // end clang namespace
} // namespace clang
#endif
#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H

View File

@ -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

View File

@ -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 <cassert>
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<const SymExpr *, 5> 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<SymbolRef, 2> SymbolRefSmallVectorTy;
using SymbolRef = const SymExpr *;
using SymbolRefSmallVectorTy = SmallVector<SymbolRef, 2>;
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

View File

@ -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 <cassert>
#include <cstdint>
#include <utility>
using namespace clang;
using namespace ento;
@ -40,10 +49,11 @@ void PointerToMemberData::Profile(
ID.AddPointer(L.getInternalPointer());
}
typedef std::pair<SVal, uintptr_t> SValData;
typedef std::pair<SVal, SVal> SValPair;
using SValData = std::pair<SVal, uintptr_t>;
using SValPair = std::pair<SVal, SVal>;
namespace llvm {
template<> struct FoldingSetTrait<SValData> {
static inline void Profile(const SValData& X, llvm::FoldingSetNodeID& ID) {
X.first.Profile(ID);
@ -57,20 +67,21 @@ template<> struct FoldingSetTrait<SValPair> {
X.second.Profile(ID);
}
};
}
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<SValData> >
PersistentSValsTy;
} // namespace llvm
typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<SValPair> >
PersistentSValPairsTy;
using PersistentSValsTy =
llvm::FoldingSet<llvm::FoldingSetNodeWrapper<SValData>>;
using PersistentSValPairsTy =
llvm::FoldingSet<llvm::FoldingSetNodeWrapper<SValPair>>;
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<llvm::APSInt> FoldNodeTy;
using FoldNodeTy = llvm::FoldingSetNodeWrapper<llvm::APSInt>;
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<SVal> 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<const CXXBaseSpecifier*> L) {
const DeclaratorDecl *DD, llvm::ImmutableList<const CXXBaseSpecifier *> 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<CastExpr::path_const_iterator> 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<SVal, uintptr_t>&
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<SValData> FoldNodeTy;
using FoldNodeTy = llvm::FoldingSetNodeWrapper<SValData>;
FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos);
if (!P) {
@ -316,7 +322,6 @@ BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) {
const std::pair<SVal, SVal>&
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<SValPair> FoldNodeTy;
using FoldNodeTy = llvm::FoldingSetNodeWrapper<SValPair>;
FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos);
if (!P) {

View File

@ -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 <algorithm>
#include <cassert>
#include <deque>
#include <memory>
#include <utility>
#include <vector>
using namespace clang;
using namespace ento;
@ -44,8 +63,10 @@ STATISTIC(MaxReachableSize, "Maximum size of auxiliary worklist set");
//===----------------------------------------------------------------------===//
namespace {
class DFS : public WorkList {
SmallVector<WorkListUnit,20> Stack;
SmallVector<WorkListUnit, 20> 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<WorkListUnit> 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> WorkList::makeDFS() {
return llvm::make_unique<DFS>();
@ -97,9 +118,11 @@ std::unique_ptr<WorkList> WorkList::makeBFS() {
}
namespace {
class BFSBlockDFSContents : public WorkList {
std::deque<WorkListUnit> Queue;
SmallVector<WorkListUnit,20> Stack;
SmallVector<WorkListUnit, 20> 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> WorkList::makeBFSBlockDFSContents() {
return llvm::make_unique<BFSBlockDFSContents>();
}
namespace {
class UnexploredFirstStack : public WorkList {
class UnexploredFirstStack : public WorkList {
/// Stack of nodes known to have statements we have not traversed yet.
SmallVector<WorkListUnit, 20> StackUnexplored;
/// Stack of all other nodes.
SmallVector<WorkListUnit, 20> StackOthers;
typedef unsigned BlockID;
typedef std::pair<BlockID, const StackFrameContext *> LocIdentifier;
using BlockID = unsigned;
using LocIdentifier = std::pair<BlockID, const StackFrameContext *>;
llvm::DenseSet<LocIdentifier> Reachable;
public:
@ -157,7 +182,6 @@ public:
auto BE = N->getLocation().getAs<BlockEntrance>();
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> WorkList::makeUnexploredFirst() {
return llvm::make_unique<UnexploredFirstStack>();
}
class UnexploredFirstPriorityQueue : public WorkList {
typedef unsigned BlockID;
typedef std::pair<BlockID, const StackFrameContext *> LocIdentifier;
using BlockID = unsigned;
using LocIdentifier = std::pair<BlockID, const StackFrameContext *>;
// How many times each location was visited.
// Is signed because we negate it later in order to have a reversed
// comparison.
typedef llvm::DenseMap<LocIdentifier, int> VisitedTimesMap;
using VisitedTimesMap = llvm::DenseMap<LocIdentifier, int>;
// 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<int, unsigned long> QueuePriority;
typedef std::pair<WorkListUnit, QueuePriority> QueueItem;
using QueuePriority = std::pair<int, unsigned long>;
using QueueItem = std::pair<WorkListUnit, QueuePriority>;
struct ExplorationComparator {
bool operator() (const QueueItem &LHS, const QueueItem &RHS) {
@ -275,27 +300,22 @@ static std::unique_ptr<WorkList> 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<CallEnter>(), 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<ChooseExpr>(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<DoStmt>(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<IndirectGotoStmt>(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<SwitchStmt>(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<CallEnter>()) {
@ -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<StackFrameContext>(N->getLocationContext());
const auto *LocCtx = cast<StackFrameContext>(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) {

View File

@ -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 <cassert>
#include <cstdint>
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<CallEvent::FrameBindingTy, 16> 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<TypedValueRegion>(R)) {
if (const auto *TR = dyn_cast<TypedValueRegion>(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<TypedValueRegion>(baseR)) {
if (const auto *TR = dyn_cast<TypedValueRegion>(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<TypedValueRegion>(MR);
const auto *TVR = dyn_cast<TypedValueRegion>(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<TypedValueRegion>(MR))
if (const auto *TVR = dyn_cast<TypedValueRegion>(MR))
return TVR->getValueType()->getAsCXXRecordDecl();
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
if (const auto *SR = dyn_cast<SymbolicRegion>(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<CXXBaseObjectRegion>(MR)) {
if (const auto *BaseR = dyn_cast<CXXBaseObjectRegion>(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<ObjCIvarDecl>(D))
if (const auto *ID = dyn_cast<ObjCIvarDecl>(D))
return loc::MemRegionVal(MRMgr.getObjCIvarRegion(ID, BaseR));
return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(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<loc::MemRegionVal>().getRegionAs<SubRegion>();
// Pointer of any type can be cast and used as array base.
const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
const auto *ElemR = dyn_cast<ElementRegion>(BaseRegion);
// Convert the offset to the appropriate size and signedness.
Offset = svalBuilder.convertToArrayIndex(Offset).castAs<NonLoc>();
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,