diff options
Diffstat (limited to 'include/clang/StaticAnalyzer/Core/PathSensitive')
19 files changed, 435 insertions, 214 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h index 3e0913ec4e..15b930bc3f 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -15,7 +15,7 @@ #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index 0d1a120c9d..4aa87443e4 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -20,6 +20,7 @@ #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" namespace clang { namespace ento { @@ -29,8 +30,9 @@ class CompoundValData : public llvm::FoldingSetNode { llvm::ImmutableList<SVal> L; public: - CompoundValData(QualType t, llvm::ImmutableList<SVal> l) - : T(t), L(l) {} + CompoundValData(QualType t, llvm::ImmutableList<SVal> l) : T(t), L(l) { + assert(NonLoc::isCompoundType(t)); + } typedef llvm::ImmutableList<SVal>::iterator iterator; iterator begin() const { return L.begin(); } @@ -47,7 +49,9 @@ class LazyCompoundValData : public llvm::FoldingSetNode { const TypedValueRegion *region; public: LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r) - : store(st), region(r) {} + : store(st), region(r) { + assert(NonLoc::isCompoundType(r->getValueType())); + } const void *getStore() const { return store.getStore(); } const TypedValueRegion *getRegion() const { return region; } @@ -120,7 +124,7 @@ public: /// Returns the type of the APSInt used to store values of the given QualType. APSIntType getAPSIntType(QualType T) const { assert(T->isIntegralOrEnumerationType() || Loc::isLocType(T)); - return APSIntType(Ctx.getTypeSize(T), + return APSIntType(Ctx.getIntWidth(T), !T->isSignedIntegerOrEnumerationType()); } @@ -176,6 +180,11 @@ public: return getValue(X); } + inline const llvm::APSInt& getZeroWithTypeSize(QualType T) { + assert(T->isScalarType()); + return getValue(0, Ctx.getTypeSize(T), true); + } + inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index aaecf38f33..9fec217aca 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -19,7 +19,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/SourceManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" @@ -383,7 +383,9 @@ public: // Iterator access to formal parameters and their types. private: - typedef std::const_mem_fun_t<QualType, ParmVarDecl> get_type_fun; + struct GetTypeFn { + QualType operator()(ParmVarDecl *PD) const { return PD->getType(); } + }; public: /// Return call's formal parameters. @@ -393,7 +395,7 @@ public: /// correspond with the argument value returned by \c getArgSVal(0). virtual ArrayRef<ParmVarDecl*> parameters() const = 0; - typedef llvm::mapped_iterator<ArrayRef<ParmVarDecl*>::iterator, get_type_fun> + typedef llvm::mapped_iterator<ArrayRef<ParmVarDecl*>::iterator, GetTypeFn> param_type_iterator; /// Returns an iterator over the types of the call's formal parameters. @@ -402,13 +404,11 @@ public: /// definition because it represents a public interface, and probably has /// more annotations. param_type_iterator param_type_begin() const { - return llvm::map_iterator(parameters().begin(), - get_type_fun(&ParmVarDecl::getType)); + return llvm::map_iterator(parameters().begin(), GetTypeFn()); } /// \sa param_type_begin() param_type_iterator param_type_end() const { - return llvm::map_iterator(parameters().end(), - get_type_fun(&ParmVarDecl::getType)); + return llvm::map_iterator(parameters().end(), GetTypeFn()); } // For debugging purposes only @@ -436,20 +436,7 @@ public: return cast<FunctionDecl>(CallEvent::getDecl()); } - RuntimeDefinition getRuntimeDefinition() const override { - const FunctionDecl *FD = getDecl(); - // Note that the AnalysisDeclContext will have the FunctionDecl with - // the definition (if one exists). - if (FD) { - AnalysisDeclContext *AD = - getLocationContext()->getAnalysisDeclContext()-> - getManager()->getContext(FD); - if (AD->getBody()) - return RuntimeDefinition(AD->getDecl()); - } - - return RuntimeDefinition(); - } + RuntimeDefinition getRuntimeDefinition() const override; bool argumentsMayEscape() const override; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index e380982d43..78d38a3d59 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -196,6 +196,13 @@ public: return getState()->getSVal(S, getLocationContext()); } + /// \brief Returns true if the value of \p E is greater than or equal to \p + /// Val under unsigned comparison + bool isGreaterOrEqual(const Expr *E, unsigned long long Val); + + /// Returns true if the value of \p E is negative. + bool isNegative(const Expr *E); + /// \brief Generates a new transition in the program state graph /// (ExplodedGraph). Uses the default CheckerContext predecessor node. /// diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h index fa12d7727d..c01600d5c9 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -184,6 +184,9 @@ std::unique_ptr<ConstraintManager> CreateRangeConstraintManager(ProgramStateManager &statemgr, SubEngine *subengine); +std::unique_ptr<ConstraintManager> +CreateZ3ConstraintManager(ProgramStateManager &statemgr, SubEngine *subengine); + } // end GR namespace } // end clang namespace diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index 12ec5b6c64..7472a7147f 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -16,7 +16,7 @@ #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H #include "clang/AST/Expr.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h index a66e1a1aed..c63ed4a013 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h @@ -14,7 +14,7 @@ #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/ImmutableMap.h" diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index a710ae68be..dcea5e461d 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -20,14 +20,14 @@ #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H #include "clang/AST/Decl.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/Analysis/Support/BumpVector.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SetVector.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" #include <memory> @@ -404,7 +404,7 @@ private: }; class ExplodedNodeSet { - typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy; + typedef llvm::SmallSetVector<ExplodedNode*, 4> ImplTy; ImplTy Impl; public: @@ -424,7 +424,7 @@ public: unsigned size() const { return Impl.size(); } bool empty() const { return Impl.empty(); } - bool erase(ExplodedNode *N) { return Impl.erase(N); } + bool erase(ExplodedNode *N) { return Impl.remove(N); } void clear() { Impl.clear(); } void insert(const ExplodedNodeSet &S) { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index fa7769bcfc..ecff5c6623 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -196,6 +196,8 @@ public: void ProcessStmt(const CFGStmt S, ExplodedNode *Pred); + void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred); + void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred); void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred); @@ -237,7 +239,7 @@ public: const CFGBlock *DstF) override; /// Called by CoreEngine. Used to processing branching behavior - /// at static initalizers. + /// at static initializers. void processStaticInitializer(const DeclStmt *DS, NodeBuilderContext& BuilderCtx, ExplodedNode *Pred, @@ -621,16 +623,16 @@ private: void performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, const CallEvent &Call); - /// If the value of the given expression is a NonLoc, copy it into a new - /// temporary object region, and replace the value of the expression with - /// that. + /// If the value of the given expression \p InitWithAdjustments is a NonLoc, + /// copy it into a new temporary object region, and replace the value of the + /// expression with that. /// - /// If \p ResultE is provided, the new region will be bound to this expression - /// instead of \p E. + /// If \p Result is provided, the new region will be bound to this expression + /// instead of \p InitWithAdjustments. ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State, const LocationContext *LC, - const Expr *E, - const Expr *ResultE = nullptr); + const Expr *InitWithAdjustments, + const Expr *Result = nullptr); /// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG /// block to find the constructor expression that directly constructed into diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h new file mode 100644 index 0000000000..a4c505ce5f --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h @@ -0,0 +1,50 @@ +//===--- LoopUnrolling.h - Unroll loops -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// This header contains the declarations of functions which are used to decide +/// which loops should be completely unrolled and mark their corresponding +/// CFGBlocks. It is done by tracking a stack of loops in the ProgramState. This +/// way specific loops can be marked as completely unrolled. For considering a +/// loop to be completely unrolled it has to fulfill the following requirements: +/// - Currently only forStmts can be considered. +/// - The bound has to be known. +/// - The counter variable has not escaped before/in the body of the loop and +/// changed only in the increment statement corresponding to the loop. It also +/// has to be initialized by a literal in the corresponding initStmt. +/// - Does not contain goto, switch and returnStmt. +/// +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPUNROLLING_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPUNROLLING_H + +#include "clang/Analysis/CFG.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +namespace clang { +namespace ento { +class AnalysisManager; + +/// Returns if the given State indicates that is inside a completely unrolled +/// loop. +bool isUnrolledState(ProgramStateRef State); + +/// Updates the stack of loops contained by the ProgramState. +ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx, + ExplodedNode* Pred, unsigned maxVisitOnPath); + +/// Updates the given ProgramState. In current implementation it removes the top +/// element of the stack of loops. +ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State); + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index da4b964424..8ab6656230 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -21,7 +21,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprObjC.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/FoldingSet.h" @@ -182,6 +182,7 @@ protected: MemSpaceRegion(MemRegionManager *mgr, Kind k) : MemRegion(k), Mgr(mgr) { assert(classof(this)); + assert(mgr); } MemRegionManager* getMemRegionManager() const override { return Mgr; } @@ -215,9 +216,12 @@ public: class GlobalsSpaceRegion : public MemSpaceRegion { virtual void anchor(); + protected: - GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) - : MemSpaceRegion(mgr, k) {} + GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) : MemSpaceRegion(mgr, k) { + assert(classof(this)); + } + public: static bool classof(const MemRegion *R) { Kind k = R->getKind(); @@ -236,7 +240,9 @@ class StaticGlobalSpaceRegion : public GlobalsSpaceRegion { const CodeTextRegion *CR; StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr) - : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {} + : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) { + assert(cr); + } public: void Profile(llvm::FoldingSetNodeID &ID) const override; @@ -257,9 +263,13 @@ public: /// RegionStoreManager::invalidateRegions (instead of finding all the dependent /// globals, we invalidate the whole parent region). class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion { + virtual void anchor() override; + protected: NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k) - : GlobalsSpaceRegion(mgr, k) {} + : GlobalsSpaceRegion(mgr, k) { + assert(classof(this)); + } public: @@ -326,7 +336,6 @@ public: }; class HeapSpaceRegion : public MemSpaceRegion { - virtual void anchor(); friend class MemRegionManager; HeapSpaceRegion(MemRegionManager *mgr) @@ -341,10 +350,10 @@ public: }; class UnknownSpaceRegion : public MemSpaceRegion { - virtual void anchor(); friend class MemRegionManager; UnknownSpaceRegion(MemRegionManager *mgr) - : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} + : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} + public: void dumpToStream(raw_ostream &os) const override; @@ -355,13 +364,15 @@ public: }; class StackSpaceRegion : public MemSpaceRegion { -private: + virtual void anchor(); + const StackFrameContext *SFC; protected: StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc) : MemSpaceRegion(mgr, k), SFC(sfc) { assert(classof(this)); + assert(sfc); } public: @@ -376,7 +387,6 @@ public: }; class StackLocalsSpaceRegion : public StackSpaceRegion { - virtual void anchor(); friend class MemRegionManager; StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {} @@ -391,7 +401,6 @@ public: class StackArgumentsSpaceRegion : public StackSpaceRegion { private: - virtual void anchor(); friend class MemRegionManager; StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {} @@ -408,11 +417,15 @@ public: /// SubRegion - A region that subsets another larger region. Most regions /// are subclasses of SubRegion. class SubRegion : public MemRegion { -private: virtual void anchor(); + protected: const MemRegion* superRegion; - SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {} + SubRegion(const MemRegion *sReg, Kind k) : MemRegion(k), superRegion(sReg) { + assert(classof(this)); + assert(sReg); + } + public: const MemRegion* getSuperRegion() const { return superRegion; @@ -440,13 +453,18 @@ public: /// by a call to 'alloca'. class AllocaRegion : public SubRegion { friend class MemRegionManager; -protected: + unsigned Cnt; // Block counter. Used to distinguish different pieces of // memory allocated by alloca at the same call site. const Expr *Ex; - AllocaRegion(const Expr *ex, unsigned cnt, const MemRegion *superRegion) - : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {} + AllocaRegion(const Expr *ex, unsigned cnt, const MemSpaceRegion *superRegion) + : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) { + assert(Ex); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex, + unsigned Cnt, const MemRegion *superRegion); public: @@ -458,9 +476,6 @@ public: void Profile(llvm::FoldingSetNodeID& ID) const override; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex, - unsigned Cnt, const MemRegion *superRegion); - void dumpToStream(raw_ostream &os) const override; static bool classof(const MemRegion* R) { @@ -470,10 +485,12 @@ public: /// TypedRegion - An abstract class representing regions that are typed. class TypedRegion : public SubRegion { -public: - void anchor() override; + virtual void anchor() override; + protected: - TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {} + TypedRegion(const MemRegion *sReg, Kind k) : SubRegion(sReg, k) { + assert(classof(this)); + } public: virtual QualType getLocationType() const = 0; @@ -492,10 +509,12 @@ public: /// TypedValueRegion - An abstract class representing regions having a typed value. class TypedValueRegion : public TypedRegion { -public: - void anchor() override; + virtual void anchor() override; + protected: - TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {} + TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) { + assert(classof(this)); + } public: virtual QualType getValueType() const = 0; @@ -524,10 +543,13 @@ public: class CodeTextRegion : public TypedRegion { -public: - void anchor() override; + virtual void anchor() override; + protected: - CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {} + CodeTextRegion(const MemSpaceRegion *sreg, Kind k) : TypedRegion(sreg, k) { + assert(classof(this)); + } + public: bool isBoundable() const override { return false; } @@ -539,13 +561,19 @@ public: /// FunctionCodeRegion - A region that represents code texts of function. class FunctionCodeRegion : public CodeTextRegion { + friend class MemRegionManager; + const NamedDecl *FD; -public: - FunctionCodeRegion(const NamedDecl *fd, const MemRegion* sreg) + + FunctionCodeRegion(const NamedDecl *fd, const CodeSpaceRegion* sreg) : CodeTextRegion(sreg, FunctionCodeRegionKind), FD(fd) { assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd)); } + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD, + const MemRegion*); + +public: QualType getLocationType() const override { const ASTContext &Ctx = getContext(); if (const FunctionDecl *D = dyn_cast<FunctionDecl>(FD)) { @@ -568,9 +596,6 @@ public: void Profile(llvm::FoldingSetNodeID& ID) const override; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const NamedDecl *FD, - const MemRegion*); - static bool classof(const MemRegion* R) { return R->getKind() == FunctionCodeRegionKind; } @@ -591,8 +616,16 @@ class BlockCodeRegion : public CodeTextRegion { CanQualType locTy; BlockCodeRegion(const BlockDecl *bd, CanQualType lTy, - AnalysisDeclContext *ac, const MemRegion* sreg) - : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) {} + AnalysisDeclContext *ac, const CodeSpaceRegion* sreg) + : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) { + assert(bd); + assert(ac); + assert(lTy->getTypePtr()->isBlockPointerType()); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, + CanQualType, const AnalysisDeclContext*, + const MemRegion*); public: QualType getLocationType() const override { @@ -609,10 +642,6 @@ public: void Profile(llvm::FoldingSetNodeID& ID) const override; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, - CanQualType, const AnalysisDeclContext*, - const MemRegion*); - static bool classof(const MemRegion* R) { return R->getKind() == BlockCodeRegionKind; } @@ -626,6 +655,7 @@ public: /// variables. class BlockDataRegion : public TypedRegion { friend class MemRegionManager; + const BlockCodeRegion *BC; const LocationContext *LC; // Can be null */ unsigned BlockCount; @@ -633,10 +663,19 @@ class BlockDataRegion : public TypedRegion { void *OriginalVars; BlockDataRegion(const BlockCodeRegion *bc, const LocationContext *lc, - unsigned count, const MemRegion *sreg) - : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), - BlockCount(count), - ReferencedVars(nullptr), OriginalVars(nullptr) {} + unsigned count, const MemSpaceRegion *sreg) + : TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), + BlockCount(count), ReferencedVars(nullptr), OriginalVars(nullptr) { + assert(bc); + assert(lc); + assert(isa<GlobalImmutableSpaceRegion>(sreg) || + isa<StackLocalsSpaceRegion>(sreg) || + isa<UnknownSpaceRegion>(sreg)); + } + + static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *, + const LocationContext *, unsigned, + const MemRegion *); public: const BlockCodeRegion *getCodeRegion() const { return BC; } @@ -686,10 +725,6 @@ public: void Profile(llvm::FoldingSetNodeID& ID) const override; - static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *, - const LocationContext *, unsigned, - const MemRegion *); - static bool classof(const MemRegion* R) { return R->getKind() == BlockDataRegionKind; } @@ -705,13 +740,20 @@ private: /// map the concept of symbolic values into the domain of regions. Symbolic /// regions do not need to be typed. class SymbolicRegion : public SubRegion { -protected: + friend class MemRegionManager; + const SymbolRef sym; -public: - SymbolicRegion(const SymbolRef s, const MemRegion* sreg) - : SubRegion(sreg, SymbolicRegionKind), sym(s) {} + SymbolicRegion(const SymbolRef s, const MemSpaceRegion *sreg) + : SubRegion(sreg, SymbolicRegionKind), sym(s) { + assert(s); + assert(s->getType()->isAnyPointerType() || + s->getType()->isReferenceType() || + s->getType()->isBlockPointerType()); + assert(isa<UnknownSpaceRegion>(sreg) || isa<HeapSpaceRegion>(sreg)); + } +public: SymbolRef getSymbol() const { return sym; } @@ -736,11 +778,13 @@ public: /// StringRegion - Region associated with a StringLiteral. class StringRegion : public TypedValueRegion { friend class MemRegionManager; + const StringLiteral* Str; -protected: - StringRegion(const StringLiteral* str, const MemRegion* sreg) - : TypedValueRegion(sreg, StringRegionKind), Str(str) {} + StringRegion(const StringLiteral *str, const GlobalInternalSpaceRegion *sreg) + : TypedValueRegion(sreg, StringRegionKind), Str(str) { + assert(str); + } static void ProfileRegion(llvm::FoldingSetNodeID& ID, const StringLiteral* Str, @@ -772,12 +816,15 @@ public: /// The region associated with an ObjCStringLiteral. class ObjCStringRegion : public TypedValueRegion { friend class MemRegionManager; + const ObjCStringLiteral* Str; -protected: - - ObjCStringRegion(const ObjCStringLiteral* str, const MemRegion* sreg) - : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) {} - + + ObjCStringRegion(const ObjCStringLiteral *str, + const GlobalInternalSpaceRegion *sreg) + : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) { + assert(str); + } + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCStringLiteral* Str, const MemRegion* superRegion); @@ -807,12 +854,17 @@ public: /// Compound literals are essentially temporaries that are stack allocated /// or in the global constant pool. class CompoundLiteralRegion : public TypedValueRegion { -private: friend class MemRegionManager; + const CompoundLiteralExpr *CL; - CompoundLiteralRegion(const CompoundLiteralExpr *cl, const MemRegion* sReg) - : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {} + CompoundLiteralRegion(const CompoundLiteralExpr *cl, + const MemSpaceRegion *sReg) + : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) { + assert(cl); + assert(isa<GlobalInternalSpaceRegion>(sReg) || + isa<StackLocalsSpaceRegion>(sReg)); + } static void ProfileRegion(llvm::FoldingSetNodeID& ID, const CompoundLiteralExpr *CL, @@ -839,8 +891,11 @@ class DeclRegion : public TypedValueRegion { protected: const Decl *D; - DeclRegion(const Decl *d, const MemRegion* sReg, Kind k) - : TypedValueRegion(sReg, k), D(d) {} + DeclRegion(const Decl *d, const MemRegion *sReg, Kind k) + : TypedValueRegion(sReg, k), D(d) { + assert(classof(this)); + assert(d); + } static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D, const MemRegion* superRegion, Kind k); @@ -859,17 +914,24 @@ class VarRegion : public DeclRegion { friend class MemRegionManager; // Constructors and private methods. - VarRegion(const VarDecl *vd, const MemRegion* sReg) - : DeclRegion(vd, sReg, VarRegionKind) {} + VarRegion(const VarDecl *vd, const MemRegion *sReg) + : DeclRegion(vd, sReg, VarRegionKind) { + // VarRegion appears in unknown space when it's a block variable as seen + // from a block using it, when this block is analyzed at top-level. + // Other block variables appear within block data regions, + // which, unlike everything else on this list, are not memory spaces. + assert(isa<GlobalsSpaceRegion>(sReg) || isa<StackSpaceRegion>(sReg) || + isa<BlockDataRegion>(sReg) || isa<UnknownSpaceRegion>(sReg)); + } static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD, const MemRegion *superRegion) { DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); } +public: void Profile(llvm::FoldingSetNodeID& ID) const override; -public: const VarDecl *getDecl() const { return cast<VarDecl>(D); } const StackFrameContext *getStackFrame() const; @@ -895,17 +957,19 @@ public: /// referred to by 'this', but rather 'this' itself. class CXXThisRegion : public TypedValueRegion { friend class MemRegionManager; + CXXThisRegion(const PointerType *thisPointerTy, - const MemRegion *sReg) - : TypedValueRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {} + const StackArgumentsSpaceRegion *sReg) + : TypedValueRegion(sReg, CXXThisRegionKind), + ThisPointerTy(thisPointerTy) {} static void ProfileRegion(llvm::FoldingSetNodeID &ID, const PointerType *PT, const MemRegion *sReg); +public: void Profile(llvm::FoldingSetNodeID &ID) const override; -public: QualType getValueType() const override { return QualType(ThisPointerTy, 0); } @@ -923,9 +987,14 @@ private: class FieldRegion : public DeclRegion { friend class MemRegionManager; - FieldRegion(const FieldDecl *fd, const MemRegion* sReg) + FieldRegion(const FieldDecl *fd, const SubRegion* sReg) : DeclRegion(fd, sReg, FieldRegionKind) {} + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); + } + public: const FieldDecl *getDecl() const { return cast<FieldDecl>(D); } @@ -936,11 +1005,6 @@ public: DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD, - const MemRegion* superRegion) { - DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); - } - static bool classof(const MemRegion* R) { return R->getKind() == FieldRegionKind; } @@ -954,10 +1018,9 @@ public: }; class ObjCIvarRegion : public DeclRegion { - friend class MemRegionManager; - ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg); + ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg); static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd, const MemRegion* superRegion); @@ -982,7 +1045,6 @@ public: class ElementRegion; class RegionRawOffset { -private: friend class ElementRegion; const MemRegion *Region; @@ -1007,9 +1069,9 @@ class ElementRegion : public TypedValueRegion { QualType ElementType; NonLoc Index; - ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg) - : TypedValueRegion(sReg, ElementRegionKind), - ElementType(elementType), Index(Idx) { + ElementRegion(QualType elementType, NonLoc Idx, const SubRegion *sReg) + : TypedValueRegion(sReg, ElementRegionKind), + ElementType(elementType), Index(Idx) { assert((!Idx.getAs<nonloc::ConcreteInt>() || Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) && "The index must be signed"); @@ -1047,12 +1109,16 @@ class CXXTempObjectRegion : public TypedValueRegion { Expr const *Ex; - CXXTempObjectRegion(Expr const *E, MemRegion const *sReg) - : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {} + CXXTempObjectRegion(Expr const *E, MemSpaceRegion const *sReg) + : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) { + assert(E); + assert(isa<StackLocalsSpaceRegion>(sReg) || + isa<GlobalInternalSpaceRegion>(sReg)); + } static void ProfileRegion(llvm::FoldingSetNodeID &ID, Expr const *E, const MemRegion *sReg); - + public: const Expr *getExpr() const { return Ex; } @@ -1077,8 +1143,10 @@ class CXXBaseObjectRegion : public TypedValueRegion { llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data; CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual, - const MemRegion *SReg) - : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {} + const SubRegion *SReg) + : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) { + assert(RD); + } static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD, bool IsVirtual, const MemRegion *SReg); @@ -1204,16 +1272,16 @@ public: /// getVarRegion - Retrieve or create the memory region associated with /// a specified VarDecl and super region. - const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR); - + const VarRegion *getVarRegion(const VarDecl *D, const MemRegion *superR); + /// getElementRegion - Retrieve the memory region associated with the /// associated element type, index, and super region. const ElementRegion *getElementRegion(QualType elementType, NonLoc Idx, - const MemRegion *superRegion, + const SubRegion *superRegion, ASTContext &Ctx); const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, - const MemRegion *superRegion) { + const SubRegion *superRegion) { return getElementRegion(ER->getElementType(), ER->getIndex(), superRegion, ER->getContext()); } @@ -1223,10 +1291,10 @@ public: /// memory region (which typically represents the memory representing /// a structure or class). const FieldRegion *getFieldRegion(const FieldDecl *fd, - const MemRegion* superRegion); + const SubRegion* superRegion); const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, - const MemRegion *superRegion) { + const SubRegion *superRegion) { return getFieldRegion(FR->getDecl(), superRegion); } @@ -1235,7 +1303,7 @@ public: /// to the containing region (which typically represents the Objective-C /// object). const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl *ivd, - const MemRegion* superRegion); + const SubRegion* superRegion); const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex, LocationContext const *LC); @@ -1245,14 +1313,14 @@ public: /// /// The type of \p Super is assumed be a class deriving from \p BaseClass. const CXXBaseObjectRegion * - getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const MemRegion *Super, + getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const SubRegion *Super, bool IsVirtual); /// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different /// super region. const CXXBaseObjectRegion * getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg, - const MemRegion *superRegion) { + const SubRegion *superRegion) { return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion, baseReg->isVirtual()); } @@ -1276,17 +1344,22 @@ public: const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex); private: - template <typename RegionTy, typename A1> - RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion); + template <typename RegionTy, typename SuperTy, + typename Arg1Ty> + RegionTy* getSubRegion(const Arg1Ty arg1, + const SuperTy* superRegion); + + template <typename RegionTy, typename SuperTy, + typename Arg1Ty, typename Arg2Ty> + RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, + const SuperTy* superRegion); + + template <typename RegionTy, typename SuperTy, + typename Arg1Ty, typename Arg2Ty, typename Arg3Ty> + RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, + const Arg3Ty arg3, + const SuperTy* superRegion); - template <typename RegionTy, typename A1, typename A2> - RegionTy* getSubRegion(const A1 a1, const A2 a2, - const MemRegion* superRegion); - - template <typename RegionTy, typename A1, typename A2, typename A3> - RegionTy* getSubRegion(const A1 a1, const A2 a2, const A3 a3, - const MemRegion* superRegion); - template <typename REG> const REG* LazyAllocate(REG*& region); @@ -1339,21 +1412,18 @@ public: bool hasTrait(SymbolRef Sym, InvalidationKinds IK) const; bool hasTrait(const MemRegion *MR, InvalidationKinds IK) const; }; - -} // end GR namespace - -} // end clang namespace //===----------------------------------------------------------------------===// // Pretty-printing regions. //===----------------------------------------------------------------------===// - -namespace llvm { -static inline raw_ostream &operator<<(raw_ostream &os, - const clang::ento::MemRegion* R) { +inline raw_ostream &operator<<(raw_ostream &os, + const clang::ento::MemRegion *R) { R->dumpToStream(os); return os; } -} // end llvm namespace + +} // namespace ento + +} // namespace clang #endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 2910ef4212..e3a2164b11 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -43,6 +43,7 @@ typedef std::unique_ptr<ConstraintManager>(*ConstraintManagerCreator)( ProgramStateManager &, SubEngine *); typedef std::unique_ptr<StoreManager>(*StoreManagerCreator)( ProgramStateManager &); +typedef llvm::ImmutableMap<const SubRegion*, TaintTagType> TaintedSubRegions; //===----------------------------------------------------------------------===// // ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState. @@ -343,6 +344,9 @@ public: ProgramStateRef addTaint(const Stmt *S, const LocationContext *LCtx, TaintTagType Kind = TaintTagGeneric) const; + /// Create a new state in which the value is marked as tainted. + ProgramStateRef addTaint(SVal V, TaintTagType Kind = TaintTagGeneric) const; + /// Create a new state in which the symbol is marked as tainted. ProgramStateRef addTaint(SymbolRef S, TaintTagType Kind = TaintTagGeneric) const; @@ -351,6 +355,14 @@ public: ProgramStateRef addTaint(const MemRegion *R, TaintTagType Kind = TaintTagGeneric) const; + /// Create a new state in a which a sub-region of a given symbol is tainted. + /// This might be necessary when referring to regions that can not have an + /// individual symbol, e.g. if they are represented by the default binding of + /// a LazyCompoundVal. + ProgramStateRef addPartialTaint(SymbolRef ParentSym, + const SubRegion *SubRegion, + TaintTagType Kind = TaintTagGeneric) const; + /// Check if the statement is tainted in the current state. bool isTainted(const Stmt *S, const LocationContext *LCtx, TaintTagType Kind = TaintTagGeneric) const; @@ -453,6 +465,7 @@ private: std::unique_ptr<ConstraintManager> ConstraintMgr; ProgramState::GenericDataMap::Factory GDMFactory; + TaintedSubRegions::Factory TSRFactory; typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy; GDMContextsTy GDMContexts; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index a4c01fc453..d58d0a690c 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -112,6 +112,11 @@ public: /// Evaluates a given SVal. If the SVal has only one possible (integer) value, /// that value is returned. Otherwise, returns NULL. virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal val) = 0; + + /// Simplify symbolic expressions within a given SVal. Return an SVal + /// that represents the same value, but is hopefully easier to work with + /// than the original SVal. + virtual SVal simplifySVal(ProgramStateRef State, SVal Val) = 0; /// Constructs a symbolic expression for two non-location values. SVal makeSymExprValNN(ProgramStateRef state, BinaryOperator::Opcode op, @@ -310,6 +315,13 @@ public: return nonloc::ConcreteInt(BasicVals.getTruthValue(b)); } + /// Create NULL pointer, with proper pointer bit-width for given address + /// space. + /// \param type pointer type. + Loc makeNullWithType(QualType type) { + return loc::ConcreteInt(BasicVals.getZeroWithTypeSize(type)); + } + Loc makeNull() { return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth()); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index cc3c02a02c..af1af4590d 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -41,6 +41,22 @@ class MemRegionManager; class ProgramStateManager; class SValBuilder; +namespace nonloc { +/// Sub-kinds for NonLoc values. +enum Kind { +#define NONLOC_SVAL(Id, Parent) Id ## Kind, +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" +}; +} + +namespace loc { +/// Sub-kinds for Loc values. +enum Kind { +#define LOC_SVAL(Id, Parent) Id ## Kind, +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" +}; +} + /// SVal - This represents a symbolic expression, which can be either /// an L-value or an R-value. /// @@ -75,10 +91,7 @@ public: template<typename T> T castAs() const { assert(T::isKind(*this)); - T t; - SVal& sv = t; - sv = *this; - return t; + return *static_cast<const T *>(this); } /// \brief Convert to the specified SVal type, returning None if this SVal is @@ -87,10 +100,7 @@ public: Optional<T> getAs() const { if (!T::isKind(*this)) return None; - T t; - SVal& sv = t; - sv = *this; - return t; + return *static_cast<const T *>(this); } /// BufferTy - A temporary buffer to hold a set of SVals. @@ -188,6 +198,10 @@ public: } }; +inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) { + V.dumpToStream(os); + return os; +} class UndefinedVal : public SVal { public: @@ -273,6 +287,11 @@ protected: public: void dumpToStream(raw_ostream &Out) const; + static inline bool isCompoundType(QualType T) { + return T->isArrayType() || T->isRecordType() || + T->isComplexType() || T->isVectorType(); + } + private: friend class SVal; static bool isKind(const SVal& V) { @@ -307,15 +326,11 @@ private: namespace nonloc { -enum Kind { -#define NONLOC_SVAL(Id, Parent) Id ## Kind, -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" -}; - /// \brief Represents symbolic expression. class SymbolVal : public NonLoc { public: - SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} + SymbolVal() = delete; + SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) { assert(sym); } SymbolRef getSymbol() const { return (const SymExpr*) Data; @@ -327,7 +342,6 @@ public: private: friend class SVal; - SymbolVal() {} static bool isKind(const SVal& V) { return V.getBaseKind() == NonLocKind && V.getSubKind() == SymbolValKind; @@ -373,7 +387,11 @@ class LocAsInteger : public NonLoc { explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data) : NonLoc(LocAsIntegerKind, &data) { - assert (data.first.getAs<Loc>()); + // We do not need to represent loc::ConcreteInt as LocAsInteger, + // as it'd collapse into a nonloc::ConcreteInt instead. + assert(data.first.getBaseKind() == LocKind && + (data.first.getSubKind() == loc::MemRegionValKind || + data.first.getSubKind() == loc::GotoLabelKind)); } public: @@ -513,14 +531,11 @@ private: namespace loc { -enum Kind { -#define LOC_SVAL(Id, Parent) Id ## Kind, -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" -}; - class GotoLabel : public Loc { public: - explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {} + explicit GotoLabel(const LabelDecl *Label) : Loc(GotoLabelKind, Label) { + assert(Label); + } const LabelDecl *getLabel() const { return static_cast<const LabelDecl*>(Data); @@ -541,7 +556,9 @@ private: class MemRegionVal : public Loc { public: - explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {} + explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) { + assert(r); + } /// \brief Get the underlining region. const MemRegion* getRegion() const { @@ -609,11 +626,6 @@ private: } // end clang namespace namespace llvm { -static inline raw_ostream &operator<<(raw_ostream &os, - clang::ento::SVal V) { - V.dumpToStream(os); - return os; -} template <typename T> struct isPodLike; template <> struct isPodLike<clang::ento::SVal> { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 7fa7515bf2..25d20a17af 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -51,7 +51,7 @@ public: virtual ~StoreManager() {} /// Return the value bound to specified location in a given state. - /// \param[in] store The analysis state. + /// \param[in] store The store in which to make the lookup. /// \param[in] loc The symbolic memory location. /// \param[in] T An optional type that provides a hint indicating the /// expected type of the returned value. This is used if the value is @@ -83,12 +83,12 @@ public: return getDefaultBinding(lcv.getStore(), lcv.getRegion()); } - /// Return a state with the specified value bound to the given location. - /// \param[in] store The analysis state. + /// Return a store with the specified value bound to the given location. + /// \param[in] store The store in which to make the binding. /// \param[in] loc The symbolic memory location. /// \param[in] val The value to bind to location \c loc. - /// \return A pointer to a ProgramState object that contains the same - /// bindings as \c state with the addition of having the value specified + /// \return A StoreRef object that contains the same + /// bindings as \c store with the addition of having the value specified /// by \c val bound to the location given for \c loc. virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0; @@ -160,7 +160,7 @@ public: /// valid only if Failed flag is set to false. SVal attemptDownCast(SVal Base, QualType DerivedPtrType, bool &Failed); - const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T); + const ElementRegion *GetElementZeroRegion(const SubRegion *R, QualType T); /// castRegion - Used by ExprEngine::VisitCast to handle casts from /// a MemRegion* to a specific location type. 'R' is the region being @@ -259,8 +259,9 @@ public: virtual void iterBindings(Store store, BindingsHandler& f) = 0; protected: - const MemRegion *MakeElementRegion(const MemRegion *baseRegion, - QualType pointeeTy, uint64_t index = 0); + const ElementRegion *MakeElementRegion(const SubRegion *baseRegion, + QualType pointeeTy, + uint64_t index = 0); /// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h index e16df136ca..8ccd34751b 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -83,7 +83,7 @@ public: const CFGBlock *DstF) = 0; /// Called by CoreEngine. Used to processing branching behavior - /// at static initalizers. + /// at static initializers. virtual void processStaticInitializer(const DeclStmt *DS, NodeBuilderContext& BuilderCtx, ExplodedNode *Pred, diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h index 18bc60754b..9780d01447 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h @@ -42,6 +42,12 @@ private: protected: SymExpr(Kind k) : K(k) {} + static bool isValidTypeForSymbol(QualType T) { + // FIXME: Depending on whether we choose to deprecate structural symbols, + // this may become much stricter. + return !T.isNull() && !T->isVoidType(); + } + public: virtual ~SymExpr() {} @@ -92,6 +98,12 @@ public: virtual const MemRegion *getOriginRegion() const { return nullptr; } }; +inline raw_ostream &operator<<(raw_ostream &os, + const clang::ento::SymExpr *SE) { + SE->dumpToStream(os); + return os; +} + typedef const SymExpr *SymbolRef; typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy; @@ -103,7 +115,9 @@ class SymbolData : public SymExpr { const SymbolID Sym; protected: - SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {} + SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) { + assert(classof(this)); + } public: ~SymbolData() override {} diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index f00dce568e..7d2e5ad8ba 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -17,7 +17,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" -#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" @@ -44,7 +44,10 @@ class SymbolRegionValue : public SymbolData { public: SymbolRegionValue(SymbolID sym, const TypedValueRegion *r) - : SymbolData(SymbolRegionValueKind, sym), R(r) {} + : SymbolData(SymbolRegionValueKind, sym), R(r) { + assert(r); + assert(isValidTypeForSymbol(r->getValueType())); + } const TypedValueRegion* getRegion() const { return R; } @@ -81,7 +84,15 @@ public: SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx, QualType t, unsigned count, const void *symbolTag) : SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count), - LCtx(lctx), SymbolTag(symbolTag) {} + LCtx(lctx), SymbolTag(symbolTag) { + // FIXME: 's' might be a nullptr if we're conducting invalidation + // that was caused by a destructor call on a temporary object, + // which has no statement associated with it. + // Due to this, we might be creating the same invalidation symbol for + // two different invalidation passes (for two different temporaries). + assert(lctx); + assert(isValidTypeForSymbol(t)); + } const Stmt *getStmt() const { return S; } unsigned getCount() const { return Count; } @@ -120,7 +131,11 @@ class SymbolDerived : public SymbolData { public: SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r) - : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) {} + : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) { + assert(parent); + assert(r); + assert(isValidTypeForSymbol(r->getValueType())); + } SymbolRef getParentSymbol() const { return parentSymbol; } const TypedValueRegion *getRegion() const { return R; } @@ -155,7 +170,9 @@ class SymbolExtent : public SymbolData { public: SymbolExtent(SymbolID sym, const SubRegion *r) - : SymbolData(SymbolExtentKind, sym), R(r) {} + : SymbolData(SymbolExtentKind, sym), R(r) { + assert(r); + } const SubRegion *getRegion() const { return R; } @@ -193,7 +210,13 @@ public: SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t, const LocationContext *LCtx, unsigned count, const void *tag) : SymbolData(SymbolMetadataKind, sym), R(r), S(s), T(t), LCtx(LCtx), - Count(count), Tag(tag) {} + Count(count), Tag(tag) { + assert(r); + assert(s); + assert(isValidTypeForSymbol(t)); + assert(LCtx); + assert(tag); + } const MemRegion *getRegion() const { return R; } const Stmt *getStmt() const { return S; } @@ -236,8 +259,13 @@ class SymbolCast : public SymExpr { QualType ToTy; public: - SymbolCast(const SymExpr *In, QualType From, QualType To) : - SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) { } + SymbolCast(const SymExpr *In, QualType From, QualType To) + : SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) { + assert(In); + assert(isValidTypeForSymbol(From)); + // FIXME: GenericTaintChecker creates symbols of void type. + // Otherwise, 'To' should also be a valid type. + } QualType getType() const override { return ToTy; } @@ -270,7 +298,10 @@ class BinarySymExpr : public SymExpr { protected: BinarySymExpr(Kind k, BinaryOperator::Opcode op, QualType t) - : SymExpr(k), Op(op), T(t) {} + : SymExpr(k), Op(op), T(t) { + assert(classof(this)); + assert(isValidTypeForSymbol(t)); + } public: // FIXME: We probably need to make this out-of-line to avoid redundant @@ -293,8 +324,10 @@ class SymIntExpr : public BinarySymExpr { public: SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt& rhs, QualType t) - : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) {} + const llvm::APSInt &rhs, QualType t) + : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) { + assert(lhs); + } void dumpToStream(raw_ostream &os) const override; @@ -327,9 +360,11 @@ class IntSymExpr : public BinarySymExpr { const SymExpr *RHS; public: - IntSymExpr(const llvm::APSInt& lhs, BinaryOperator::Opcode op, + IntSymExpr(const llvm::APSInt &lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) - : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) {} + : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) { + assert(rhs); + } void dumpToStream(raw_ostream &os) const override; @@ -364,7 +399,10 @@ class SymSymExpr : public BinarySymExpr { public: SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) - : BinarySymExpr(SymSymExprKind, op, t), LHS(lhs), RHS(rhs) {} + : BinarySymExpr(SymSymExprKind, op, t), LHS(lhs), RHS(rhs) { + assert(lhs); + assert(rhs); + } const SymExpr *getLHS() const { return LHS; } const SymExpr *getRHS() const { return RHS; } @@ -595,11 +633,4 @@ public: } // end clang namespace -namespace llvm { -static inline raw_ostream &operator<<(raw_ostream &os, - const clang::ento::SymExpr *SE) { - SE->dumpToStream(os); - return os; -} -} // end llvm namespace #endif diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h index d39b5017d3..7b76263f04 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h @@ -35,6 +35,16 @@ template<> struct ProgramStateTrait<TaintMap> static void *GDMIndex() { static int index = 0; return &index; } }; +/// The GDM component mapping derived symbols' parent symbols to their +/// underlying regions. This is used to efficiently check whether a symbol is +/// tainted when it represents a sub-region of a tainted symbol. +struct DerivedSymTaint {}; +typedef llvm::ImmutableMap<SymbolRef, TaintedSubRegions> DerivedSymTaintImpl; +template<> struct ProgramStateTrait<DerivedSymTaint> + : public ProgramStatePartialTrait<DerivedSymTaintImpl> { + static void *GDMIndex() { static int index; return &index; } +}; + class TaintManager { TaintManager() {} |