diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
commit | 486754660bb926339aefcf012a3f848592babb8b (patch) | |
tree | ecdbc446c9876f4f120f701c243373cd3cb43db3 /include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h | |
parent | 55e6d896ad333f07bb3b1ba487df214fc268a4ab (diff) | |
download | src-486754660bb926339aefcf012a3f848592babb8b.tar.gz src-486754660bb926339aefcf012a3f848592babb8b.zip |
Vendor import of clang trunk r338150:vendor/clang/clang-trunk-r338150
Notes
Notes:
svn path=/vendor/clang/dist/; revision=336815
svn path=/vendor/clang/clang-trunk-r338150/; revision=336816; tag=vendor/clang/clang-trunk-r338150
Diffstat (limited to 'include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h')
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h | 264 |
1 files changed, 208 insertions, 56 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 712cd6361e11..25849e94c8ff 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -1,4 +1,4 @@ -//===-- ExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-=// +//===- ExprEngine.h - Path-Sensitive Expression-Level Dataflow --*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,32 +18,68 @@ #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "clang/Analysis/CFG.h" #include "clang/Analysis/DomainSpecific/ObjCNoReturn.h" +#include "clang/Analysis/ProgramPoint.h" +#include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.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/SubEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" +#include "llvm/ADT/ArrayRef.h" +#include <cassert> +#include <utility> namespace clang { class AnalysisDeclContextManager; +class AnalyzerOptions; +class ASTContext; +class ConstructionContext; +class CXXBindTemporaryExpr; class CXXCatchStmt; class CXXConstructExpr; class CXXDeleteExpr; class CXXNewExpr; -class CXXTemporaryObjectExpr; class CXXThisExpr; +class Decl; +class DeclStmt; +class GCCAsmStmt; +class LambdaExpr; +class LocationContext; class MaterializeTemporaryExpr; +class MSAsmStmt; +class NamedDecl; class ObjCAtSynchronizedStmt; class ObjCForCollectionStmt; +class ObjCIvarRefExpr; +class ObjCMessageExpr; +class ReturnStmt; +class Stmt; + +namespace cross_tu { + +class CrossTranslationUnitContext; + +} // namespace cross_tu namespace ento { -class AnalysisManager; +class BasicValueFactory; class CallEvent; -class CXXConstructorCall; +class CheckerManager; +class ConstraintManager; +class CXXTempObjectRegion; +class MemRegion; +class RegionAndSymbolInvalidationTraits; +class SymbolManager; class ExprEngine : public SubEngine { public: @@ -51,11 +87,35 @@ public: enum InliningModes { /// Follow the default settings for inlining callees. Inline_Regular = 0, + /// Do minimal inlining of callees. Inline_Minimal = 0x1 }; + /// Hints for figuring out of a call should be inlined during evalCall(). + struct EvalCallOptions { + /// This call is a constructor or a destructor for which we do not currently + /// compute the this-region correctly. + bool IsCtorOrDtorWithImproperlyModeledTargetRegion = false; + + /// This call is a constructor or a destructor for a single element within + /// an array, a part of array construction or destruction. + bool IsArrayCtorOrDtor = false; + + /// This call is a constructor or a destructor of a temporary value. + bool IsTemporaryCtorOrDtor = false; + + /// This call is a constructor for a temporary that is lifetime-extended + /// by binding it to a reference-type field within an aggregate, + /// for example 'A { const C &c; }; A a = { C() };' + bool IsTemporaryLifetimeExtendedViaAggregate = false; + + EvalCallOptions() {} + }; + private: + cross_tu::CrossTranslationUnitContext &CTU; + AnalysisManager &AMgr; AnalysisDeclContextManager &AnalysisDeclContexts; @@ -63,19 +123,19 @@ private: CoreEngine Engine; /// G - the simulation graph. - ExplodedGraph& G; + ExplodedGraph &G; /// StateMgr - Object that manages the data for all created states. ProgramStateManager StateMgr; /// SymMgr - Object that manages the symbol information. - SymbolManager& SymMgr; + SymbolManager &SymMgr; /// svalBuilder - SValBuilder object that creates SVals from expressions. SValBuilder &svalBuilder; - unsigned int currStmtIdx; - const NodeBuilderContext *currBldrCtx; + unsigned int currStmtIdx = 0; + const NodeBuilderContext *currBldrCtx = nullptr; /// Helper object to determine if an Objective-C message expression /// implicitly never returns. @@ -97,10 +157,9 @@ private: InliningModes HowToInline; public: - ExprEngine(AnalysisManager &mgr, bool gcEnabled, - SetOfConstDecls *VisitedCalleesIn, - FunctionSummariesTy *FS, - InliningModes HowToInlineIn); + ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, AnalysisManager &mgr, + bool gcEnabled, SetOfConstDecls *VisitedCalleesIn, + FunctionSummariesTy *FS, InliningModes HowToInlineIn); ~ExprEngine() override; @@ -130,7 +189,12 @@ public: SValBuilder &getSValBuilder() { return svalBuilder; } - BugReporter& getBugReporter() { return BR; } + BugReporter &getBugReporter() { return BR; } + + cross_tu::CrossTranslationUnitContext * + getCrossTranslationUnitContext() override { + return &CTU; + } const NodeBuilderContext &getBuilderContext() { assert(currBldrCtx); @@ -150,16 +214,16 @@ public: /// Visualize a trimmed ExplodedGraph that only contains paths to the given /// nodes. - void ViewGraph(ArrayRef<const ExplodedNode*> Nodes); + void ViewGraph(ArrayRef<const ExplodedNode *> Nodes); /// getInitialState - Return the initial state used for the root vertex /// in the ExplodedGraph. ProgramStateRef getInitialState(const LocationContext *InitLoc) override; - ExplodedGraph& getGraph() { return G; } - const ExplodedGraph& getGraph() const { return G; } + ExplodedGraph &getGraph() { return G; } + const ExplodedGraph &getGraph() const { return G; } - /// \brief Run the analyzer's garbage collection - remove dead symbols and + /// Run the analyzer's garbage collection - remove dead symbols and /// bindings from the state. /// /// Checkers can participate in this process with two callbacks: @@ -194,7 +258,7 @@ public: void processCFGElement(const CFGElement E, ExplodedNode *Pred, unsigned StmtIdx, NodeBuilderContext *Ctx) override; - void ProcessStmt(const CFGStmt S, ExplodedNode *Pred); + void ProcessStmt(const Stmt *S, ExplodedNode *Pred); void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred); @@ -299,25 +363,26 @@ public: const CallEvent *Call) override; /// printState - Called by ProgramStateManager to print checker-specific data. - void printState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) override; + void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, + const char *Sep, + const LocationContext *LCtx = nullptr) override; - ProgramStateManager& getStateManager() override { return StateMgr; } + ProgramStateManager &getStateManager() override { return StateMgr; } - StoreManager& getStoreManager() { return StateMgr.getStoreManager(); } + StoreManager &getStoreManager() { return StateMgr.getStoreManager(); } - ConstraintManager& getConstraintManager() { + ConstraintManager &getConstraintManager() { return StateMgr.getConstraintManager(); } // FIXME: Remove when we migrate over to just using SValBuilder. - BasicValueFactory& getBasicVals() { + BasicValueFactory &getBasicVals() { return StateMgr.getBasicVals(); } // FIXME: Remove when we migrate over to just using ValueManager. - SymbolManager& getSymbolManager() { return SymMgr; } - const SymbolManager& getSymbolManager() const { return SymMgr; } + SymbolManager &getSymbolManager() { return SymMgr; } + const SymbolManager &getSymbolManager() const { return SymMgr; } // Functions for external checking of whether we have unfinished work bool wasBlocksExhausted() const { return Engine.wasBlocksExhausted(); } @@ -363,7 +428,7 @@ public: /// VisitCast - Transfer function logic for all casts (implicit and explicit). void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, - ExplodedNodeSet &Dst); + ExplodedNodeSet &Dst); /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. void VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, @@ -390,9 +455,9 @@ public: /// VisitMemberExpr - Transfer function for member expressions. void VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, - ExplodedNodeSet &Dst); + ExplodedNodeSet &Dst); - /// VisitMemberExpr - Transfer function for builtin atomic expressions + /// VisitAtomicExpr - Transfer function for builtin atomic expressions void VisitAtomicExpr(const AtomicExpr *E, ExplodedNode *Pred, ExplodedNodeSet &Dst); @@ -422,7 +487,7 @@ public: /// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof. void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, - ExplodedNode *Pred, ExplodedNodeSet &Dst); + ExplodedNode *Pred, ExplodedNodeSet &Dst); /// VisitUnaryOperator - Transfer function logic for unary operators. void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode *Pred, @@ -448,7 +513,8 @@ public: void VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest, const Stmt *S, bool IsBaseDtor, - ExplodedNode *Pred, ExplodedNodeSet &Dst); + ExplodedNode *Pred, ExplodedNodeSet &Dst, + const EvalCallOptions &Options); void VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, ExplodedNode *Pred, @@ -471,7 +537,7 @@ public: void evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, const Expr *Ex); - std::pair<const ProgramPointTag *, const ProgramPointTag*> + static std::pair<const ProgramPointTag *, const ProgramPointTag *> geteagerlyAssumeBinOpBifurcationTags(); SVal evalMinus(SVal X) { @@ -499,7 +565,6 @@ public: StmtNodeBuilder &Bldr); public: - SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc L, NonLoc R, QualType T) { return svalBuilder.evalBinOpNN(state, op, L, R, T); @@ -539,6 +604,11 @@ protected: const CallEvent *Call, RegionAndSymbolInvalidationTraits &ITraits) override; + /// A simple wrapper when you only need to notify checkers of pointer-escape + /// of a single value. + ProgramStateRef escapeValue(ProgramStateRef State, SVal V, + PointerEscapeKind K) const; + public: // FIXME: 'tag' should be removed, and a LocationContext should be used // instead. @@ -561,7 +631,13 @@ public: ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val, const ProgramPointTag *tag = nullptr); - /// \brief Create a new state in which the call return value is binded to the + /// Return the CFG element corresponding to the worklist element + /// that is currently being processed by ExprEngine. + CFGElement getCurrentCFGElement() { + return (*currBldrCtx->getBlock())[currStmtIdx]; + } + + /// Create a new state in which the call return value is binded to the /// call origin expression. ProgramStateRef bindReturnValue(const CallEvent &Call, const LocationContext *LCtx, @@ -572,9 +648,11 @@ public: void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, const CallEvent &Call); - /// \brief Default implementation of call evaluation. + /// Default implementation of call evaluation. void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred, - const CallEvent &Call); + const CallEvent &Call, + const EvalCallOptions &CallOpts = {}); + private: void evalLoadCommon(ExplodedNodeSet &Dst, const Expr *NodeEx, /* Eventually will be a CFGStmt */ @@ -598,19 +676,33 @@ private: void examineStackFrames(const Decl *D, const LocationContext *LCtx, bool &IsRecursive, unsigned &StackDepth); + enum CallInlinePolicy { + CIP_Allowed, + CIP_DisallowedOnce, + CIP_DisallowedAlways + }; + + /// See if a particular call should be inlined, by only looking + /// at the call event and the current state of analysis. + CallInlinePolicy mayInlineCallKind(const CallEvent &Call, + const ExplodedNode *Pred, + AnalyzerOptions &Opts, + const EvalCallOptions &CallOpts); + /// Checks our policies and decides weither the given call should be inlined. bool shouldInlineCall(const CallEvent &Call, const Decl *D, - const ExplodedNode *Pred); + const ExplodedNode *Pred, + const EvalCallOptions &CallOpts = {}); bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, ExplodedNode *Pred, ProgramStateRef State); - /// \brief Conservatively evaluate call by invalidating regions and binding + /// Conservatively evaluate call by invalidating regions and binding /// a conjured return value. void conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr, ExplodedNode *Pred, ProgramStateRef State); - /// \brief Either inline or process the call conservatively (or both), based + /// Either inline or process the call conservatively (or both), based /// on DynamicDispatchBifurcation data. void BifurcateCall(const MemRegion *BifurReg, const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, @@ -634,6 +726,17 @@ private: const Expr *InitWithAdjustments, const Expr *Result = nullptr); + /// Returns a region representing the first element of a (possibly + /// multi-dimensional) array, for the purposes of element construction or + /// destruction. + /// + /// On return, \p Ty will be set to the base type of the array. + /// + /// If the type is not an array type at all, the original value is returned. + /// Otherwise the "IsArray" flag is set. + static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue, + QualType &Ty, bool &IsArray); + /// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG /// block to find the constructor expression that directly constructed into /// the storage for this statement. Returns null if the constructor for this @@ -641,20 +744,69 @@ private: /// constructing into an existing region. const CXXConstructExpr *findDirectConstructorForCurrentCFGElement(); - /// For a CXXConstructExpr, walk forward in the current CFG block to find the - /// CFGElement for the DeclStmt or CXXInitCtorInitializer for which is - /// directly constructed by this constructor. Returns None if the current - /// constructor expression did not directly construct into an existing - /// region. - Optional<CFGElement> findElementDirectlyInitializedByCurrentConstructor(); - - /// For a given constructor, look forward in the current CFG block to - /// determine the region into which an object will be constructed by \p CE. - /// Returns either a field or local variable region if the object will be - /// directly constructed in an existing region or a temporary object region - /// if not. - const MemRegion *getRegionForConstructedObject(const CXXConstructExpr *CE, - ExplodedNode *Pred); + /// Update the program state with all the path-sensitive information + /// that's necessary to perform construction of an object with a given + /// syntactic construction context. If the construction context is unavailable + /// or unusable for any reason, a dummy temporary region is returned, and the + /// IsConstructorWithImproperlyModeledTargetRegion flag is set in \p CallOpts. + /// Returns the updated program state and the new object's this-region. + std::pair<ProgramStateRef, SVal> prepareForObjectConstruction( + const Expr *E, ProgramStateRef State, const LocationContext *LCtx, + const ConstructionContext *CC, EvalCallOptions &CallOpts); + + /// Store the location of a C++ object corresponding to a statement + /// until the statement is actually encountered. For example, if a DeclStmt + /// has CXXConstructExpr as its initializer, the object would be considered + /// to be "under construction" between CXXConstructExpr and DeclStmt. + /// This allows, among other things, to keep bindings to variable's fields + /// made within the constructor alive until its declaration actually + /// goes into scope. + static ProgramStateRef addObjectUnderConstruction( + ProgramStateRef State, + llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P, + const LocationContext *LC, SVal V); + + /// Mark the object sa fully constructed, cleaning up the state trait + /// that tracks objects under construction. + static ProgramStateRef finishObjectConstruction( + ProgramStateRef State, + llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P, + const LocationContext *LC); + + /// If the given statement corresponds to an object under construction, + /// being part of its construciton context, retrieve that object's location. + static Optional<SVal> getObjectUnderConstruction( + ProgramStateRef State, + llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P, + const LocationContext *LC); + + /// If the given expression corresponds to a temporary that was used for + /// passing into an elidable copy/move constructor and that constructor + /// was actually elided, track that we also need to elide the destructor. + static ProgramStateRef elideDestructor(ProgramStateRef State, + const CXXBindTemporaryExpr *BTE, + const LocationContext *LC); + + /// Stop tracking the destructor that corresponds to an elided constructor. + static ProgramStateRef + cleanupElidedDestructor(ProgramStateRef State, + const CXXBindTemporaryExpr *BTE, + const LocationContext *LC); + + /// Returns true if the given expression corresponds to a temporary that + /// was constructed for passing into an elidable copy/move constructor + /// and that constructor was actually elided. + static bool isDestructorElided(ProgramStateRef State, + const CXXBindTemporaryExpr *BTE, + const LocationContext *LC); + + /// Check if all objects under construction have been fully constructed + /// for the given context range (including FromLC, not including ToLC). + /// This is useful for assertions. Also checks if elided destructors + /// were cleaned up. + static bool areAllObjectsFullyConstructed(ProgramStateRef State, + const LocationContext *FromLC, + const LocationContext *ToLC); }; /// Traits for storing the call processing policy inside GDM. @@ -668,8 +820,8 @@ struct ProgramStateTrait<ReplayWithoutInlining> : static void *GDMIndex() { static int index = 0; return &index; } }; -} // end ento namespace +} // namespace ento -} // end clang namespace +} // namespace clang -#endif +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H |