aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
diff options
context:
space:
mode:
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.h213
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