106f32e7eSjoerg //===- ExprEngine.h - Path-Sensitive Expression-Level Dataflow --*- C++ -*-===// 206f32e7eSjoerg // 306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information. 506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606f32e7eSjoerg // 706f32e7eSjoerg //===----------------------------------------------------------------------===// 806f32e7eSjoerg // 906f32e7eSjoerg // This file defines a meta-engine for path-sensitive dataflow analysis that 1006f32e7eSjoerg // is built on CoreEngine, but provides the boilerplate to execute transfer 1106f32e7eSjoerg // functions and build the ExplodedGraph at the expression level. 1206f32e7eSjoerg // 1306f32e7eSjoerg //===----------------------------------------------------------------------===// 1406f32e7eSjoerg 1506f32e7eSjoerg #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H 1606f32e7eSjoerg #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H 1706f32e7eSjoerg 1806f32e7eSjoerg #include "clang/AST/Expr.h" 1906f32e7eSjoerg #include "clang/AST/Type.h" 2006f32e7eSjoerg #include "clang/Analysis/CFG.h" 2106f32e7eSjoerg #include "clang/Analysis/DomainSpecific/ObjCNoReturn.h" 2206f32e7eSjoerg #include "clang/Analysis/ProgramPoint.h" 2306f32e7eSjoerg #include "clang/Basic/LLVM.h" 24*13fbcb42Sjoerg #include "clang/StaticAnalyzer/Core/CheckerManager.h" 2506f32e7eSjoerg #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 2606f32e7eSjoerg #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" 2706f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 2806f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" 2906f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" 3006f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 3106f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 3206f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" 33*13fbcb42Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" 3406f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" 3506f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 3606f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" 3706f32e7eSjoerg #include "llvm/ADT/ArrayRef.h" 3806f32e7eSjoerg #include <cassert> 3906f32e7eSjoerg #include <utility> 4006f32e7eSjoerg 4106f32e7eSjoerg namespace clang { 4206f32e7eSjoerg 4306f32e7eSjoerg class AnalysisDeclContextManager; 4406f32e7eSjoerg class AnalyzerOptions; 4506f32e7eSjoerg class ASTContext; 46*13fbcb42Sjoerg class CFGBlock; 47*13fbcb42Sjoerg class CFGElement; 4806f32e7eSjoerg class ConstructionContext; 4906f32e7eSjoerg class CXXBindTemporaryExpr; 5006f32e7eSjoerg class CXXCatchStmt; 5106f32e7eSjoerg class CXXConstructExpr; 5206f32e7eSjoerg class CXXDeleteExpr; 5306f32e7eSjoerg class CXXNewExpr; 5406f32e7eSjoerg class CXXThisExpr; 5506f32e7eSjoerg class Decl; 5606f32e7eSjoerg class DeclStmt; 5706f32e7eSjoerg class GCCAsmStmt; 5806f32e7eSjoerg class LambdaExpr; 5906f32e7eSjoerg class LocationContext; 6006f32e7eSjoerg class MaterializeTemporaryExpr; 6106f32e7eSjoerg class MSAsmStmt; 6206f32e7eSjoerg class NamedDecl; 6306f32e7eSjoerg class ObjCAtSynchronizedStmt; 6406f32e7eSjoerg class ObjCForCollectionStmt; 6506f32e7eSjoerg class ObjCIvarRefExpr; 6606f32e7eSjoerg class ObjCMessageExpr; 6706f32e7eSjoerg class ReturnStmt; 6806f32e7eSjoerg class Stmt; 6906f32e7eSjoerg 7006f32e7eSjoerg namespace cross_tu { 7106f32e7eSjoerg 7206f32e7eSjoerg class CrossTranslationUnitContext; 7306f32e7eSjoerg 7406f32e7eSjoerg } // namespace cross_tu 7506f32e7eSjoerg 7606f32e7eSjoerg namespace ento { 7706f32e7eSjoerg 78*13fbcb42Sjoerg class AnalysisManager; 7906f32e7eSjoerg class BasicValueFactory; 80*13fbcb42Sjoerg class BlockCounter; 81*13fbcb42Sjoerg class BranchNodeBuilder; 8206f32e7eSjoerg class CallEvent; 8306f32e7eSjoerg class CheckerManager; 8406f32e7eSjoerg class ConstraintManager; 8506f32e7eSjoerg class CXXTempObjectRegion; 86*13fbcb42Sjoerg class EndOfFunctionNodeBuilder; 87*13fbcb42Sjoerg class ExplodedNodeSet; 88*13fbcb42Sjoerg class ExplodedNode; 89*13fbcb42Sjoerg class IndirectGotoNodeBuilder; 9006f32e7eSjoerg class MemRegion; 91*13fbcb42Sjoerg struct NodeBuilderContext; 92*13fbcb42Sjoerg class NodeBuilderWithSinks; 93*13fbcb42Sjoerg class ProgramState; 94*13fbcb42Sjoerg class ProgramStateManager; 9506f32e7eSjoerg class RegionAndSymbolInvalidationTraits; 9606f32e7eSjoerg class SymbolManager; 97*13fbcb42Sjoerg class SwitchNodeBuilder; 9806f32e7eSjoerg 9906f32e7eSjoerg /// Hints for figuring out of a call should be inlined during evalCall(). 10006f32e7eSjoerg struct EvalCallOptions { 10106f32e7eSjoerg /// This call is a constructor or a destructor for which we do not currently 10206f32e7eSjoerg /// compute the this-region correctly. 10306f32e7eSjoerg bool IsCtorOrDtorWithImproperlyModeledTargetRegion = false; 10406f32e7eSjoerg 10506f32e7eSjoerg /// This call is a constructor or a destructor for a single element within 10606f32e7eSjoerg /// an array, a part of array construction or destruction. 10706f32e7eSjoerg bool IsArrayCtorOrDtor = false; 10806f32e7eSjoerg 10906f32e7eSjoerg /// This call is a constructor or a destructor of a temporary value. 11006f32e7eSjoerg bool IsTemporaryCtorOrDtor = false; 11106f32e7eSjoerg 11206f32e7eSjoerg /// This call is a constructor for a temporary that is lifetime-extended 11306f32e7eSjoerg /// by binding it to a reference-type field within an aggregate, 11406f32e7eSjoerg /// for example 'A { const C &c; }; A a = { C() };' 11506f32e7eSjoerg bool IsTemporaryLifetimeExtendedViaAggregate = false; 11606f32e7eSjoerg 117*13fbcb42Sjoerg /// This call is a pre-C++17 elidable constructor that we failed to elide 118*13fbcb42Sjoerg /// because we failed to compute the target region into which 119*13fbcb42Sjoerg /// this constructor would have been ultimately elided. Analysis that 120*13fbcb42Sjoerg /// we perform in this case is still correct but it behaves differently, 121*13fbcb42Sjoerg /// as if copy elision is disabled. 122*13fbcb42Sjoerg bool IsElidableCtorThatHasNotBeenElided = false; 123*13fbcb42Sjoerg EvalCallOptionsEvalCallOptions12406f32e7eSjoerg EvalCallOptions() {} 12506f32e7eSjoerg }; 12606f32e7eSjoerg 127*13fbcb42Sjoerg class ExprEngine { 128*13fbcb42Sjoerg void anchor(); 129*13fbcb42Sjoerg 130*13fbcb42Sjoerg public: 131*13fbcb42Sjoerg /// The modes of inlining, which override the default analysis-wide settings. 132*13fbcb42Sjoerg enum InliningModes { 133*13fbcb42Sjoerg /// Follow the default settings for inlining callees. 134*13fbcb42Sjoerg Inline_Regular = 0, 135*13fbcb42Sjoerg 136*13fbcb42Sjoerg /// Do minimal inlining of callees. 137*13fbcb42Sjoerg Inline_Minimal = 0x1 138*13fbcb42Sjoerg }; 139*13fbcb42Sjoerg 14006f32e7eSjoerg private: 14106f32e7eSjoerg cross_tu::CrossTranslationUnitContext &CTU; 14206f32e7eSjoerg 14306f32e7eSjoerg AnalysisManager &AMgr; 14406f32e7eSjoerg 14506f32e7eSjoerg AnalysisDeclContextManager &AnalysisDeclContexts; 14606f32e7eSjoerg 14706f32e7eSjoerg CoreEngine Engine; 14806f32e7eSjoerg 14906f32e7eSjoerg /// G - the simulation graph. 15006f32e7eSjoerg ExplodedGraph &G; 15106f32e7eSjoerg 15206f32e7eSjoerg /// StateMgr - Object that manages the data for all created states. 15306f32e7eSjoerg ProgramStateManager StateMgr; 15406f32e7eSjoerg 15506f32e7eSjoerg /// SymMgr - Object that manages the symbol information. 15606f32e7eSjoerg SymbolManager &SymMgr; 15706f32e7eSjoerg 15806f32e7eSjoerg /// MRMgr - MemRegionManager object that creates memory regions. 15906f32e7eSjoerg MemRegionManager &MRMgr; 16006f32e7eSjoerg 16106f32e7eSjoerg /// svalBuilder - SValBuilder object that creates SVals from expressions. 16206f32e7eSjoerg SValBuilder &svalBuilder; 16306f32e7eSjoerg 16406f32e7eSjoerg unsigned int currStmtIdx = 0; 16506f32e7eSjoerg const NodeBuilderContext *currBldrCtx = nullptr; 16606f32e7eSjoerg 16706f32e7eSjoerg /// Helper object to determine if an Objective-C message expression 16806f32e7eSjoerg /// implicitly never returns. 16906f32e7eSjoerg ObjCNoReturn ObjCNoRet; 17006f32e7eSjoerg 17106f32e7eSjoerg /// The BugReporter associated with this engine. It is important that 17206f32e7eSjoerg /// this object be placed at the very end of member variables so that its 17306f32e7eSjoerg /// destructor is called before the rest of the ExprEngine is destroyed. 17406f32e7eSjoerg PathSensitiveBugReporter BR; 17506f32e7eSjoerg 17606f32e7eSjoerg /// The functions which have been analyzed through inlining. This is owned by 17706f32e7eSjoerg /// AnalysisConsumer. It can be null. 17806f32e7eSjoerg SetOfConstDecls *VisitedCallees; 17906f32e7eSjoerg 18006f32e7eSjoerg /// The flag, which specifies the mode of inlining for the engine. 18106f32e7eSjoerg InliningModes HowToInline; 18206f32e7eSjoerg 18306f32e7eSjoerg public: 18406f32e7eSjoerg ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, AnalysisManager &mgr, 18506f32e7eSjoerg SetOfConstDecls *VisitedCalleesIn, 18606f32e7eSjoerg FunctionSummariesTy *FS, InliningModes HowToInlineIn); 18706f32e7eSjoerg 188*13fbcb42Sjoerg virtual ~ExprEngine() = default; 18906f32e7eSjoerg 19006f32e7eSjoerg /// Returns true if there is still simulation state on the worklist. 19106f32e7eSjoerg bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) { 19206f32e7eSjoerg return Engine.ExecuteWorkList(L, Steps, nullptr); 19306f32e7eSjoerg } 19406f32e7eSjoerg 19506f32e7eSjoerg /// Execute the work list with an initial state. Nodes that reaches the exit 19606f32e7eSjoerg /// of the function are added into the Dst set, which represent the exit 19706f32e7eSjoerg /// state of the function call. Returns true if there is still simulation 19806f32e7eSjoerg /// state on the worklist. ExecuteWorkListWithInitialState(const LocationContext * L,unsigned Steps,ProgramStateRef InitState,ExplodedNodeSet & Dst)19906f32e7eSjoerg bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps, 20006f32e7eSjoerg ProgramStateRef InitState, 20106f32e7eSjoerg ExplodedNodeSet &Dst) { 20206f32e7eSjoerg return Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst); 20306f32e7eSjoerg } 20406f32e7eSjoerg 20506f32e7eSjoerg /// getContext - Return the ASTContext associated with this analysis. getContext()20606f32e7eSjoerg ASTContext &getContext() const { return AMgr.getASTContext(); } 20706f32e7eSjoerg getAnalysisManager()208*13fbcb42Sjoerg AnalysisManager &getAnalysisManager() { return AMgr; } 20906f32e7eSjoerg getAnalysisDeclContextManager()21006f32e7eSjoerg AnalysisDeclContextManager &getAnalysisDeclContextManager() { 21106f32e7eSjoerg return AMgr.getAnalysisDeclContextManager(); 21206f32e7eSjoerg } 21306f32e7eSjoerg getCheckerManager()21406f32e7eSjoerg CheckerManager &getCheckerManager() const { 21506f32e7eSjoerg return *AMgr.getCheckerManager(); 21606f32e7eSjoerg } 21706f32e7eSjoerg getSValBuilder()21806f32e7eSjoerg SValBuilder &getSValBuilder() { return svalBuilder; } 21906f32e7eSjoerg getBugReporter()22006f32e7eSjoerg BugReporter &getBugReporter() { return BR; } 22106f32e7eSjoerg 22206f32e7eSjoerg cross_tu::CrossTranslationUnitContext * getCrossTranslationUnitContext()223*13fbcb42Sjoerg getCrossTranslationUnitContext() { 22406f32e7eSjoerg return &CTU; 22506f32e7eSjoerg } 22606f32e7eSjoerg getBuilderContext()22706f32e7eSjoerg const NodeBuilderContext &getBuilderContext() { 22806f32e7eSjoerg assert(currBldrCtx); 22906f32e7eSjoerg return *currBldrCtx; 23006f32e7eSjoerg } 23106f32e7eSjoerg 23206f32e7eSjoerg const Stmt *getStmt() const; 23306f32e7eSjoerg 23406f32e7eSjoerg void GenerateAutoTransition(ExplodedNode *N); 23506f32e7eSjoerg void enqueueEndOfPath(ExplodedNodeSet &S); 23606f32e7eSjoerg void GenerateCallExitNode(ExplodedNode *N); 23706f32e7eSjoerg 23806f32e7eSjoerg 23906f32e7eSjoerg /// Dump graph to the specified filename. 24006f32e7eSjoerg /// If filename is empty, generate a temporary one. 24106f32e7eSjoerg /// \return The filename the graph is written into. 24206f32e7eSjoerg std::string DumpGraph(bool trim = false, StringRef Filename=""); 24306f32e7eSjoerg 24406f32e7eSjoerg /// Dump the graph consisting of the given nodes to a specified filename. 24506f32e7eSjoerg /// Generate a temporary filename if it's not provided. 24606f32e7eSjoerg /// \return The filename the graph is written into. 24706f32e7eSjoerg std::string DumpGraph(ArrayRef<const ExplodedNode *> Nodes, 24806f32e7eSjoerg StringRef Filename = ""); 24906f32e7eSjoerg 25006f32e7eSjoerg /// Visualize the ExplodedGraph created by executing the simulation. 25106f32e7eSjoerg void ViewGraph(bool trim = false); 25206f32e7eSjoerg 25306f32e7eSjoerg /// Visualize a trimmed ExplodedGraph that only contains paths to the given 25406f32e7eSjoerg /// nodes. 25506f32e7eSjoerg void ViewGraph(ArrayRef<const ExplodedNode *> Nodes); 25606f32e7eSjoerg 25706f32e7eSjoerg /// getInitialState - Return the initial state used for the root vertex 25806f32e7eSjoerg /// in the ExplodedGraph. 259*13fbcb42Sjoerg ProgramStateRef getInitialState(const LocationContext *InitLoc); 26006f32e7eSjoerg getGraph()26106f32e7eSjoerg ExplodedGraph &getGraph() { return G; } getGraph()26206f32e7eSjoerg const ExplodedGraph &getGraph() const { return G; } 26306f32e7eSjoerg 26406f32e7eSjoerg /// Run the analyzer's garbage collection - remove dead symbols and 26506f32e7eSjoerg /// bindings from the state. 26606f32e7eSjoerg /// 26706f32e7eSjoerg /// Checkers can participate in this process with two callbacks: 26806f32e7eSjoerg /// \c checkLiveSymbols and \c checkDeadSymbols. See the CheckerDocumentation 26906f32e7eSjoerg /// class for more information. 27006f32e7eSjoerg /// 27106f32e7eSjoerg /// \param Node The predecessor node, from which the processing should start. 27206f32e7eSjoerg /// \param Out The returned set of output nodes. 27306f32e7eSjoerg /// \param ReferenceStmt The statement which is about to be processed. 27406f32e7eSjoerg /// Everything needed for this statement should be considered live. 27506f32e7eSjoerg /// A null statement means that everything in child LocationContexts 27606f32e7eSjoerg /// is dead. 27706f32e7eSjoerg /// \param LC The location context of the \p ReferenceStmt. A null location 27806f32e7eSjoerg /// context means that we have reached the end of analysis and that 27906f32e7eSjoerg /// all statements and local variables should be considered dead. 28006f32e7eSjoerg /// \param DiagnosticStmt Used as a location for any warnings that should 28106f32e7eSjoerg /// occur while removing the dead (e.g. leaks). By default, the 28206f32e7eSjoerg /// \p ReferenceStmt is used. 28306f32e7eSjoerg /// \param K Denotes whether this is a pre- or post-statement purge. This 28406f32e7eSjoerg /// must only be ProgramPoint::PostStmtPurgeDeadSymbolsKind if an 28506f32e7eSjoerg /// entire location context is being cleared, in which case the 28606f32e7eSjoerg /// \p ReferenceStmt must either be a ReturnStmt or \c NULL. Otherwise, 28706f32e7eSjoerg /// it must be ProgramPoint::PreStmtPurgeDeadSymbolsKind (the default) 28806f32e7eSjoerg /// and \p ReferenceStmt must be valid (non-null). 28906f32e7eSjoerg void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out, 29006f32e7eSjoerg const Stmt *ReferenceStmt, const LocationContext *LC, 29106f32e7eSjoerg const Stmt *DiagnosticStmt = nullptr, 29206f32e7eSjoerg ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind); 29306f32e7eSjoerg 29406f32e7eSjoerg /// processCFGElement - Called by CoreEngine. Used to generate new successor 29506f32e7eSjoerg /// nodes by processing the 'effects' of a CFG element. 29606f32e7eSjoerg void processCFGElement(const CFGElement E, ExplodedNode *Pred, 297*13fbcb42Sjoerg unsigned StmtIdx, NodeBuilderContext *Ctx); 29806f32e7eSjoerg 29906f32e7eSjoerg void ProcessStmt(const Stmt *S, ExplodedNode *Pred); 30006f32e7eSjoerg 30106f32e7eSjoerg void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred); 30206f32e7eSjoerg 30306f32e7eSjoerg void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred); 30406f32e7eSjoerg 30506f32e7eSjoerg void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred); 30606f32e7eSjoerg 30706f32e7eSjoerg void ProcessNewAllocator(const CXXNewExpr *NE, ExplodedNode *Pred); 30806f32e7eSjoerg 30906f32e7eSjoerg void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D, 31006f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 31106f32e7eSjoerg void ProcessDeleteDtor(const CFGDeleteDtor D, 31206f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 31306f32e7eSjoerg void ProcessBaseDtor(const CFGBaseDtor D, 31406f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 31506f32e7eSjoerg void ProcessMemberDtor(const CFGMemberDtor D, 31606f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 31706f32e7eSjoerg void ProcessTemporaryDtor(const CFGTemporaryDtor D, 31806f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 31906f32e7eSjoerg 32006f32e7eSjoerg /// Called by CoreEngine when processing the entrance of a CFGBlock. 32106f32e7eSjoerg void processCFGBlockEntrance(const BlockEdge &L, 32206f32e7eSjoerg NodeBuilderWithSinks &nodeBuilder, 323*13fbcb42Sjoerg ExplodedNode *Pred); 32406f32e7eSjoerg 32506f32e7eSjoerg /// ProcessBranch - Called by CoreEngine. Used to generate successor 32606f32e7eSjoerg /// nodes by processing the 'effects' of a branch condition. 32706f32e7eSjoerg void processBranch(const Stmt *Condition, 32806f32e7eSjoerg NodeBuilderContext& BuilderCtx, 32906f32e7eSjoerg ExplodedNode *Pred, 33006f32e7eSjoerg ExplodedNodeSet &Dst, 33106f32e7eSjoerg const CFGBlock *DstT, 332*13fbcb42Sjoerg const CFGBlock *DstF); 33306f32e7eSjoerg 33406f32e7eSjoerg /// Called by CoreEngine. 33506f32e7eSjoerg /// Used to generate successor nodes for temporary destructors depending 33606f32e7eSjoerg /// on whether the corresponding constructor was visited. 33706f32e7eSjoerg void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, 33806f32e7eSjoerg NodeBuilderContext &BldCtx, 33906f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst, 34006f32e7eSjoerg const CFGBlock *DstT, 341*13fbcb42Sjoerg const CFGBlock *DstF); 34206f32e7eSjoerg 34306f32e7eSjoerg /// Called by CoreEngine. Used to processing branching behavior 34406f32e7eSjoerg /// at static initializers. 34506f32e7eSjoerg void processStaticInitializer(const DeclStmt *DS, 34606f32e7eSjoerg NodeBuilderContext& BuilderCtx, 34706f32e7eSjoerg ExplodedNode *Pred, 34806f32e7eSjoerg ExplodedNodeSet &Dst, 34906f32e7eSjoerg const CFGBlock *DstT, 350*13fbcb42Sjoerg const CFGBlock *DstF); 35106f32e7eSjoerg 35206f32e7eSjoerg /// processIndirectGoto - Called by CoreEngine. Used to generate successor 35306f32e7eSjoerg /// nodes by processing the 'effects' of a computed goto jump. 354*13fbcb42Sjoerg void processIndirectGoto(IndirectGotoNodeBuilder& builder); 35506f32e7eSjoerg 35606f32e7eSjoerg /// ProcessSwitch - Called by CoreEngine. Used to generate successor 35706f32e7eSjoerg /// nodes by processing the 'effects' of a switch statement. 358*13fbcb42Sjoerg void processSwitch(SwitchNodeBuilder& builder); 35906f32e7eSjoerg 36006f32e7eSjoerg /// Called by CoreEngine. Used to notify checkers that processing a 36106f32e7eSjoerg /// function has begun. Called for both inlined and and top-level functions. 36206f32e7eSjoerg void processBeginOfFunction(NodeBuilderContext &BC, 36306f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst, 364*13fbcb42Sjoerg const BlockEdge &L); 36506f32e7eSjoerg 36606f32e7eSjoerg /// Called by CoreEngine. Used to notify checkers that processing a 36706f32e7eSjoerg /// function has ended. Called for both inlined and and top-level functions. 36806f32e7eSjoerg void processEndOfFunction(NodeBuilderContext& BC, 36906f32e7eSjoerg ExplodedNode *Pred, 370*13fbcb42Sjoerg const ReturnStmt *RS = nullptr); 37106f32e7eSjoerg 37206f32e7eSjoerg /// Remove dead bindings/symbols before exiting a function. 37306f32e7eSjoerg void removeDeadOnEndOfFunction(NodeBuilderContext& BC, 37406f32e7eSjoerg ExplodedNode *Pred, 37506f32e7eSjoerg ExplodedNodeSet &Dst); 37606f32e7eSjoerg 37706f32e7eSjoerg /// Generate the entry node of the callee. 37806f32e7eSjoerg void processCallEnter(NodeBuilderContext& BC, CallEnter CE, 379*13fbcb42Sjoerg ExplodedNode *Pred); 38006f32e7eSjoerg 38106f32e7eSjoerg /// Generate the sequence of nodes that simulate the call exit and the post 38206f32e7eSjoerg /// visit for CallExpr. 383*13fbcb42Sjoerg void processCallExit(ExplodedNode *Pred); 38406f32e7eSjoerg 38506f32e7eSjoerg /// Called by CoreEngine when the analysis worklist has terminated. 386*13fbcb42Sjoerg void processEndWorklist(); 38706f32e7eSjoerg 38806f32e7eSjoerg /// evalAssume - Callback function invoked by the ConstraintManager when 38906f32e7eSjoerg /// making assumptions about state values. 39006f32e7eSjoerg ProgramStateRef processAssume(ProgramStateRef state, SVal cond, 391*13fbcb42Sjoerg bool assumption); 39206f32e7eSjoerg 39306f32e7eSjoerg /// processRegionChanges - Called by ProgramStateManager whenever a change is made 39406f32e7eSjoerg /// to the store. Used to update checkers that track region values. 39506f32e7eSjoerg ProgramStateRef 39606f32e7eSjoerg processRegionChanges(ProgramStateRef state, 39706f32e7eSjoerg const InvalidatedSymbols *invalidated, 39806f32e7eSjoerg ArrayRef<const MemRegion *> ExplicitRegions, 39906f32e7eSjoerg ArrayRef<const MemRegion *> Regions, 40006f32e7eSjoerg const LocationContext *LCtx, 401*13fbcb42Sjoerg const CallEvent *Call); 402*13fbcb42Sjoerg 403*13fbcb42Sjoerg inline ProgramStateRef processRegionChange(ProgramStateRef state,const MemRegion * MR,const LocationContext * LCtx)404*13fbcb42Sjoerg processRegionChange(ProgramStateRef state, 405*13fbcb42Sjoerg const MemRegion* MR, 406*13fbcb42Sjoerg const LocationContext *LCtx) { 407*13fbcb42Sjoerg return processRegionChanges(state, nullptr, MR, MR, LCtx, nullptr); 408*13fbcb42Sjoerg } 40906f32e7eSjoerg 41006f32e7eSjoerg /// printJson - Called by ProgramStateManager to print checker-specific data. 41106f32e7eSjoerg void printJson(raw_ostream &Out, ProgramStateRef State, 41206f32e7eSjoerg const LocationContext *LCtx, const char *NL, 413*13fbcb42Sjoerg unsigned int Space, bool IsDot) const; 41406f32e7eSjoerg getStateManager()415*13fbcb42Sjoerg ProgramStateManager &getStateManager() { return StateMgr; } 41606f32e7eSjoerg getStoreManager()41706f32e7eSjoerg StoreManager &getStoreManager() { return StateMgr.getStoreManager(); } 41806f32e7eSjoerg getConstraintManager()41906f32e7eSjoerg ConstraintManager &getConstraintManager() { 42006f32e7eSjoerg return StateMgr.getConstraintManager(); 42106f32e7eSjoerg } 42206f32e7eSjoerg 42306f32e7eSjoerg // FIXME: Remove when we migrate over to just using SValBuilder. getBasicVals()42406f32e7eSjoerg BasicValueFactory &getBasicVals() { 42506f32e7eSjoerg return StateMgr.getBasicVals(); 42606f32e7eSjoerg } 42706f32e7eSjoerg getSymbolManager()42806f32e7eSjoerg SymbolManager &getSymbolManager() { return SymMgr; } getRegionManager()42906f32e7eSjoerg MemRegionManager &getRegionManager() { return MRMgr; } 43006f32e7eSjoerg getNoteTags()43106f32e7eSjoerg NoteTag::Factory &getNoteTags() { return Engine.getNoteTags(); } 43206f32e7eSjoerg 43306f32e7eSjoerg 43406f32e7eSjoerg // Functions for external checking of whether we have unfinished work wasBlocksExhausted()43506f32e7eSjoerg bool wasBlocksExhausted() const { return Engine.wasBlocksExhausted(); } hasEmptyWorkList()43606f32e7eSjoerg bool hasEmptyWorkList() const { return !Engine.getWorkList()->hasWork(); } hasWorkRemaining()43706f32e7eSjoerg bool hasWorkRemaining() const { return Engine.hasWorkRemaining(); } 43806f32e7eSjoerg getCoreEngine()43906f32e7eSjoerg const CoreEngine &getCoreEngine() const { return Engine; } 44006f32e7eSjoerg 44106f32e7eSjoerg public: 44206f32e7eSjoerg /// Visit - Transfer function logic for all statements. Dispatches to 44306f32e7eSjoerg /// other functions that handle specific kinds of statements. 44406f32e7eSjoerg void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst); 44506f32e7eSjoerg 44606f32e7eSjoerg /// VisitArraySubscriptExpr - Transfer function for array accesses. 44706f32e7eSjoerg void VisitArraySubscriptExpr(const ArraySubscriptExpr *Ex, 44806f32e7eSjoerg ExplodedNode *Pred, 44906f32e7eSjoerg ExplodedNodeSet &Dst); 45006f32e7eSjoerg 45106f32e7eSjoerg /// VisitGCCAsmStmt - Transfer function logic for inline asm. 45206f32e7eSjoerg void VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, 45306f32e7eSjoerg ExplodedNodeSet &Dst); 45406f32e7eSjoerg 45506f32e7eSjoerg /// VisitMSAsmStmt - Transfer function logic for MS inline asm. 45606f32e7eSjoerg void VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred, 45706f32e7eSjoerg ExplodedNodeSet &Dst); 45806f32e7eSjoerg 45906f32e7eSjoerg /// VisitBlockExpr - Transfer function logic for BlockExprs. 46006f32e7eSjoerg void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, 46106f32e7eSjoerg ExplodedNodeSet &Dst); 46206f32e7eSjoerg 46306f32e7eSjoerg /// VisitLambdaExpr - Transfer function logic for LambdaExprs. 46406f32e7eSjoerg void VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred, 46506f32e7eSjoerg ExplodedNodeSet &Dst); 46606f32e7eSjoerg 46706f32e7eSjoerg /// VisitBinaryOperator - Transfer function logic for binary operators. 46806f32e7eSjoerg void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode *Pred, 46906f32e7eSjoerg ExplodedNodeSet &Dst); 47006f32e7eSjoerg 47106f32e7eSjoerg 47206f32e7eSjoerg /// VisitCall - Transfer function for function calls. 47306f32e7eSjoerg void VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, 47406f32e7eSjoerg ExplodedNodeSet &Dst); 47506f32e7eSjoerg 47606f32e7eSjoerg /// VisitCast - Transfer function logic for all casts (implicit and explicit). 47706f32e7eSjoerg void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, 47806f32e7eSjoerg ExplodedNodeSet &Dst); 47906f32e7eSjoerg 48006f32e7eSjoerg /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. 48106f32e7eSjoerg void VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, 48206f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 48306f32e7eSjoerg 48406f32e7eSjoerg /// Transfer function logic for DeclRefExprs and BlockDeclRefExprs. 48506f32e7eSjoerg void VisitCommonDeclRefExpr(const Expr *DR, const NamedDecl *D, 48606f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 48706f32e7eSjoerg 48806f32e7eSjoerg /// VisitDeclStmt - Transfer function logic for DeclStmts. 48906f32e7eSjoerg void VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, 49006f32e7eSjoerg ExplodedNodeSet &Dst); 49106f32e7eSjoerg 49206f32e7eSjoerg /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose 49306f32e7eSjoerg void VisitGuardedExpr(const Expr *Ex, const Expr *L, const Expr *R, 49406f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 49506f32e7eSjoerg 49606f32e7eSjoerg void VisitInitListExpr(const InitListExpr *E, ExplodedNode *Pred, 49706f32e7eSjoerg ExplodedNodeSet &Dst); 49806f32e7eSjoerg 49906f32e7eSjoerg /// VisitLogicalExpr - Transfer function logic for '&&', '||' 50006f32e7eSjoerg void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, 50106f32e7eSjoerg ExplodedNodeSet &Dst); 50206f32e7eSjoerg 50306f32e7eSjoerg /// VisitMemberExpr - Transfer function for member expressions. 50406f32e7eSjoerg void VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, 50506f32e7eSjoerg ExplodedNodeSet &Dst); 50606f32e7eSjoerg 50706f32e7eSjoerg /// VisitAtomicExpr - Transfer function for builtin atomic expressions 50806f32e7eSjoerg void VisitAtomicExpr(const AtomicExpr *E, ExplodedNode *Pred, 50906f32e7eSjoerg ExplodedNodeSet &Dst); 51006f32e7eSjoerg 51106f32e7eSjoerg /// Transfer function logic for ObjCAtSynchronizedStmts. 51206f32e7eSjoerg void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, 51306f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 51406f32e7eSjoerg 51506f32e7eSjoerg /// Transfer function logic for computing the lvalue of an Objective-C ivar. 51606f32e7eSjoerg void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *DR, ExplodedNode *Pred, 51706f32e7eSjoerg ExplodedNodeSet &Dst); 51806f32e7eSjoerg 51906f32e7eSjoerg /// VisitObjCForCollectionStmt - Transfer function logic for 52006f32e7eSjoerg /// ObjCForCollectionStmt. 52106f32e7eSjoerg void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, 52206f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 52306f32e7eSjoerg 52406f32e7eSjoerg void VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred, 52506f32e7eSjoerg ExplodedNodeSet &Dst); 52606f32e7eSjoerg 52706f32e7eSjoerg /// VisitReturnStmt - Transfer function logic for return statements. 52806f32e7eSjoerg void VisitReturnStmt(const ReturnStmt *R, ExplodedNode *Pred, 52906f32e7eSjoerg ExplodedNodeSet &Dst); 53006f32e7eSjoerg 53106f32e7eSjoerg /// VisitOffsetOfExpr - Transfer function for offsetof. 53206f32e7eSjoerg void VisitOffsetOfExpr(const OffsetOfExpr *Ex, ExplodedNode *Pred, 53306f32e7eSjoerg ExplodedNodeSet &Dst); 53406f32e7eSjoerg 53506f32e7eSjoerg /// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof. 53606f32e7eSjoerg void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, 53706f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 53806f32e7eSjoerg 53906f32e7eSjoerg /// VisitUnaryOperator - Transfer function logic for unary operators. 54006f32e7eSjoerg void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode *Pred, 54106f32e7eSjoerg ExplodedNodeSet &Dst); 54206f32e7eSjoerg 54306f32e7eSjoerg /// Handle ++ and -- (both pre- and post-increment). 54406f32e7eSjoerg void VisitIncrementDecrementOperator(const UnaryOperator* U, 54506f32e7eSjoerg ExplodedNode *Pred, 54606f32e7eSjoerg ExplodedNodeSet &Dst); 54706f32e7eSjoerg 54806f32e7eSjoerg void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE, 54906f32e7eSjoerg ExplodedNodeSet &PreVisit, 55006f32e7eSjoerg ExplodedNodeSet &Dst); 55106f32e7eSjoerg 55206f32e7eSjoerg void VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, 55306f32e7eSjoerg ExplodedNodeSet &Dst); 55406f32e7eSjoerg 55506f32e7eSjoerg void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, 55606f32e7eSjoerg ExplodedNodeSet & Dst); 55706f32e7eSjoerg 55806f32e7eSjoerg void VisitCXXConstructExpr(const CXXConstructExpr *E, ExplodedNode *Pred, 55906f32e7eSjoerg ExplodedNodeSet &Dst); 56006f32e7eSjoerg 561*13fbcb42Sjoerg void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E, 562*13fbcb42Sjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst); 563*13fbcb42Sjoerg 56406f32e7eSjoerg void VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest, 56506f32e7eSjoerg const Stmt *S, bool IsBaseDtor, 56606f32e7eSjoerg ExplodedNode *Pred, ExplodedNodeSet &Dst, 56706f32e7eSjoerg EvalCallOptions &Options); 56806f32e7eSjoerg 56906f32e7eSjoerg void VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, 57006f32e7eSjoerg ExplodedNode *Pred, 57106f32e7eSjoerg ExplodedNodeSet &Dst); 57206f32e7eSjoerg 57306f32e7eSjoerg void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, 57406f32e7eSjoerg ExplodedNodeSet &Dst); 57506f32e7eSjoerg 57606f32e7eSjoerg void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred, 57706f32e7eSjoerg ExplodedNodeSet &Dst); 57806f32e7eSjoerg 57906f32e7eSjoerg /// Create a C++ temporary object for an rvalue. 58006f32e7eSjoerg void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, 58106f32e7eSjoerg ExplodedNode *Pred, 58206f32e7eSjoerg ExplodedNodeSet &Dst); 58306f32e7eSjoerg 58406f32e7eSjoerg /// evalEagerlyAssumeBinOpBifurcation - Given the nodes in 'Src', eagerly assume symbolic 58506f32e7eSjoerg /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) 58606f32e7eSjoerg /// with those assumptions. 58706f32e7eSjoerg void evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, 58806f32e7eSjoerg const Expr *Ex); 58906f32e7eSjoerg 59006f32e7eSjoerg static std::pair<const ProgramPointTag *, const ProgramPointTag *> 59106f32e7eSjoerg geteagerlyAssumeBinOpBifurcationTags(); 59206f32e7eSjoerg evalMinus(SVal X)59306f32e7eSjoerg SVal evalMinus(SVal X) { 59406f32e7eSjoerg return X.isValid() ? svalBuilder.evalMinus(X.castAs<NonLoc>()) : X; 59506f32e7eSjoerg } 59606f32e7eSjoerg evalComplement(SVal X)59706f32e7eSjoerg SVal evalComplement(SVal X) { 59806f32e7eSjoerg return X.isValid() ? svalBuilder.evalComplement(X.castAs<NonLoc>()) : X; 59906f32e7eSjoerg } 60006f32e7eSjoerg 60106f32e7eSjoerg ProgramStateRef handleLValueBitCast(ProgramStateRef state, const Expr *Ex, 60206f32e7eSjoerg const LocationContext *LCtx, QualType T, 60306f32e7eSjoerg QualType ExTy, const CastExpr *CastE, 60406f32e7eSjoerg StmtNodeBuilder &Bldr, 60506f32e7eSjoerg ExplodedNode *Pred); 60606f32e7eSjoerg 60706f32e7eSjoerg ProgramStateRef handleLVectorSplat(ProgramStateRef state, 60806f32e7eSjoerg const LocationContext *LCtx, 60906f32e7eSjoerg const CastExpr *CastE, 61006f32e7eSjoerg StmtNodeBuilder &Bldr, 61106f32e7eSjoerg ExplodedNode *Pred); 61206f32e7eSjoerg 61306f32e7eSjoerg void handleUOExtension(ExplodedNodeSet::iterator I, 61406f32e7eSjoerg const UnaryOperator* U, 61506f32e7eSjoerg StmtNodeBuilder &Bldr); 61606f32e7eSjoerg 61706f32e7eSjoerg public: evalBinOp(ProgramStateRef state,BinaryOperator::Opcode op,NonLoc L,NonLoc R,QualType T)61806f32e7eSjoerg SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, 61906f32e7eSjoerg NonLoc L, NonLoc R, QualType T) { 62006f32e7eSjoerg return svalBuilder.evalBinOpNN(state, op, L, R, T); 62106f32e7eSjoerg } 62206f32e7eSjoerg evalBinOp(ProgramStateRef state,BinaryOperator::Opcode op,NonLoc L,SVal R,QualType T)62306f32e7eSjoerg SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, 62406f32e7eSjoerg NonLoc L, SVal R, QualType T) { 62506f32e7eSjoerg return R.isValid() ? svalBuilder.evalBinOpNN(state, op, L, 62606f32e7eSjoerg R.castAs<NonLoc>(), T) : R; 62706f32e7eSjoerg } 62806f32e7eSjoerg evalBinOp(ProgramStateRef ST,BinaryOperator::Opcode Op,SVal LHS,SVal RHS,QualType T)62906f32e7eSjoerg SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op, 63006f32e7eSjoerg SVal LHS, SVal RHS, QualType T) { 63106f32e7eSjoerg return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T); 63206f32e7eSjoerg } 63306f32e7eSjoerg 63406f32e7eSjoerg /// By looking at a certain item that may be potentially part of an object's 63506f32e7eSjoerg /// ConstructionContext, retrieve such object's location. A particular 63606f32e7eSjoerg /// statement can be transparently passed as \p Item in most cases. 63706f32e7eSjoerg static Optional<SVal> 63806f32e7eSjoerg getObjectUnderConstruction(ProgramStateRef State, 63906f32e7eSjoerg const ConstructionContextItem &Item, 64006f32e7eSjoerg const LocationContext *LC); 64106f32e7eSjoerg 64206f32e7eSjoerg /// Call PointerEscape callback when a value escapes as a result of bind. 643*13fbcb42Sjoerg ProgramStateRef processPointerEscapedOnBind( 644*13fbcb42Sjoerg ProgramStateRef State, ArrayRef<std::pair<SVal, SVal>> LocAndVals, 645*13fbcb42Sjoerg const LocationContext *LCtx, PointerEscapeKind Kind, 646*13fbcb42Sjoerg const CallEvent *Call); 647*13fbcb42Sjoerg 64806f32e7eSjoerg /// Call PointerEscape callback when a value escapes as a result of 64906f32e7eSjoerg /// region invalidation. 65006f32e7eSjoerg /// \param[in] ITraits Specifies invalidation traits for regions/symbols. 65106f32e7eSjoerg ProgramStateRef notifyCheckersOfPointerEscape( 65206f32e7eSjoerg ProgramStateRef State, 65306f32e7eSjoerg const InvalidatedSymbols *Invalidated, 65406f32e7eSjoerg ArrayRef<const MemRegion *> ExplicitRegions, 65506f32e7eSjoerg const CallEvent *Call, 656*13fbcb42Sjoerg RegionAndSymbolInvalidationTraits &ITraits); 657*13fbcb42Sjoerg 658*13fbcb42Sjoerg private: 659*13fbcb42Sjoerg /// evalBind - Handle the semantics of binding a value to a specific location. 660*13fbcb42Sjoerg /// This method is used by evalStore, VisitDeclStmt, and others. 661*13fbcb42Sjoerg void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred, 662*13fbcb42Sjoerg SVal location, SVal Val, bool atDeclInit = false, 663*13fbcb42Sjoerg const ProgramPoint *PP = nullptr); 664*13fbcb42Sjoerg 665*13fbcb42Sjoerg ProgramStateRef 666*13fbcb42Sjoerg processPointerEscapedOnBind(ProgramStateRef State, 667*13fbcb42Sjoerg SVal Loc, SVal Val, 668*13fbcb42Sjoerg const LocationContext *LCtx); 66906f32e7eSjoerg 67006f32e7eSjoerg /// A simple wrapper when you only need to notify checkers of pointer-escape 671*13fbcb42Sjoerg /// of some values. 672*13fbcb42Sjoerg ProgramStateRef escapeValues(ProgramStateRef State, ArrayRef<SVal> Vs, 673*13fbcb42Sjoerg PointerEscapeKind K, 674*13fbcb42Sjoerg const CallEvent *Call = nullptr) const; 67506f32e7eSjoerg 67606f32e7eSjoerg public: 67706f32e7eSjoerg // FIXME: 'tag' should be removed, and a LocationContext should be used 67806f32e7eSjoerg // instead. 67906f32e7eSjoerg // FIXME: Comment on the meaning of the arguments, when 'St' may not 68006f32e7eSjoerg // be the same as Pred->state, and when 'location' may not be the 68106f32e7eSjoerg // same as state->getLValue(Ex). 68206f32e7eSjoerg /// Simulate a read of the result of Ex. 68306f32e7eSjoerg void evalLoad(ExplodedNodeSet &Dst, 68406f32e7eSjoerg const Expr *NodeEx, /* Eventually will be a CFGStmt */ 68506f32e7eSjoerg const Expr *BoundExpr, 68606f32e7eSjoerg ExplodedNode *Pred, 68706f32e7eSjoerg ProgramStateRef St, 68806f32e7eSjoerg SVal location, 68906f32e7eSjoerg const ProgramPointTag *tag = nullptr, 69006f32e7eSjoerg QualType LoadTy = QualType()); 69106f32e7eSjoerg 69206f32e7eSjoerg // FIXME: 'tag' should be removed, and a LocationContext should be used 69306f32e7eSjoerg // instead. 69406f32e7eSjoerg void evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, const Expr *StoreE, 69506f32e7eSjoerg ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val, 69606f32e7eSjoerg const ProgramPointTag *tag = nullptr); 69706f32e7eSjoerg 69806f32e7eSjoerg /// Return the CFG element corresponding to the worklist element 69906f32e7eSjoerg /// that is currently being processed by ExprEngine. getCurrentCFGElement()70006f32e7eSjoerg CFGElement getCurrentCFGElement() { 70106f32e7eSjoerg return (*currBldrCtx->getBlock())[currStmtIdx]; 70206f32e7eSjoerg } 70306f32e7eSjoerg 70406f32e7eSjoerg /// Create a new state in which the call return value is binded to the 70506f32e7eSjoerg /// call origin expression. 70606f32e7eSjoerg ProgramStateRef bindReturnValue(const CallEvent &Call, 70706f32e7eSjoerg const LocationContext *LCtx, 70806f32e7eSjoerg ProgramStateRef State); 70906f32e7eSjoerg 71006f32e7eSjoerg /// Evaluate a call, running pre- and post-call checkers and allowing checkers 71106f32e7eSjoerg /// to be responsible for handling the evaluation of the call itself. 71206f32e7eSjoerg void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, 71306f32e7eSjoerg const CallEvent &Call); 71406f32e7eSjoerg 71506f32e7eSjoerg /// Default implementation of call evaluation. 71606f32e7eSjoerg void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred, 71706f32e7eSjoerg const CallEvent &Call, 71806f32e7eSjoerg const EvalCallOptions &CallOpts = {}); 71906f32e7eSjoerg 720*13fbcb42Sjoerg /// Find location of the object that is being constructed by a given 721*13fbcb42Sjoerg /// constructor. This should ideally always succeed but due to not being 722*13fbcb42Sjoerg /// fully implemented it sometimes indicates that it failed via its 723*13fbcb42Sjoerg /// out-parameter CallOpts; in such cases a fake temporary region is 724*13fbcb42Sjoerg /// returned, which is better than nothing but does not represent 725*13fbcb42Sjoerg /// the actual behavior of the program. 726*13fbcb42Sjoerg SVal computeObjectUnderConstruction( 727*13fbcb42Sjoerg const Expr *E, ProgramStateRef State, const LocationContext *LCtx, 728*13fbcb42Sjoerg const ConstructionContext *CC, EvalCallOptions &CallOpts); 729*13fbcb42Sjoerg 730*13fbcb42Sjoerg /// Update the program state with all the path-sensitive information 731*13fbcb42Sjoerg /// that's necessary to perform construction of an object with a given 732*13fbcb42Sjoerg /// syntactic construction context. V and CallOpts have to be obtained from 733*13fbcb42Sjoerg /// computeObjectUnderConstruction() invoked with the same set of 734*13fbcb42Sjoerg /// the remaining arguments (E, State, LCtx, CC). 735*13fbcb42Sjoerg ProgramStateRef updateObjectsUnderConstruction( 736*13fbcb42Sjoerg SVal V, const Expr *E, ProgramStateRef State, const LocationContext *LCtx, 737*13fbcb42Sjoerg const ConstructionContext *CC, const EvalCallOptions &CallOpts); 738*13fbcb42Sjoerg 739*13fbcb42Sjoerg /// A convenient wrapper around computeObjectUnderConstruction 740*13fbcb42Sjoerg /// and updateObjectsUnderConstruction. handleConstructionContext(const Expr * E,ProgramStateRef State,const LocationContext * LCtx,const ConstructionContext * CC,EvalCallOptions & CallOpts)741*13fbcb42Sjoerg std::pair<ProgramStateRef, SVal> handleConstructionContext( 742*13fbcb42Sjoerg const Expr *E, ProgramStateRef State, const LocationContext *LCtx, 743*13fbcb42Sjoerg const ConstructionContext *CC, EvalCallOptions &CallOpts) { 744*13fbcb42Sjoerg SVal V = computeObjectUnderConstruction(E, State, LCtx, CC, CallOpts); 745*13fbcb42Sjoerg return std::make_pair( 746*13fbcb42Sjoerg updateObjectsUnderConstruction(V, E, State, LCtx, CC, CallOpts), V); 747*13fbcb42Sjoerg } 748*13fbcb42Sjoerg 74906f32e7eSjoerg private: 75006f32e7eSjoerg ProgramStateRef finishArgumentConstruction(ProgramStateRef State, 75106f32e7eSjoerg const CallEvent &Call); 75206f32e7eSjoerg void finishArgumentConstruction(ExplodedNodeSet &Dst, ExplodedNode *Pred, 75306f32e7eSjoerg const CallEvent &Call); 75406f32e7eSjoerg 75506f32e7eSjoerg void evalLoadCommon(ExplodedNodeSet &Dst, 75606f32e7eSjoerg const Expr *NodeEx, /* Eventually will be a CFGStmt */ 75706f32e7eSjoerg const Expr *BoundEx, 75806f32e7eSjoerg ExplodedNode *Pred, 75906f32e7eSjoerg ProgramStateRef St, 76006f32e7eSjoerg SVal location, 76106f32e7eSjoerg const ProgramPointTag *tag, 76206f32e7eSjoerg QualType LoadTy); 76306f32e7eSjoerg 76406f32e7eSjoerg void evalLocation(ExplodedNodeSet &Dst, 76506f32e7eSjoerg const Stmt *NodeEx, /* This will eventually be a CFGStmt */ 76606f32e7eSjoerg const Stmt *BoundEx, 76706f32e7eSjoerg ExplodedNode *Pred, 76806f32e7eSjoerg ProgramStateRef St, 76906f32e7eSjoerg SVal location, 77006f32e7eSjoerg bool isLoad); 77106f32e7eSjoerg 77206f32e7eSjoerg /// Count the stack depth and determine if the call is recursive. 77306f32e7eSjoerg void examineStackFrames(const Decl *D, const LocationContext *LCtx, 77406f32e7eSjoerg bool &IsRecursive, unsigned &StackDepth); 77506f32e7eSjoerg 77606f32e7eSjoerg enum CallInlinePolicy { 77706f32e7eSjoerg CIP_Allowed, 77806f32e7eSjoerg CIP_DisallowedOnce, 77906f32e7eSjoerg CIP_DisallowedAlways 78006f32e7eSjoerg }; 78106f32e7eSjoerg 78206f32e7eSjoerg /// See if a particular call should be inlined, by only looking 78306f32e7eSjoerg /// at the call event and the current state of analysis. 78406f32e7eSjoerg CallInlinePolicy mayInlineCallKind(const CallEvent &Call, 78506f32e7eSjoerg const ExplodedNode *Pred, 78606f32e7eSjoerg AnalyzerOptions &Opts, 78706f32e7eSjoerg const EvalCallOptions &CallOpts); 78806f32e7eSjoerg 78906f32e7eSjoerg /// See if the given AnalysisDeclContext is built for a function that we 79006f32e7eSjoerg /// should always inline simply because it's small enough. 79106f32e7eSjoerg /// Apart from "small" functions, we also have "large" functions 79206f32e7eSjoerg /// (cf. isLarge()), some of which are huge (cf. isHuge()), and we classify 79306f32e7eSjoerg /// the remaining functions as "medium". 79406f32e7eSjoerg bool isSmall(AnalysisDeclContext *ADC) const; 79506f32e7eSjoerg 79606f32e7eSjoerg /// See if the given AnalysisDeclContext is built for a function that we 79706f32e7eSjoerg /// should inline carefully because it looks pretty large. 79806f32e7eSjoerg bool isLarge(AnalysisDeclContext *ADC) const; 79906f32e7eSjoerg 80006f32e7eSjoerg /// See if the given AnalysisDeclContext is built for a function that we 80106f32e7eSjoerg /// should never inline because it's legit gigantic. 80206f32e7eSjoerg bool isHuge(AnalysisDeclContext *ADC) const; 80306f32e7eSjoerg 80406f32e7eSjoerg /// See if the given AnalysisDeclContext is built for a function that we 80506f32e7eSjoerg /// should inline, just by looking at the declaration of the function. 80606f32e7eSjoerg bool mayInlineDecl(AnalysisDeclContext *ADC) const; 80706f32e7eSjoerg 80806f32e7eSjoerg /// Checks our policies and decides weither the given call should be inlined. 80906f32e7eSjoerg bool shouldInlineCall(const CallEvent &Call, const Decl *D, 81006f32e7eSjoerg const ExplodedNode *Pred, 81106f32e7eSjoerg const EvalCallOptions &CallOpts = {}); 81206f32e7eSjoerg 81306f32e7eSjoerg bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, 81406f32e7eSjoerg ExplodedNode *Pred, ProgramStateRef State); 81506f32e7eSjoerg 81606f32e7eSjoerg /// Conservatively evaluate call by invalidating regions and binding 81706f32e7eSjoerg /// a conjured return value. 81806f32e7eSjoerg void conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr, 81906f32e7eSjoerg ExplodedNode *Pred, ProgramStateRef State); 82006f32e7eSjoerg 82106f32e7eSjoerg /// Either inline or process the call conservatively (or both), based 82206f32e7eSjoerg /// on DynamicDispatchBifurcation data. 82306f32e7eSjoerg void BifurcateCall(const MemRegion *BifurReg, 82406f32e7eSjoerg const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, 82506f32e7eSjoerg ExplodedNode *Pred); 82606f32e7eSjoerg 82706f32e7eSjoerg bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC); 82806f32e7eSjoerg 82906f32e7eSjoerg /// Models a trivial copy or move constructor or trivial assignment operator 83006f32e7eSjoerg /// call with a simple bind. 83106f32e7eSjoerg void performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, 83206f32e7eSjoerg const CallEvent &Call); 83306f32e7eSjoerg 83406f32e7eSjoerg /// If the value of the given expression \p InitWithAdjustments is a NonLoc, 83506f32e7eSjoerg /// copy it into a new temporary object region, and replace the value of the 83606f32e7eSjoerg /// expression with that. 83706f32e7eSjoerg /// 83806f32e7eSjoerg /// If \p Result is provided, the new region will be bound to this expression 83906f32e7eSjoerg /// instead of \p InitWithAdjustments. 84006f32e7eSjoerg /// 84106f32e7eSjoerg /// Returns the temporary region with adjustments into the optional 84206f32e7eSjoerg /// OutRegionWithAdjustments out-parameter if a new region was indeed needed, 84306f32e7eSjoerg /// otherwise sets it to nullptr. 84406f32e7eSjoerg ProgramStateRef createTemporaryRegionIfNeeded( 84506f32e7eSjoerg ProgramStateRef State, const LocationContext *LC, 84606f32e7eSjoerg const Expr *InitWithAdjustments, const Expr *Result = nullptr, 84706f32e7eSjoerg const SubRegion **OutRegionWithAdjustments = nullptr); 84806f32e7eSjoerg 84906f32e7eSjoerg /// Returns a region representing the first element of a (possibly 85006f32e7eSjoerg /// multi-dimensional) array, for the purposes of element construction or 85106f32e7eSjoerg /// destruction. 85206f32e7eSjoerg /// 85306f32e7eSjoerg /// On return, \p Ty will be set to the base type of the array. 85406f32e7eSjoerg /// 85506f32e7eSjoerg /// If the type is not an array type at all, the original value is returned. 85606f32e7eSjoerg /// Otherwise the "IsArray" flag is set. 85706f32e7eSjoerg static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue, 85806f32e7eSjoerg QualType &Ty, bool &IsArray); 85906f32e7eSjoerg 86006f32e7eSjoerg /// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG 86106f32e7eSjoerg /// block to find the constructor expression that directly constructed into 86206f32e7eSjoerg /// the storage for this statement. Returns null if the constructor for this 86306f32e7eSjoerg /// statement created a temporary object region rather than directly 86406f32e7eSjoerg /// constructing into an existing region. 86506f32e7eSjoerg const CXXConstructExpr *findDirectConstructorForCurrentCFGElement(); 86606f32e7eSjoerg 867*13fbcb42Sjoerg /// Common code that handles either a CXXConstructExpr or a 868*13fbcb42Sjoerg /// CXXInheritedCtorInitExpr. 869*13fbcb42Sjoerg void handleConstructor(const Expr *E, ExplodedNode *Pred, 870*13fbcb42Sjoerg ExplodedNodeSet &Dst); 87106f32e7eSjoerg 872*13fbcb42Sjoerg public: 873*13fbcb42Sjoerg /// Note whether this loop has any more iteratios to model. These methods are 874*13fbcb42Sjoerg /// essentially an interface for a GDM trait. Further reading in 875*13fbcb42Sjoerg /// ExprEngine::VisitObjCForCollectionStmt(). 876*13fbcb42Sjoerg LLVM_NODISCARD static ProgramStateRef 877*13fbcb42Sjoerg setWhetherHasMoreIteration(ProgramStateRef State, 878*13fbcb42Sjoerg const ObjCForCollectionStmt *O, 879*13fbcb42Sjoerg const LocationContext *LC, bool HasMoreIteraton); 880*13fbcb42Sjoerg 881*13fbcb42Sjoerg LLVM_NODISCARD static ProgramStateRef 882*13fbcb42Sjoerg removeIterationState(ProgramStateRef State, const ObjCForCollectionStmt *O, 883*13fbcb42Sjoerg const LocationContext *LC); 884*13fbcb42Sjoerg 885*13fbcb42Sjoerg LLVM_NODISCARD static bool hasMoreIteration(ProgramStateRef State, 886*13fbcb42Sjoerg const ObjCForCollectionStmt *O, 887*13fbcb42Sjoerg const LocationContext *LC); 888*13fbcb42Sjoerg private: 88906f32e7eSjoerg /// Store the location of a C++ object corresponding to a statement 89006f32e7eSjoerg /// until the statement is actually encountered. For example, if a DeclStmt 89106f32e7eSjoerg /// has CXXConstructExpr as its initializer, the object would be considered 89206f32e7eSjoerg /// to be "under construction" between CXXConstructExpr and DeclStmt. 89306f32e7eSjoerg /// This allows, among other things, to keep bindings to variable's fields 89406f32e7eSjoerg /// made within the constructor alive until its declaration actually 89506f32e7eSjoerg /// goes into scope. 89606f32e7eSjoerg static ProgramStateRef 89706f32e7eSjoerg addObjectUnderConstruction(ProgramStateRef State, 89806f32e7eSjoerg const ConstructionContextItem &Item, 89906f32e7eSjoerg const LocationContext *LC, SVal V); 90006f32e7eSjoerg 90106f32e7eSjoerg /// Mark the object sa fully constructed, cleaning up the state trait 90206f32e7eSjoerg /// that tracks objects under construction. 90306f32e7eSjoerg static ProgramStateRef 90406f32e7eSjoerg finishObjectConstruction(ProgramStateRef State, 90506f32e7eSjoerg const ConstructionContextItem &Item, 90606f32e7eSjoerg const LocationContext *LC); 90706f32e7eSjoerg 90806f32e7eSjoerg /// If the given expression corresponds to a temporary that was used for 90906f32e7eSjoerg /// passing into an elidable copy/move constructor and that constructor 91006f32e7eSjoerg /// was actually elided, track that we also need to elide the destructor. 91106f32e7eSjoerg static ProgramStateRef elideDestructor(ProgramStateRef State, 91206f32e7eSjoerg const CXXBindTemporaryExpr *BTE, 91306f32e7eSjoerg const LocationContext *LC); 91406f32e7eSjoerg 91506f32e7eSjoerg /// Stop tracking the destructor that corresponds to an elided constructor. 91606f32e7eSjoerg static ProgramStateRef 91706f32e7eSjoerg cleanupElidedDestructor(ProgramStateRef State, 91806f32e7eSjoerg const CXXBindTemporaryExpr *BTE, 91906f32e7eSjoerg const LocationContext *LC); 92006f32e7eSjoerg 92106f32e7eSjoerg /// Returns true if the given expression corresponds to a temporary that 92206f32e7eSjoerg /// was constructed for passing into an elidable copy/move constructor 92306f32e7eSjoerg /// and that constructor was actually elided. 92406f32e7eSjoerg static bool isDestructorElided(ProgramStateRef State, 92506f32e7eSjoerg const CXXBindTemporaryExpr *BTE, 92606f32e7eSjoerg const LocationContext *LC); 92706f32e7eSjoerg 92806f32e7eSjoerg /// Check if all objects under construction have been fully constructed 92906f32e7eSjoerg /// for the given context range (including FromLC, not including ToLC). 93006f32e7eSjoerg /// This is useful for assertions. Also checks if elided destructors 93106f32e7eSjoerg /// were cleaned up. 93206f32e7eSjoerg static bool areAllObjectsFullyConstructed(ProgramStateRef State, 93306f32e7eSjoerg const LocationContext *FromLC, 93406f32e7eSjoerg const LocationContext *ToLC); 93506f32e7eSjoerg }; 93606f32e7eSjoerg 93706f32e7eSjoerg /// Traits for storing the call processing policy inside GDM. 93806f32e7eSjoerg /// The GDM stores the corresponding CallExpr pointer. 93906f32e7eSjoerg // FIXME: This does not use the nice trait macros because it must be accessible 94006f32e7eSjoerg // from multiple translation units. 94106f32e7eSjoerg struct ReplayWithoutInlining{}; 94206f32e7eSjoerg template <> 94306f32e7eSjoerg struct ProgramStateTrait<ReplayWithoutInlining> : 94406f32e7eSjoerg public ProgramStatePartialTrait<const void*> { 94506f32e7eSjoerg static void *GDMIndex(); 94606f32e7eSjoerg }; 94706f32e7eSjoerg 94806f32e7eSjoerg } // namespace ento 94906f32e7eSjoerg 95006f32e7eSjoerg } // namespace clang 95106f32e7eSjoerg 95206f32e7eSjoerg #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H 953