diff options
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h')
-rw-r--r-- | contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h | 213 |
1 files changed, 141 insertions, 72 deletions
diff --git a/contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index cef7dda172f3..ed5c4adb5e3d 100644 --- a/contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -36,6 +36,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" #include "llvm/ADT/ArrayRef.h" #include <cassert> +#include <optional> #include <utility> namespace clang { @@ -77,13 +78,9 @@ namespace ento { class AnalysisManager; class BasicValueFactory; -class BlockCounter; -class BranchNodeBuilder; class CallEvent; class CheckerManager; class ConstraintManager; -class CXXTempObjectRegion; -class EndOfFunctionNodeBuilder; class ExplodedNodeSet; class ExplodedNode; class IndirectGotoNodeBuilder; @@ -139,6 +136,7 @@ public: private: cross_tu::CrossTranslationUnitContext &CTU; + bool IsCTUEnabled; AnalysisManager &AMgr; @@ -231,10 +229,15 @@ public: const Stmt *getStmt() const; - void GenerateAutoTransition(ExplodedNode *N); - void enqueueEndOfPath(ExplodedNodeSet &S); - void GenerateCallExitNode(ExplodedNode *N); + const LocationContext *getRootLocationContext() const { + assert(G.roots_begin() != G.roots_end()); + return (*G.roots_begin())->getLocation().getLocationContext(); + } + CFGBlock::ConstCFGElementRef getCFGElementRef() const { + const CFGBlock *blockPtr = currBldrCtx ? currBldrCtx->getBlock() : nullptr; + return {blockPtr, currStmtIdx}; + } /// Dump graph to the specified filename. /// If filename is empty, generate a temporary one. @@ -358,13 +361,13 @@ public: void processSwitch(SwitchNodeBuilder& builder); /// Called by CoreEngine. Used to notify checkers that processing a - /// function has begun. Called for both inlined and and top-level functions. + /// function has begun. Called for both inlined and top-level functions. void processBeginOfFunction(NodeBuilderContext &BC, ExplodedNode *Pred, ExplodedNodeSet &Dst, const BlockEdge &L); /// Called by CoreEngine. Used to notify checkers that processing a - /// function has ended. Called for both inlined and and top-level functions. + /// function has ended. Called for both inlined and top-level functions. void processEndOfFunction(NodeBuilderContext& BC, ExplodedNode *Pred, const ReturnStmt *RS = nullptr); @@ -442,6 +445,10 @@ public: /// other functions that handle specific kinds of statements. void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst); + /// VisitArrayInitLoopExpr - Transfer function for array init loop. + void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + /// VisitArraySubscriptExpr - Transfer function for array accesses. void VisitArraySubscriptExpr(const ArraySubscriptExpr *Ex, ExplodedNode *Pred, @@ -589,51 +596,40 @@ public: static std::pair<const ProgramPointTag *, const ProgramPointTag *> geteagerlyAssumeBinOpBifurcationTags(); - SVal evalMinus(SVal X) { - return X.isValid() ? svalBuilder.evalMinus(X.castAs<NonLoc>()) : X; - } - - SVal evalComplement(SVal X) { - return X.isValid() ? svalBuilder.evalComplement(X.castAs<NonLoc>()) : X; - } - ProgramStateRef handleLValueBitCast(ProgramStateRef state, const Expr *Ex, const LocationContext *LCtx, QualType T, QualType ExTy, const CastExpr *CastE, StmtNodeBuilder &Bldr, ExplodedNode *Pred); - ProgramStateRef handleLVectorSplat(ProgramStateRef state, - const LocationContext *LCtx, - const CastExpr *CastE, - StmtNodeBuilder &Bldr, - ExplodedNode *Pred); - - void handleUOExtension(ExplodedNodeSet::iterator I, - const UnaryOperator* U, + void handleUOExtension(ExplodedNode *N, const UnaryOperator *U, StmtNodeBuilder &Bldr); public: - SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, - NonLoc L, NonLoc R, QualType T) { - return svalBuilder.evalBinOpNN(state, op, L, R, T); - } - - SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, - NonLoc L, SVal R, QualType T) { - return R.isValid() ? svalBuilder.evalBinOpNN(state, op, L, - R.castAs<NonLoc>(), T) : R; - } - SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op, SVal LHS, SVal RHS, QualType T) { return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T); } + /// Retreives which element is being constructed in a non-POD type array. + static std::optional<unsigned> + getIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E, + const LocationContext *LCtx); + + /// Retreives which element is being destructed in a non-POD type array. + static std::optional<unsigned> + getPendingArrayDestruction(ProgramStateRef State, + const LocationContext *LCtx); + + /// Retreives the size of the array in the pending ArrayInitLoopExpr. + static std::optional<unsigned> + getPendingInitLoop(ProgramStateRef State, const CXXConstructExpr *E, + const LocationContext *LCtx); + /// By looking at a certain item that may be potentially part of an object's /// ConstructionContext, retrieve such object's location. A particular /// statement can be transparently passed as \p Item in most cases. - static Optional<SVal> + static std::optional<SVal> getObjectUnderConstruction(ProgramStateRef State, const ConstructionContextItem &Item, const LocationContext *LC); @@ -721,10 +717,20 @@ public: /// fully implemented it sometimes indicates that it failed via its /// out-parameter CallOpts; in such cases a fake temporary region is /// returned, which is better than nothing but does not represent - /// the actual behavior of the program. - SVal computeObjectUnderConstruction( - const Expr *E, ProgramStateRef State, const LocationContext *LCtx, - const ConstructionContext *CC, EvalCallOptions &CallOpts); + /// the actual behavior of the program. The Idx parameter is used if we + /// construct an array of objects. In that case it points to the index + /// of the continuous memory region. + /// E.g.: + /// For `int arr[4]` this index can be 0,1,2,3. + /// For `int arr2[3][3]` this index can be 0,1,...,7,8. + /// A multi-dimensional array is also a continuous memory location in a + /// row major order, so for arr[0][0] Idx is 0 and for arr[2][2] Idx is 8. + SVal computeObjectUnderConstruction(const Expr *E, ProgramStateRef State, + const NodeBuilderContext *BldrCtx, + const LocationContext *LCtx, + const ConstructionContext *CC, + EvalCallOptions &CallOpts, + unsigned Idx = 0); /// Update the program state with all the path-sensitive information /// that's necessary to perform construction of an object with a given @@ -738,11 +744,15 @@ public: /// A convenient wrapper around computeObjectUnderConstruction /// and updateObjectsUnderConstruction. std::pair<ProgramStateRef, SVal> handleConstructionContext( - const Expr *E, ProgramStateRef State, const LocationContext *LCtx, - const ConstructionContext *CC, EvalCallOptions &CallOpts) { - SVal V = computeObjectUnderConstruction(E, State, LCtx, CC, CallOpts); - return std::make_pair( - updateObjectsUnderConstruction(V, E, State, LCtx, CC, CallOpts), V); + const Expr *E, ProgramStateRef State, const NodeBuilderContext *BldrCtx, + const LocationContext *LCtx, const ConstructionContext *CC, + EvalCallOptions &CallOpts, unsigned Idx = 0) { + + SVal V = computeObjectUnderConstruction(E, State, BldrCtx, LCtx, CC, + CallOpts, Idx); + State = updateObjectsUnderConstruction(V, E, State, LCtx, CC, CallOpts); + + return std::make_pair(State, V); } private: @@ -751,15 +761,6 @@ private: void finishArgumentConstruction(ExplodedNodeSet &Dst, ExplodedNode *Pred, const CallEvent &Call); - void evalLoadCommon(ExplodedNodeSet &Dst, - const Expr *NodeEx, /* Eventually will be a CFGStmt */ - const Expr *BoundEx, - ExplodedNode *Pred, - ProgramStateRef St, - SVal location, - const ProgramPointTag *tag, - QualType LoadTy); - void evalLocation(ExplodedNodeSet &Dst, const Stmt *NodeEx, /* This will eventually be a CFGStmt */ const Stmt *BoundEx, @@ -809,8 +810,46 @@ private: const ExplodedNode *Pred, const EvalCallOptions &CallOpts = {}); - bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, - ExplodedNode *Pred, ProgramStateRef State); + /// Checks whether our policies allow us to inline a non-POD type array + /// construction. + bool shouldInlineArrayConstruction(const ProgramStateRef State, + const CXXConstructExpr *CE, + const LocationContext *LCtx); + + /// Checks whether our policies allow us to inline a non-POD type array + /// destruction. + /// \param Size The size of the array. + bool shouldInlineArrayDestruction(uint64_t Size); + + /// Prepares the program state for array destruction. If no error happens + /// the function binds a 'PendingArrayDestruction' entry to the state, which + /// it returns along with the index. If any error happens (we fail to read + /// the size, the index would be -1, etc.) the function will return the + /// original state along with an index of 0. The actual element count of the + /// array can be accessed by the optional 'ElementCountVal' parameter. \param + /// State The program state. \param Region The memory region where the array + /// is stored. \param ElementTy The type an element in the array. \param LCty + /// The location context. \param ElementCountVal A pointer to an optional + /// SVal. If specified, the size of the array will be returned in it. It can + /// be Unknown. + std::pair<ProgramStateRef, uint64_t> prepareStateForArrayDestruction( + const ProgramStateRef State, const MemRegion *Region, + const QualType &ElementTy, const LocationContext *LCtx, + SVal *ElementCountVal = nullptr); + + /// Checks whether we construct an array of non-POD type, and decides if the + /// constructor should be inkoved once again. + bool shouldRepeatCtorCall(ProgramStateRef State, const CXXConstructExpr *E, + const LocationContext *LCtx); + + void inlineCall(WorkList *WList, const CallEvent &Call, const Decl *D, + NodeBuilder &Bldr, ExplodedNode *Pred, ProgramStateRef State); + + void ctuBifurcate(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, + ExplodedNode *Pred, ProgramStateRef State); + + /// Returns true if the CTU analysis is running its second phase. + bool isSecondPhaseCTU() { return IsCTUEnabled && !Engine.getCTUWorkList(); } /// Conservatively evaluate call by invalidating regions and binding /// a conjured return value. @@ -845,7 +884,7 @@ private: const Expr *InitWithAdjustments, const Expr *Result = nullptr, const SubRegion **OutRegionWithAdjustments = nullptr); - /// Returns a region representing the first element of a (possibly + /// Returns a region representing the `Idx`th element of a (possibly /// multi-dimensional) array, for the purposes of element construction or /// destruction. /// @@ -853,15 +892,8 @@ private: /// /// 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 - /// statement created a temporary object region rather than directly - /// constructing into an existing region. - const CXXConstructExpr *findDirectConstructorForCurrentCFGElement(); + static SVal makeElementRegion(ProgramStateRef State, SVal LValue, + QualType &Ty, bool &IsArray, unsigned Idx = 0); /// Common code that handles either a CXXConstructExpr or a /// CXXInheritedCtorInitExpr. @@ -872,19 +904,56 @@ public: /// Note whether this loop has any more iteratios to model. These methods are /// essentially an interface for a GDM trait. Further reading in /// ExprEngine::VisitObjCForCollectionStmt(). - LLVM_NODISCARD static ProgramStateRef + [[nodiscard]] static ProgramStateRef setWhetherHasMoreIteration(ProgramStateRef State, const ObjCForCollectionStmt *O, const LocationContext *LC, bool HasMoreIteraton); - LLVM_NODISCARD static ProgramStateRef + [[nodiscard]] static ProgramStateRef removeIterationState(ProgramStateRef State, const ObjCForCollectionStmt *O, const LocationContext *LC); - LLVM_NODISCARD static bool hasMoreIteration(ProgramStateRef State, - const ObjCForCollectionStmt *O, - const LocationContext *LC); + [[nodiscard]] static bool hasMoreIteration(ProgramStateRef State, + const ObjCForCollectionStmt *O, + const LocationContext *LC); + private: + /// Assuming we construct an array of non-POD types, this method allows us + /// to store which element is to be constructed next. + static ProgramStateRef + setIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E, + const LocationContext *LCtx, unsigned Idx); + + static ProgramStateRef + removeIndexOfElementToConstruct(ProgramStateRef State, + const CXXConstructExpr *E, + const LocationContext *LCtx); + + /// Assuming we destruct an array of non-POD types, this method allows us + /// to store which element is to be destructed next. + static ProgramStateRef setPendingArrayDestruction(ProgramStateRef State, + const LocationContext *LCtx, + unsigned Idx); + + static ProgramStateRef + removePendingArrayDestruction(ProgramStateRef State, + const LocationContext *LCtx); + + /// Sets the size of the array in a pending ArrayInitLoopExpr. + static ProgramStateRef setPendingInitLoop(ProgramStateRef State, + const CXXConstructExpr *E, + const LocationContext *LCtx, + unsigned Idx); + + static ProgramStateRef removePendingInitLoop(ProgramStateRef State, + const CXXConstructExpr *E, + const LocationContext *LCtx); + + static ProgramStateRef + removeStateTraitsUsedForArrayEvaluation(ProgramStateRef State, + const CXXConstructExpr *E, + const LocationContext *LCtx); + /// 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 |