forked from OSchip/llvm-project
[StaticAnalyzer] Fix some Clang-tidy modernize and Include What You Use warnings; other minor fixes (NFC).
llvm-svn: 326633
This commit is contained in:
parent
e29375d04c
commit
e029a2ff23
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue