Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:37:08

0001 //===- CoreEngine.h - Path-Sensitive Dataflow Engine ------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file defines a generic engine for intraprocedural, path-sensitive,
0010 //  dataflow analysis via graph reachability.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
0015 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
0016 
0017 #include "clang/AST/Stmt.h"
0018 #include "clang/Analysis/AnalysisDeclContext.h"
0019 #include "clang/Analysis/CFG.h"
0020 #include "clang/Analysis/ProgramPoint.h"
0021 #include "clang/Basic/LLVM.h"
0022 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
0023 #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
0024 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
0025 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
0026 #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
0027 #include "llvm/ADT/SmallVector.h"
0028 #include "llvm/ADT/iterator_range.h"
0029 #include "llvm/Support/Casting.h"
0030 #include <cassert>
0031 #include <memory>
0032 #include <utility>
0033 #include <vector>
0034 
0035 namespace clang {
0036 
0037 class AnalyzerOptions;
0038 class CXXBindTemporaryExpr;
0039 class Expr;
0040 class LabelDecl;
0041 
0042 namespace ento {
0043 
0044 class FunctionSummariesTy;
0045 class ExprEngine;
0046 
0047 //===----------------------------------------------------------------------===//
0048 /// CoreEngine - Implements the core logic of the graph-reachability analysis.
0049 /// It traverses the CFG and generates the ExplodedGraph.
0050 class CoreEngine {
0051   friend class CommonNodeBuilder;
0052   friend class EndOfFunctionNodeBuilder;
0053   friend class ExprEngine;
0054   friend class IndirectGotoNodeBuilder;
0055   friend class NodeBuilder;
0056   friend class NodeBuilderContext;
0057   friend class SwitchNodeBuilder;
0058 
0059 public:
0060   using BlocksExhausted =
0061       std::vector<std::pair<BlockEdge, const ExplodedNode *>>;
0062 
0063   using BlocksAborted =
0064       std::vector<std::pair<const CFGBlock *, const ExplodedNode *>>;
0065 
0066 private:
0067   ExprEngine &ExprEng;
0068 
0069   /// G - The simulation graph.  Each node is a (location,state) pair.
0070   mutable ExplodedGraph G;
0071 
0072   /// WList - A set of queued nodes that need to be processed by the
0073   ///  worklist algorithm.  It is up to the implementation of WList to decide
0074   ///  the order that nodes are processed.
0075   std::unique_ptr<WorkList> WList;
0076   std::unique_ptr<WorkList> CTUWList;
0077 
0078   /// BCounterFactory - A factory object for created BlockCounter objects.
0079   ///   These are used to record for key nodes in the ExplodedGraph the
0080   ///   number of times different CFGBlocks have been visited along a path.
0081   BlockCounter::Factory BCounterFactory;
0082 
0083   /// The locations where we stopped doing work because we visited a location
0084   ///  too many times.
0085   BlocksExhausted blocksExhausted;
0086 
0087   /// The locations where we stopped because the engine aborted analysis,
0088   /// usually because it could not reason about something.
0089   BlocksAborted blocksAborted;
0090 
0091   /// The information about functions shared by the whole translation unit.
0092   /// (This data is owned by AnalysisConsumer.)
0093   FunctionSummariesTy *FunctionSummaries;
0094 
0095   /// Add path tags with some useful data along the path when we see that
0096   /// something interesting is happening. This field is the allocator for such
0097   /// tags.
0098   DataTag::Factory DataTags;
0099 
0100   void setBlockCounter(BlockCounter C);
0101 
0102   void generateNode(const ProgramPoint &Loc,
0103                     ProgramStateRef State,
0104                     ExplodedNode *Pred);
0105 
0106   void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred);
0107   void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred);
0108   void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred);
0109 
0110   void HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred);
0111 
0112   void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred);
0113 
0114   void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
0115                     ExplodedNode *Pred);
0116   void HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
0117                                     const CFGBlock *B, ExplodedNode *Pred);
0118 
0119   /// Handle conditional logic for running static initializers.
0120   void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
0121                         ExplodedNode *Pred);
0122 
0123   void HandleVirtualBaseBranch(const CFGBlock *B, ExplodedNode *Pred);
0124 
0125 private:
0126   ExplodedNode *generateCallExitBeginNode(ExplodedNode *N,
0127                                           const ReturnStmt *RS);
0128 
0129   /// Helper function called by `HandleBranch()`. If the currently handled
0130   /// branch corresponds to a loop, this returns the number of already
0131   /// completed iterations in that loop, otherwise the return value is
0132   /// `std::nullopt`. Note that this counts _all_ earlier iterations, including
0133   /// ones that were performed within an earlier iteration of an outer loop.
0134   std::optional<unsigned> getCompletedIterationCount(const CFGBlock *B,
0135                                                      ExplodedNode *Pred) const;
0136 
0137 public:
0138   /// Construct a CoreEngine object to analyze the provided CFG.
0139   CoreEngine(ExprEngine &exprengine,
0140              FunctionSummariesTy *FS,
0141              AnalyzerOptions &Opts);
0142 
0143   CoreEngine(const CoreEngine &) = delete;
0144   CoreEngine &operator=(const CoreEngine &) = delete;
0145 
0146   /// getGraph - Returns the exploded graph.
0147   ExplodedGraph &getGraph() { return G; }
0148 
0149   /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
0150   ///  steps.  Returns true if there is still simulation state on the worklist.
0151   bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
0152                        ProgramStateRef InitState);
0153 
0154   /// Dispatch the work list item based on the given location information.
0155   /// Use Pred parameter as the predecessor state.
0156   void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
0157                         const WorkListUnit& WU);
0158 
0159   // Functions for external checking of whether we have unfinished work
0160   bool wasBlockAborted() const { return !blocksAborted.empty(); }
0161   bool wasBlocksExhausted() const { return !blocksExhausted.empty(); }
0162   bool hasWorkRemaining() const { return wasBlocksExhausted() ||
0163                                          WList->hasWork() ||
0164                                          wasBlockAborted(); }
0165 
0166   /// Inform the CoreEngine that a basic block was aborted because
0167   /// it could not be completely analyzed.
0168   void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) {
0169     blocksAborted.push_back(std::make_pair(block, node));
0170   }
0171 
0172   WorkList *getWorkList() const { return WList.get(); }
0173   WorkList *getCTUWorkList() const { return CTUWList.get(); }
0174 
0175   auto exhausted_blocks() const {
0176     return llvm::iterator_range(blocksExhausted);
0177   }
0178 
0179   auto aborted_blocks() const { return llvm::iterator_range(blocksAborted); }
0180 
0181   /// Enqueue the given set of nodes onto the work list.
0182   void enqueue(ExplodedNodeSet &Set);
0183 
0184   /// Enqueue nodes that were created as a result of processing
0185   /// a statement onto the work list.
0186   void enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx);
0187 
0188   /// enqueue the nodes corresponding to the end of function onto the
0189   /// end of path / work list.
0190   void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS);
0191 
0192   /// Enqueue a single node created as a result of statement processing.
0193   void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx);
0194 
0195   DataTag::Factory &getDataTags() { return DataTags; }
0196 };
0197 
0198 class NodeBuilderContext {
0199   const CoreEngine &Eng;
0200   const CFGBlock *Block;
0201   const LocationContext *LC;
0202 
0203 public:
0204   NodeBuilderContext(const CoreEngine &E, const CFGBlock *B,
0205                      const LocationContext *L)
0206       : Eng(E), Block(B), LC(L) {
0207     assert(B);
0208   }
0209 
0210   NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
0211       : NodeBuilderContext(E, B, N->getLocationContext()) {}
0212 
0213   /// Return the CoreEngine associated with this builder.
0214   const CoreEngine &getEngine() const { return Eng; }
0215 
0216   /// Return the CFGBlock associated with this builder.
0217   const CFGBlock *getBlock() const { return Block; }
0218 
0219   /// Return the location context associated with this builder.
0220   const LocationContext *getLocationContext() const { return LC; }
0221 
0222   /// Returns the number of times the current basic block has been
0223   /// visited on the exploded graph path.
0224   unsigned blockCount() const {
0225     return Eng.WList->getBlockCounter().getNumVisited(
0226                     LC->getStackFrame(),
0227                     Block->getBlockID());
0228   }
0229 };
0230 
0231 /// \class NodeBuilder
0232 /// This is the simplest builder which generates nodes in the
0233 /// ExplodedGraph.
0234 ///
0235 /// The main benefit of the builder is that it automatically tracks the
0236 /// frontier nodes (or destination set). This is the set of nodes which should
0237 /// be propagated to the next step / builder. They are the nodes which have been
0238 /// added to the builder (either as the input node set or as the newly
0239 /// constructed nodes) but did not have any outgoing transitions added.
0240 class NodeBuilder {
0241   virtual void anchor();
0242 
0243 protected:
0244   const NodeBuilderContext &C;
0245 
0246   /// Specifies if the builder results have been finalized. For example, if it
0247   /// is set to false, autotransitions are yet to be generated.
0248   bool Finalized;
0249 
0250   bool HasGeneratedNodes = false;
0251 
0252   /// The frontier set - a set of nodes which need to be propagated after
0253   /// the builder dies.
0254   ExplodedNodeSet &Frontier;
0255 
0256   /// Checks if the results are ready.
0257   virtual bool checkResults() {
0258     return Finalized;
0259   }
0260 
0261   bool hasNoSinksInFrontier() {
0262     for (const auto  I : Frontier)
0263       if (I->isSink())
0264         return false;
0265     return true;
0266   }
0267 
0268   /// Allow subclasses to finalize results before result_begin() is executed.
0269   virtual void finalizeResults() {}
0270 
0271   ExplodedNode *generateNodeImpl(const ProgramPoint &PP,
0272                                  ProgramStateRef State,
0273                                  ExplodedNode *Pred,
0274                                  bool MarkAsSink = false);
0275 
0276 public:
0277   NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
0278               const NodeBuilderContext &Ctx, bool F = true)
0279       : C(Ctx), Finalized(F), Frontier(DstSet) {
0280     Frontier.Add(SrcNode);
0281   }
0282 
0283   NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
0284               const NodeBuilderContext &Ctx, bool F = true)
0285       : C(Ctx), Finalized(F), Frontier(DstSet) {
0286     Frontier.insert(SrcSet);
0287     assert(hasNoSinksInFrontier());
0288   }
0289 
0290   virtual ~NodeBuilder() = default;
0291 
0292   /// Generates a node in the ExplodedGraph.
0293   ExplodedNode *generateNode(const ProgramPoint &PP,
0294                              ProgramStateRef State,
0295                              ExplodedNode *Pred) {
0296     return generateNodeImpl(
0297         PP, State, Pred,
0298         /*MarkAsSink=*/State->isPosteriorlyOverconstrained());
0299   }
0300 
0301   /// Generates a sink in the ExplodedGraph.
0302   ///
0303   /// When a node is marked as sink, the exploration from the node is stopped -
0304   /// the node becomes the last node on the path and certain kinds of bugs are
0305   /// suppressed.
0306   ExplodedNode *generateSink(const ProgramPoint &PP,
0307                              ProgramStateRef State,
0308                              ExplodedNode *Pred) {
0309     return generateNodeImpl(PP, State, Pred, true);
0310   }
0311 
0312   const ExplodedNodeSet &getResults() {
0313     finalizeResults();
0314     assert(checkResults());
0315     return Frontier;
0316   }
0317 
0318   using iterator = ExplodedNodeSet::iterator;
0319 
0320   /// Iterators through the results frontier.
0321   iterator begin() {
0322     finalizeResults();
0323     assert(checkResults());
0324     return Frontier.begin();
0325   }
0326 
0327   iterator end() {
0328     finalizeResults();
0329     return Frontier.end();
0330   }
0331 
0332   const NodeBuilderContext &getContext() { return C; }
0333   bool hasGeneratedNodes() { return HasGeneratedNodes; }
0334 
0335   void takeNodes(const ExplodedNodeSet &S) {
0336     for (const auto I : S)
0337       Frontier.erase(I);
0338   }
0339 
0340   void takeNodes(ExplodedNode *N) { Frontier.erase(N); }
0341   void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); }
0342   void addNodes(ExplodedNode *N) { Frontier.Add(N); }
0343 };
0344 
0345 /// \class NodeBuilderWithSinks
0346 /// This node builder keeps track of the generated sink nodes.
0347 class NodeBuilderWithSinks: public NodeBuilder {
0348   void anchor() override;
0349 
0350 protected:
0351   SmallVector<ExplodedNode*, 2> sinksGenerated;
0352   ProgramPoint &Location;
0353 
0354 public:
0355   NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet,
0356                        const NodeBuilderContext &Ctx, ProgramPoint &L)
0357       : NodeBuilder(Pred, DstSet, Ctx), Location(L) {}
0358 
0359   ExplodedNode *generateNode(ProgramStateRef State,
0360                              ExplodedNode *Pred,
0361                              const ProgramPointTag *Tag = nullptr) {
0362     const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
0363     return NodeBuilder::generateNode(LocalLoc, State, Pred);
0364   }
0365 
0366   ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
0367                              const ProgramPointTag *Tag = nullptr) {
0368     const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
0369     ExplodedNode *N = NodeBuilder::generateSink(LocalLoc, State, Pred);
0370     if (N && N->isSink())
0371       sinksGenerated.push_back(N);
0372     return N;
0373   }
0374 
0375   const SmallVectorImpl<ExplodedNode*> &getSinks() const {
0376     return sinksGenerated;
0377   }
0378 };
0379 
0380 /// \class StmtNodeBuilder
0381 /// This builder class is useful for generating nodes that resulted from
0382 /// visiting a statement. The main difference from its parent NodeBuilder is
0383 /// that it creates a statement specific ProgramPoint.
0384 class StmtNodeBuilder: public NodeBuilder {
0385   NodeBuilder *EnclosingBldr;
0386 
0387 public:
0388   /// Constructs a StmtNodeBuilder. If the builder is going to process
0389   /// nodes currently owned by another builder(with larger scope), use
0390   /// Enclosing builder to transfer ownership.
0391   StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
0392                   const NodeBuilderContext &Ctx,
0393                   NodeBuilder *Enclosing = nullptr)
0394       : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) {
0395     if (EnclosingBldr)
0396       EnclosingBldr->takeNodes(SrcNode);
0397   }
0398 
0399   StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
0400                   const NodeBuilderContext &Ctx,
0401                   NodeBuilder *Enclosing = nullptr)
0402       : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) {
0403     if (EnclosingBldr)
0404       for (const auto I : SrcSet)
0405         EnclosingBldr->takeNodes(I);
0406   }
0407 
0408   ~StmtNodeBuilder() override;
0409 
0410   using NodeBuilder::generateNode;
0411   using NodeBuilder::generateSink;
0412 
0413   ExplodedNode *generateNode(const Stmt *S,
0414                              ExplodedNode *Pred,
0415                              ProgramStateRef St,
0416                              const ProgramPointTag *tag = nullptr,
0417                              ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
0418     const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
0419                                   Pred->getLocationContext(), tag);
0420     return NodeBuilder::generateNode(L, St, Pred);
0421   }
0422 
0423   ExplodedNode *generateSink(const Stmt *S,
0424                              ExplodedNode *Pred,
0425                              ProgramStateRef St,
0426                              const ProgramPointTag *tag = nullptr,
0427                              ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
0428     const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
0429                                   Pred->getLocationContext(), tag);
0430     return NodeBuilder::generateSink(L, St, Pred);
0431   }
0432 };
0433 
0434 /// BranchNodeBuilder is responsible for constructing the nodes
0435 /// corresponding to the two branches of the if statement - true and false.
0436 class BranchNodeBuilder: public NodeBuilder {
0437   const CFGBlock *DstT;
0438   const CFGBlock *DstF;
0439 
0440   void anchor() override;
0441 
0442 public:
0443   BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
0444                     const NodeBuilderContext &C, const CFGBlock *DT,
0445                     const CFGBlock *DF)
0446       : NodeBuilder(SrcNode, DstSet, C), DstT(DT), DstF(DF) {
0447     // The branch node builder does not generate autotransitions.
0448     // If there are no successors it means that both branches are infeasible.
0449     takeNodes(SrcNode);
0450   }
0451 
0452   BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
0453                     const NodeBuilderContext &C, const CFGBlock *DT,
0454                     const CFGBlock *DF)
0455       : NodeBuilder(SrcSet, DstSet, C), DstT(DT), DstF(DF) {
0456     takeNodes(SrcSet);
0457   }
0458 
0459   ExplodedNode *generateNode(ProgramStateRef State, bool branch,
0460                              ExplodedNode *Pred);
0461 };
0462 
0463 class IndirectGotoNodeBuilder {
0464   CoreEngine& Eng;
0465   const CFGBlock *Src;
0466   const CFGBlock &DispatchBlock;
0467   const Expr *E;
0468   ExplodedNode *Pred;
0469 
0470 public:
0471   IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
0472                     const Expr *e, const CFGBlock *dispatch, CoreEngine* eng)
0473       : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
0474 
0475   class iterator {
0476     friend class IndirectGotoNodeBuilder;
0477 
0478     CFGBlock::const_succ_iterator I;
0479 
0480     iterator(CFGBlock::const_succ_iterator i) : I(i) {}
0481 
0482   public:
0483     // This isn't really a conventional iterator.
0484     // We just implement the deref as a no-op for now to make range-based for
0485     // loops work.
0486     const iterator &operator*() const { return *this; }
0487 
0488     iterator &operator++() { ++I; return *this; }
0489     bool operator!=(const iterator &X) const { return I != X.I; }
0490 
0491     const LabelDecl *getLabel() const {
0492       return cast<LabelStmt>((*I)->getLabel())->getDecl();
0493     }
0494 
0495     const CFGBlock *getBlock() const {
0496       return *I;
0497     }
0498   };
0499 
0500   iterator begin() { return iterator(DispatchBlock.succ_begin()); }
0501   iterator end() { return iterator(DispatchBlock.succ_end()); }
0502 
0503   ExplodedNode *generateNode(const iterator &I,
0504                              ProgramStateRef State,
0505                              bool isSink = false);
0506 
0507   const Expr *getTarget() const { return E; }
0508 
0509   ProgramStateRef getState() const { return Pred->State; }
0510 
0511   const LocationContext *getLocationContext() const {
0512     return Pred->getLocationContext();
0513   }
0514 };
0515 
0516 class SwitchNodeBuilder {
0517   CoreEngine& Eng;
0518   const CFGBlock *Src;
0519   const Expr *Condition;
0520   ExplodedNode *Pred;
0521 
0522 public:
0523   SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
0524                     const Expr *condition, CoreEngine* eng)
0525       : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
0526 
0527   class iterator {
0528     friend class SwitchNodeBuilder;
0529 
0530     CFGBlock::const_succ_reverse_iterator I;
0531 
0532     iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
0533 
0534   public:
0535     iterator &operator++() { ++I; return *this; }
0536     bool operator!=(const iterator &X) const { return I != X.I; }
0537     bool operator==(const iterator &X) const { return I == X.I; }
0538 
0539     const CaseStmt *getCase() const {
0540       return cast<CaseStmt>((*I)->getLabel());
0541     }
0542 
0543     const CFGBlock *getBlock() const {
0544       return *I;
0545     }
0546   };
0547 
0548   iterator begin() { return iterator(Src->succ_rbegin()+1); }
0549   iterator end() { return iterator(Src->succ_rend()); }
0550 
0551   const SwitchStmt *getSwitch() const {
0552     return cast<SwitchStmt>(Src->getTerminator());
0553   }
0554 
0555   ExplodedNode *generateCaseStmtNode(const iterator &I,
0556                                      ProgramStateRef State);
0557 
0558   ExplodedNode *generateDefaultCaseNode(ProgramStateRef State,
0559                                         bool isSink = false);
0560 
0561   const Expr *getCondition() const { return Condition; }
0562 
0563   ProgramStateRef getState() const { return Pred->State; }
0564 
0565   const LocationContext *getLocationContext() const {
0566     return Pred->getLocationContext();
0567   }
0568 };
0569 
0570 } // namespace ento
0571 
0572 } // namespace clang
0573 
0574 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H